Skip to content

Commit

Permalink
syscalls: add ABI to syscall information
Browse files Browse the repository at this point in the history
This commit enables the new type for the syscall64 type. Specifically,
it makes it so that we get a SyscallId event that includes both the ABI
(64- or 32-bit) and the syscall id.

Because this changes previous behaviour, we introduce a
compatibility flag.

Signed-off-by: Kornilios Kourtis <[email protected]>
  • Loading branch information
kkourt committed Oct 10, 2024
1 parent 5a3cf7c commit b335808
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 16 deletions.
23 changes: 22 additions & 1 deletion contrib/upgrade-notes/latest.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,28 @@ Depending on your setup, changes listed here might require a manual intervention

### Events (protobuf API)

* TBD

#### New events for `syscall64` type

Previous versions of Tetragon did not distinguish between different ABIs when using the syscall64 type
because the output was just a `size_arg` with the id. When executing the `getcpu` syscall, for example, the JSON
for 64- and 32-bits would be:
```
"args":[{"size_arg":"309"}]
"args":[{"size_arg":"318"}]
```

Note that 318 for x86_64 bits is a differnt syscall: `getrandom` so we cannot distinguish between a `getrandom` syscall on x86_64
and a `getcpu` call on 32-bit (`i386`). To address this issue, the ouptput of `syscall64` was changed to a `SyscallId` object that
also includes the ABI. So the JSON for 64- and 32-bits `getcpu` now is:

```
"args":[{"syscall_id":{"id":309,"abi":"x64"}}]
"args":[{"syscall_id":{"id":318,"abi":"i386"}}]
```

Users that want to maintain the old behavior can use the `--enable-compatibility-syscall64-size-type` flag for this version.
The flag will be removed in v1.4.

### Metrics

Expand Down
4 changes: 4 additions & 0 deletions docs/data/tetragon_flags.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/api/tracingapi/client_kprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ type MsgGenericKprobeArgSkb struct {
Label string
}

type MsgGenericSyscallID struct {
ID uint32
ABI string
}

func (m MsgGenericKprobeArgSkb) GetIndex() uint64 {
return m.Index
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,20 +564,27 @@ func (p *CompactEncoder) EventToString(response *tetragon.GetEventsResponse) (st

func rawSyscallEnter(tp *tetragon.ProcessTracepoint) string {
sysID := int64(-1)
abi, err := syscallinfo.DefaultABI()
defaultABI, err := syscallinfo.DefaultABI()
if err != nil {
return "unknown"
}
abi := defaultABI
// we assume that the syscall id is in the first argument
if len(tp.Args) > 0 && tp.Args[0] != nil {
if x, ok := tp.Args[0].GetArg().(*tetragon.KprobeArgument_LongArg); ok {
sysID = x.LongArg
} else if x, ok := tp.Args[0].GetArg().(*tetragon.KprobeArgument_SyscallId); ok {
sysID = int64(x.SyscallId.Id)
abi = x.SyscallId.Abi
}
}

sysName := "unknown"
if name, _ := syscallinfo.GetSyscallName(abi, int(sysID)); name != "" {
sysName = name
if abi != defaultABI {
sysName = fmt.Sprintf("%s/%s", abi, sysName)
}
sysArgs, ok := syscallinfo.GetSyscallArgs(sysName)
if ok {
sysName += "("
Expand Down
8 changes: 8 additions & 0 deletions pkg/grpc/tracing/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,14 @@ func (msg *MsgGenericTracepointUnix) HandleMessage() *tetragon.GetEventsResponse
SockArg: &sk,
}})

case tracingapi.MsgGenericSyscallID:
tetragonArgs = append(tetragonArgs, &tetragon.KprobeArgument{Arg: &tetragon.KprobeArgument_SyscallId{
SyscallId: &tetragon.SyscallId{
Id: v.ID,
Abi: v.ABI,
},
}})

default:
logger.GetLogger().Warnf("handleGenericTracepointMessage: unhandled value: %+v (%T)", arg, arg)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/option/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ type config struct {

EventCacheNumRetries int
EventCacheRetryDelay int

CompatibilitySyscall64SizeType bool
}

var (
Expand Down
6 changes: 6 additions & 0 deletions pkg/option/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ const (

KeyEventCacheRetries = "event-cache-retries"
KeyEventCacheRetryDelay = "event-cache-retry-delay"

KeyCompatibilitySyscall64SizeType = "enable-compatibility-syscall64-size-type"
)

type UsernameMetadaCode int
Expand Down Expand Up @@ -245,6 +247,8 @@ func ReadAndSetFlags() error {
Config.EventCacheNumRetries = viper.GetInt(KeyEventCacheRetries)
Config.EventCacheRetryDelay = viper.GetInt(KeyEventCacheRetryDelay)

Config.CompatibilitySyscall64SizeType = viper.GetBool(KeyCompatibilitySyscall64SizeType)

return nil
}

Expand Down Expand Up @@ -411,4 +415,6 @@ func AddFlags(flags *pflag.FlagSet) {

flags.Int(KeyEventCacheRetries, defaults.DefaultEventCacheNumRetries, "Number of retries for event cache")
flags.Int(KeyEventCacheRetryDelay, defaults.DefaultEventCacheRetryDelay, "Delay in seconds between event cache retries")

flags.Bool(KeyCompatibilitySyscall64SizeType, false, "syscall64 type will produce output of type size (compatiblity flag, will be removed in v1.4)")
}
18 changes: 14 additions & 4 deletions pkg/sensors/tracing/enforcer_32bit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/cilium/tetragon/api/v1/tetragon"
ec "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker"
lc "github.com/cilium/tetragon/pkg/matchers/listmatcher"
sm "github.com/cilium/tetragon/pkg/matchers/stringmatcher"
"github.com/cilium/tetragon/pkg/syscallinfo/arm32"
"github.com/cilium/tetragon/pkg/syscallinfo/i386"
"github.com/cilium/tetragon/pkg/testutils"
Expand All @@ -21,13 +22,16 @@ func TestEnforcerOverride32(t *testing.T) {

prctlID := uint64(0)
var syscallVal string
sysIDChecker := ec.NewSyscallIdChecker()
switch a := runtime.GOARCH; a {
case "amd64":
syscallVal = "i386/sys_prctl"
prctlID = i386.SYS_PRCTL
sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("i386"))
case "arm64":
syscallVal = "arm32/sys_prctl"
prctlID = arm32.SYS_PRCTL
sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("arm32"))
default:
t.Fatalf("Unknown arch: %s", a)
}
Expand All @@ -43,7 +47,7 @@ func TestEnforcerOverride32(t *testing.T) {
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(prctlID),
ec.NewKprobeArgumentChecker().WithSyscallId(sysIDChecker),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

Expand All @@ -62,13 +66,16 @@ func TestEnforcerSignal32(t *testing.T) {

prctlID := uint64(0)
var syscallVal string
sysIDChecker := ec.NewSyscallIdChecker()
switch a := runtime.GOARCH; a {
case "amd64":
syscallVal = "i386/sys_prctl"
prctlID = i386.SYS_PRCTL
sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("i386"))
case "arm64":
syscallVal = "arm32/sys_prctl"
prctlID = arm32.SYS_PRCTL
sysIDChecker = sysIDChecker.WithId(uint32(prctlID)).WithAbi(sm.Full("arm32"))
default:
t.Fatalf("Unknown arch: %s", a)
}
Expand All @@ -85,7 +92,7 @@ func TestEnforcerSignal32(t *testing.T) {
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(prctlID),
ec.NewKprobeArgumentChecker().WithSyscallId(sysIDChecker),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

Expand All @@ -105,13 +112,16 @@ func TestEnforcerOverrideBothBits(t *testing.T) {

prctlID := uint64(0)
var syscallVal string
sysIDChecker32 := ec.NewSyscallIdChecker()
switch a := runtime.GOARCH; a {
case "amd64":
syscallVal = "i386/sys_prctl"
prctlID = i386.SYS_PRCTL
sysIDChecker32 = sysIDChecker32.WithId(uint32(prctlID)).WithAbi(sm.Full("i386"))
case "arm64":
syscallVal = "arm32/sys_prctl"
prctlID = arm32.SYS_PRCTL
sysIDChecker32 = sysIDChecker32.WithId(uint32(prctlID)).WithAbi(sm.Full("arm32"))
default:
t.Fatalf("Unknown arch: %s", a)
}
Expand All @@ -129,15 +139,15 @@ func TestEnforcerOverrideBothBits(t *testing.T) {
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(prctlID),
ec.NewKprobeArgumentChecker().WithSyscallId(sysIDChecker32),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

tpChecker64 := ec.NewProcessTracepointChecker("").
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_PRCTL),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_PRCTL)),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

Expand Down
14 changes: 11 additions & 3 deletions pkg/sensors/tracing/enforcer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ import (
"github.com/cilium/tetragon/pkg/policyfilter"
"github.com/cilium/tetragon/pkg/sensors"
"github.com/cilium/tetragon/pkg/sensors/base"
"github.com/cilium/tetragon/pkg/syscallinfo"
"github.com/cilium/tetragon/pkg/testutils"
tus "github.com/cilium/tetragon/pkg/testutils/sensors"
"github.com/cilium/tetragon/pkg/tracingpolicy"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"
)

Expand Down Expand Up @@ -102,7 +104,7 @@ func TestEnforcerOverride(t *testing.T) {
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(unix.SYS_GETCPU),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, unix.SYS_GETCPU)),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

Expand Down Expand Up @@ -156,7 +158,7 @@ func TestEnforcerOverrideManySyscalls(t *testing.T) {
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(unix.SYS_GETCPU),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, unix.SYS_GETCPU)),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

Expand Down Expand Up @@ -195,6 +197,12 @@ func TestEnforcerOverrideManySyscalls(t *testing.T) {
})
}

func mkSysIDChecker(t *testing.T, id uint64) *ec.SyscallIdChecker {
abi, err := syscallinfo.DefaultABI()
require.NoError(t, err)
return ec.NewSyscallIdChecker().WithId(uint32(id)).WithAbi(sm.Full(abi))
}

func TestEnforcerSignal(t *testing.T) {
testEnforcerCheckSkip(t)

Expand All @@ -204,7 +212,7 @@ func TestEnforcerSignal(t *testing.T) {
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_PRCTL),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_PRCTL)),
)).
WithAction(tetragon.KprobeAction_KPROBE_ACTION_NOTIFYENFORCER)

Expand Down
11 changes: 8 additions & 3 deletions pkg/sensors/tracing/generictracepoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,9 +832,14 @@ func handleMsgGenericTracepoint(
if err != nil {
logger.GetLogger().WithError(err).Warnf("Size type error sizeof %d", m.Common.Size)
}
// NB: clear Is32Bit to mantain previous behaviour
val = val & (^uint64(Is32Bit))
unix.Args = append(unix.Args, val)
if option.Config.CompatibilitySyscall64SizeType {
// NB: clear Is32Bit to mantain previous behaviour
val = val & (^uint64(Is32Bit))
unix.Args = append(unix.Args, val)
} else {
val := parseSyscall64Value(val)
unix.Args = append(unix.Args, val)
}

default:
logger.GetLogger().Warnf("handleGenericTracepoint: ignoring: %+v", out)
Expand Down
32 changes: 32 additions & 0 deletions pkg/sensors/tracing/syscall_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ package tracing

import (
"fmt"
"runtime"
"strings"

"github.com/cilium/tetragon/pkg/api/tracingapi"
"github.com/cilium/tetragon/pkg/arch"
"github.com/cilium/tetragon/pkg/syscallinfo"
)
Expand Down Expand Up @@ -93,6 +95,36 @@ func validateABI(xarg, abi string) error {
return nil
}

// returns abi, syscall id
func parseSyscall64Value(val uint64) tracingapi.MsgGenericSyscallID {
abi32 := false
if val&Is32Bit != 0 {
abi32 = true
val = val & (^uint64(Is32Bit))
}

abi := "unknown"
switch a := runtime.GOARCH; a {
case "amd64":
if abi32 {
abi = "i386"
} else {
abi = "x64"
}
case "arm64":
if abi32 {
abi = "arm32"
} else {
abi = "arm64"
}
}

return tracingapi.MsgGenericSyscallID{
ID: uint32(val),
ABI: abi,
}
}

func parseSyscallValue(value SyscallVal) (abi string, name string, err error) {
val := string(value)
arr := strings.Split(string(val), "/")
Expand Down
6 changes: 3 additions & 3 deletions pkg/sensors/tracing/tracepoint_amd64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,23 +104,23 @@ spec:
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_DUP)),
ec.NewKprobeArgumentChecker().WithSizeArg(9999),
))

tpCheckerDup2 := ec.NewProcessTracepointChecker("").
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP2),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_DUP2)),
ec.NewKprobeArgumentChecker().WithSizeArg(9999),
))

tpCheckerDup3 := ec.NewProcessTracepointChecker("").
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP3),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, syscall.SYS_DUP3)),
ec.NewKprobeArgumentChecker().WithSizeArg(9999),
))

Expand Down
2 changes: 1 addition & 1 deletion pkg/sensors/tracing/tracepoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ spec:
WithArgs(ec.NewKprobeArgumentListMatcher().
WithOperator(lc.Ordered).
WithValues(
ec.NewKprobeArgumentChecker().WithSizeArg(syscall.SYS_DUP),
ec.NewKprobeArgumentChecker().WithSyscallId(mkSysIDChecker(t, unix.SYS_DUP)),
ec.NewKprobeArgumentChecker().WithSizeArg(uint64(i)),
))

Expand Down

0 comments on commit b335808

Please sign in to comment.