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 6fdddd3
Showing 1 changed file with 31 additions and 6 deletions.
37 changes: 31 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,21 +46,43 @@ 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)
}
}
// TypeByName() above ensures btf.Func type, but Check again so semantically we are correct
if len(fnTypes) > 0 {
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),
}
}
return &ValidationFailed{s: fmt.Sprintf("call %q %v", call, err)}
}

proto, ok := fn.Type.(*btf.FuncProto)
Expand Down

0 comments on commit 6fdddd3

Please sign in to comment.