Skip to content

Commit

Permalink
btf: take first entry on multiple function matches
Browse files Browse the repository at this point in the history
TypeByName() can fail with ErrMultipleMatches if we have multiple
candidates. If so, let's try again and take first match as it is.

This can help solve our immediate issue of having multiple definitions
per system calls, however the long-term fix would be to iterate over
all candidate, match their proto and arguments definitions, then attach
to the corresponding ones.

Example output:

time="2024-05-31T15:53:17+01:00" level=info msg="BTF includes '2' matched candidates on call \"__x64_sys_init_module\", using first one" metadata=/home/tixxdz/btf

Signed-off-by: Djalal Harouni <[email protected]>
  • Loading branch information
tixxdz committed Jun 3, 2024
1 parent dac9959 commit 3ae527f
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions pkg/btf/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
package btf

import (
"errors"
"fmt"
"os"
"reflect"
"strings"

"github.com/cilium/ebpf/btf"
"github.com/cilium/tetragon/pkg/arch"
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
"github.com/cilium/tetragon/pkg/logger"
"github.com/cilium/tetragon/pkg/syscallinfo"
)

Expand Down Expand Up @@ -43,20 +46,40 @@ func (e *ValidationFailed) Error() string {
func ValidateKprobeSpec(bspec *btf.Spec, call string, kspec *v1alpha1.KProbeSpec) error {
var fn *btf.Func

origCall := call
err := bspec.TypeByName(call, &fn)
if err != nil {
if !kspec.Syscall {
return &ValidationFailed{s: fmt.Sprintf("call %q %v", call, err)}
}
origCall := call
if err != nil && kspec.Syscall {
// Try with system call prefix
call, err = arch.AddSyscallPrefix(call)
if err == nil {
err = bspec.TypeByName(call, &fn)
}
if err != nil {
}

// BTF include multiple candidates
if errors.Is(err, btf.ErrMultipleMatches) {
var allTypes, fnTypes []btf.Type
allTypes, err = bspec.AnyTypesByName(call)
if err == nil {
for _, typ := range allTypes {
// Assert again the appropriate type
if _, ok := typ.(*btf.Func); ok {
fnTypes = append(fnTypes, typ)
}
}
logger.GetLogger().Infof("BTF metadata includes '%d' matched candidates on call %q, using first one", len(fnTypes), call)
// take first one.
reflect.ValueOf(&fn).Elem().Set(reflect.ValueOf(fnTypes[0]))
}
}

if err != nil {
if kspec.Syscall {
return &ValidationFailed{
s: fmt.Sprintf("syscall %q (or %q) %v", origCall, call, err),
}
} else {

Check warning on line 81 in pkg/btf/validation.go

View workflow job for this annotation

GitHub Actions / golangci-lint

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
return &ValidationFailed{s: fmt.Sprintf("call %q %v", call, err)}
}
}

Expand Down

0 comments on commit 3ae527f

Please sign in to comment.