Skip to content

Commit

Permalink
killer: add HasModifyReturnSyscall check
Browse files Browse the repository at this point in the history
Our detection code already has a function for detecting of fmod_ret is
supported named HasModifyReturn. If we want to load an fmod_ret program
in a syscall function, however, checking HasModifyReturn() is not
sufficient.

This is because in kernels where CONFIG_FUNCTION_ERROR_INJECTION is not
set, loading fmod_ret programs in syscalls is not supported.

So add a separate check, where we try to attach to a system call (we use
getcpu) instead of a security_ function.

Kernel check is:

```
static int check_attach_modify_return(unsigned long addr, const char *func_name)
{
	if (within_error_injection_list(addr) ||
	    !strncmp(SECURITY_PREFIX, func_name, sizeof(SECURITY_PREFIX) - 1))
		return 0;

	return -EINVAL;
}
```

And:

```
...

static inline bool within_error_injection_list(unsigned long addr)
{
	return false;
}

static inline int get_injectable_error_type(unsigned long addr)
{
	return -EOPNOTSUPP;
}

```

Signed-off-by: Kornilios Kourtis <kornilios@isovalent.com>
  • Loading branch information
kkourt committed Jan 16, 2024
1 parent c6da994 commit 84cfbe9
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 11 deletions.
62 changes: 53 additions & 9 deletions pkg/bpf/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/features"
"github.com/cilium/ebpf/link"
"github.com/cilium/tetragon/pkg/arch"
"github.com/cilium/tetragon/pkg/logger"
"golang.org/x/sys/unix"
)

Expand All @@ -24,9 +26,10 @@ type Feature struct {
}

var (
kprobeMulti Feature
buildid Feature
modifyReturn Feature
kprobeMulti Feature
buildid Feature
modifyReturn Feature
modifyReturnSyscall Feature
)

func HasOverrideHelper() bool {
Expand Down Expand Up @@ -119,18 +122,59 @@ func detectModifyReturn() bool {
return true
}

func HasModifyReturn() bool {
modifyReturn.init.Do(func() {
modifyReturn.detected = detectModifyReturn()
func detectModifyReturnSyscall() bool {
sysGetcpu, err := arch.AddSyscallPrefix("sys_getcpu")
if err != nil {
return false
}
logger.GetLogger().Infof("probing detectModifyReturnSyscall using %s", sysGetcpu)
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
Name: "probe_sys_fmod_ret",
Type: ebpf.Tracing,
Instructions: asm.Instructions{
asm.Mov.Imm(asm.R0, 0),
asm.Return(),
},
AttachType: ebpf.AttachModifyReturn,
AttachTo: sysGetcpu,
License: "MIT",
})
return modifyReturn.detected
if err != nil {
logger.GetLogger().WithError(err).Info("detectModifyReturnSyscall: failed to load")
return false
}
defer prog.Close()

link, err := link.AttachTracing(link.TracingOptions{
Program: prog,
})
if err != nil {
logger.GetLogger().WithError(err).Info("detectModifyReturnSyscall, failed to attach")
return false
}
link.Close()
return true
}

func HasModifyReturnSyscall() bool {
modifyReturnSyscall.init.Do(func() {
modifyReturnSyscall.detected = detectModifyReturnSyscall()
})
return modifyReturnSyscall.detected
}

func HasProgramLargeSize() bool {
return features.HaveLargeInstructions() == nil
}

func HasModifyReturn() bool {
modifyReturn.init.Do(func() {
modifyReturn.detected = detectModifyReturn()
})
return modifyReturn.detected
}

func LogFeatures() string {
return fmt.Sprintf("override_return: %t, buildid: %t, kprobe_multi: %t, fmodret: %t, signal: %t, large: %t",
HasOverrideHelper(), HasBuildId(), HasKprobeMulti(), HasModifyReturn(), HasSignalHelper(), HasProgramLargeSize())
return fmt.Sprintf("override_return: %t, buildid: %t, kprobe_multi: %t, fmodret: %t, fmodret_syscall: %t, signal: %t, large: %t",
HasOverrideHelper(), HasBuildId(), HasKprobeMulti(), HasModifyReturn(), HasModifyReturnSyscall(), HasSignalHelper(), HasProgramLargeSize())
}
4 changes: 2 additions & 2 deletions pkg/sensors/tracing/killer.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func selectOverrideMethod(specOpts *specOptions) (OverrideMethod, error) {
// by default, first try OverrideReturn and if this does not work try fmod_ret
if bpf.HasOverrideHelper() {
overrideMethod = OverrideMethodReturn
} else if bpf.HasModifyReturn() {
} else if bpf.HasModifyReturn() && bpf.HasModifyReturnSyscall() {
overrideMethod = OverrideMethodFmodRet
} else {
return OverrideMethodInvalid, fmt.Errorf("no override helper or mod_ret support: cannot load killer")
Expand All @@ -125,7 +125,7 @@ func selectOverrideMethod(specOpts *specOptions) (OverrideMethod, error) {
return OverrideMethodInvalid, fmt.Errorf("option override return set, but it is not supported")
}
case OverrideMethodFmodRet:
if !bpf.HasModifyReturn() {
if !bpf.HasModifyReturn() || !bpf.HasModifyReturnSyscall() {
return OverrideMethodInvalid, fmt.Errorf("option fmod_ret set, but it is not supported")
}
}
Expand Down

0 comments on commit 84cfbe9

Please sign in to comment.