Skip to content

Commit

Permalink
tls: support "invalid" go versions
Browse files Browse the repository at this point in the history
  • Loading branch information
apetruhin committed Nov 26, 2024
1 parent 4ede0a3 commit d7c186e
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 34 deletions.
19 changes: 15 additions & 4 deletions common/kernel.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
package common

import "regexp"
import (
"fmt"
)

var (
kernelVersionRe = regexp.MustCompile(`^(\d+\.\d+)`)
kernelVersion Version
)

func KernelMajorMinor(version string) string {
return kernelVersionRe.FindString(version)
func SetKernelVersion(version string) error {
v, err := VersionFromString(version)
if err != nil || v.Minor == 0 {
return fmt.Errorf("invalid kernel version: %s", version)
}
kernelVersion = v
return nil
}

func GetKernelVersion() Version {
return kernelVersion
}
61 changes: 61 additions & 0 deletions common/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package common

import (
"fmt"
"regexp"
"strconv"
"strings"
)

var (
versionRe = regexp.MustCompile(`^v?(\d+(\.\d+)*)`)
)

type Version struct {
Major, Minor, Patch int
}

func NewVersion(major, minor, patch int) Version {
return Version{Major: major, Minor: minor, Patch: patch}
}

func VersionFromString(version string) (Version, error) {
var v Version
matches := versionRe.FindStringSubmatch(version)
if len(matches) == 0 {
return v, fmt.Errorf("invalid version: %s", version)
}
parts := strings.Split(matches[1], ".")
for i, p := range parts {
ii, _ := strconv.Atoi(p)
switch i {
case 0:
v.Major = ii
case 1:
v.Minor = ii
case 2:
v.Patch = ii
default:
break
}
}
return v, nil
}

func (v Version) String() string {
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}

func (v Version) GreaterOrEqual(other Version) bool {
switch {
case v.Major > other.Major:
return true
case v.Major < other.Major:
return false
case v.Minor > other.Minor:
return true
case v.Minor < other.Minor:
return false
}
return v.Patch >= other.Patch
}
4 changes: 2 additions & 2 deletions containers/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type Registry struct {
trafficStatsUpdateCh chan *TrafficStatsUpdate
}

func NewRegistry(reg prometheus.Registerer, kernelVersion string, processInfoCh chan<- ProcessInfo) (*Registry, error) {
func NewRegistry(reg prometheus.Registerer, processInfoCh chan<- ProcessInfo) (*Registry, error) {
ns, err := proc.GetSelfNetNs()
if err != nil {
return nil, err
Expand Down Expand Up @@ -114,7 +114,7 @@ func NewRegistry(reg prometheus.Registerer, kernelVersion string, processInfoCh

processInfoCh: processInfoCh,

tracer: ebpftracer.NewTracer(kernelVersion, *flags.DisableL7Tracing),
tracer: ebpftracer.NewTracer(*flags.DisableL7Tracing),

trafficStatsUpdateCh: make(chan *TrafficStatsUpdate),
}
Expand Down
28 changes: 18 additions & 10 deletions ebpftracer/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@ import (
"strings"

"github.com/cilium/ebpf/link"
"github.com/coroot/coroot-node-agent/common"
"github.com/coroot/coroot-node-agent/proc"
"golang.org/x/arch/arm64/arm64asm"
"golang.org/x/arch/x86/x86asm"
"golang.org/x/mod/semver"
"k8s.io/klog/v2"
)

const (
minSupportedGoVersion = "v1.17.0"
goTlsWriteSymbol = "crypto/tls.(*Conn).Write"
goTlsReadSymbol = "crypto/tls.(*Conn).Read"
goTlsWriteSymbol = "crypto/tls.(*Conn).Write"
goTlsReadSymbol = "crypto/tls.(*Conn).Read"
)

var (
Expand Down Expand Up @@ -61,12 +60,17 @@ func (t *Tracer) AttachOpenSslUprobes(pid uint32) []link.Link {
readEnter := "openssl_SSL_read_enter"
readExEnter := "openssl_SSL_read_ex_enter"
readExit := "openssl_SSL_read_exit"
v, err := common.VersionFromString(version)
if err != nil {
log("failed to determine version", err)
return nil
}
switch {
case semver.Compare(version, "v3.0.0") >= 0:
case v.GreaterOrEqual(common.NewVersion(3, 0, 0)):
writeEnter = "openssl_SSL_write_enter_v3_0"
readEnter = "openssl_SSL_read_enter_v3_0"
readExEnter = "openssl_SSL_read_ex_enter_v3_0"
case semver.Compare(version, "v1.1.1") >= 0:
case v.GreaterOrEqual(common.NewVersion(1, 1, 1)):
writeEnter = "openssl_SSL_write_enter_v1_1_1"
readEnter = "openssl_SSL_read_enter_v1_1_1"
readExEnter = "openssl_SSL_read_ex_enter_v1_1_1"
Expand All @@ -82,7 +86,7 @@ func (t *Tracer) AttachOpenSslUprobes(pid uint32) []link.Link {
{symbol: "SSL_read", uprobe: readEnter},
{symbol: "SSL_read", uretprobe: readExit},
}
if semver.Compare(version, "v1.1.1") >= 0 {
if v.GreaterOrEqual(common.NewVersion(1, 1, 1)) {
progs = append(progs, []prog{
{symbol: "SSL_write_ex", uprobe: writeEnter},
{symbol: "SSL_read_ex", uprobe: readExEnter},
Expand Down Expand Up @@ -147,9 +151,13 @@ func (t *Tracer) AttachGoTlsUprobes(pid uint32) ([]link.Link, bool) {
log("failed to read name", err)
return nil, isGolangApp
}
version = strings.Replace(bi.GoVersion, "go", "v", 1)
if semver.Compare(version, minSupportedGoVersion) < 0 {
log(fmt.Sprintf("go_versions below %s are not supported", minSupportedGoVersion), nil)
version = bi.GoVersion
v, err := common.VersionFromString(strings.Replace(bi.GoVersion, "go", "", 1))
if err != nil {
log("failed to determine version", err)
}
if !v.GreaterOrEqual(common.NewVersion(1, 17, 0)) {
log("versions below 1.17 are not supported", nil)
return nil, isGolangApp
}

Expand Down
14 changes: 6 additions & 8 deletions ebpftracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/coroot/coroot-node-agent/common"
"github.com/coroot/coroot-node-agent/ebpftracer/l7"
"github.com/coroot/coroot-node-agent/proc"
"golang.org/x/mod/semver"
"golang.org/x/sys/unix"
"inet.af/netaddr"
"k8s.io/klog/v2"
Expand Down Expand Up @@ -74,7 +73,6 @@ const (
)

type Tracer struct {
kernelVersion string
disableL7Tracing bool

collection *ebpf.Collection
Expand All @@ -83,12 +81,11 @@ type Tracer struct {
uprobes map[string]*ebpf.Program
}

func NewTracer(kernelVersion string, disableL7Tracing bool) *Tracer {
func NewTracer(disableL7Tracing bool) *Tracer {
if disableL7Tracing {
klog.Infoln("L7 tracing is disabled")
}
return &Tracer{
kernelVersion: kernelVersion,
disableL7Tracing: disableL7Tracing,

readers: map[string]*perf.Reader{},
Expand Down Expand Up @@ -194,16 +191,17 @@ func (t *Tracer) ebpf(ch chan<- Event) error {
if _, ok := ebpfProg[runtime.GOARCH]; !ok {
return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH)
}
kv := "v" + common.KernelMajorMinor(t.kernelVersion)
kv := common.GetKernelVersion()
var prg []byte
for _, p := range ebpfProg[runtime.GOARCH] {
if semver.Compare(kv, p.v) >= 0 {
pv, _ := common.VersionFromString(p.v)
if kv.GreaterOrEqual(pv) {
prg = p.p
break
}
}
if len(prg) == 0 {
return fmt.Errorf("unsupported kernel version: %s", t.kernelVersion)
return fmt.Errorf("unsupported kernel version: %s", kv)
}
_, debugFsErr := os.Stat("/sys/kernel/debug/tracing")
_, traceFsErr := os.Stat("/sys/kernel/tracing")
Expand Down Expand Up @@ -239,7 +237,7 @@ func (t *Tracer) ebpf(ch chan<- Event) error {
}

if !t.disableL7Tracing {
perfMaps = append(perfMaps, perfMap{name: "l7_events", typ: perfMapTypeL7Events, perCPUBufferSizePages: 32})
perfMaps = append(perfMaps, perfMap{name: "l7_events", typ: perfMapTypeL7Events, perCPUBufferSizePages: 64})
}

for _, pm := range perfMaps {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ require (
go.opentelemetry.io/otel/trace v1.22.0
golang.org/x/arch v0.4.0
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
golang.org/x/mod v0.16.0
golang.org/x/net v0.22.0
golang.org/x/sys v0.18.0
golang.org/x/time v0.5.0
Expand Down Expand Up @@ -169,6 +168,7 @@ require (
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/text v0.14.0 // indirect
Expand Down
15 changes: 6 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/coroot/coroot-node-agent/tracing"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/mod/semver"
"golang.org/x/sys/unix"
"golang.org/x/time/rate"
"k8s.io/klog/v2"
Expand All @@ -29,8 +28,6 @@ var (
version = "unknown"
)

const minSupportedKernelVersion = "4.16"

func uname() (string, string, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
Expand Down Expand Up @@ -117,12 +114,12 @@ func main() {
klog.Infoln("hostname:", hostname)
klog.Infoln("kernel version:", kv)

ver := common.KernelMajorMinor(kv)
if ver == "" {
klog.Exitln("invalid kernel version:", kv)
if err = common.SetKernelVersion(kv); err != nil {
klog.Exitln(err)
}
if semver.Compare("v"+ver, "v"+minSupportedKernelVersion) == -1 {
klog.Exitf("the minimum Linux kernel version required is %s or later", minSupportedKernelVersion)

if !common.GetKernelVersion().GreaterOrEqual(common.NewVersion(4, 16, 0)) {
klog.Exitln("the minimum Linux kernel version required is 4.16 or later")
}

whitelistNodeExternalNetworks()
Expand All @@ -144,7 +141,7 @@ func main() {

processInfoCh := profiling.Init(machineId, hostname)

cr, err := containers.NewRegistry(registerer, kv, processInfoCh)
cr, err := containers.NewRegistry(registerer, processInfoCh)
if err != nil {
klog.Exitln(err)
}
Expand Down

0 comments on commit d7c186e

Please sign in to comment.