Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tetragon: Add support to match 32 bit syscalls #1816

Merged
merged 10 commits into from
Dec 13, 2023
6 changes: 6 additions & 0 deletions .github/workflows/gotests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ jobs:
with:
go-version-file: 'go/src/github.com/cilium/tetragon/go.mod'

- name: Install dependencies x86
with:
platforms: linux/amd64
run: |
sudo apt-get -y install libc6-dev-i386

- name: Install dependencies
run: |
sudo apt-get -y install libelf-dev netcat-traditional libcap-dev gcc
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/vmtests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:

- name: Install build dependencies
run: |
sudo apt install libelf-dev netcat-traditional libcap-dev gcc
sudo apt install libelf-dev netcat-traditional libcap-dev gcc libc6-dev-i386
echo `which clang`
echo `which llc`
echo `clang --version`
Expand Down
1 change: 1 addition & 0 deletions bpf/lib/generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct msg_selector_data {
#ifdef __CAP_CHANGES_FILTER
__u64 match_cap;
#endif
bool is32BitSyscall;
};

struct msg_generic_kprobe {
Expand Down
1 change: 1 addition & 0 deletions bpf/process/bpf_generic_tracepoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static inline __attribute__((always_inline)) unsigned long get_ctx_ul(void *src,
int type)
{
switch (type) {
case syscall64_type:
case nop_s64_ty:
case nop_u64_ty:
case s64_ty:
Expand Down
27 changes: 27 additions & 0 deletions bpf/process/generic_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "bpf_tracing.h"
#include "types/basic.h"
#include "vmlinux.h"

#define MAX_TOTAL 9000

Expand Down Expand Up @@ -70,6 +71,29 @@ generic_process_event(void *ctx, struct bpf_map_def *heap_map,
return 0;
}

#define TS_COMPAT 0x0002

#ifdef __TARGET_ARCH_x86
static inline __attribute__((always_inline)) void
generic_setup_32bit_syscall(struct msg_generic_kprobe *e, u8 op)
{
struct thread_info *info;
__u32 status;

switch (op) {
case MSG_OP_GENERIC_TRACEPOINT:
case MSG_OP_GENERIC_KPROBE:
info = (struct thread_info *)get_current_task();
probe_read(&status, sizeof(status), _(&info->status));
e->sel.is32BitSyscall = status & TS_COMPAT;
default:
break;
}
}
#else
#define generic_setup_32bit_syscall(e, op)
#endif

static inline __attribute__((always_inline)) void
generic_process_init(struct msg_generic_kprobe *e, u8 op, struct event_config *config)
{
Expand All @@ -93,6 +117,9 @@ generic_process_init(struct msg_generic_kprobe *e, u8 op, struct event_config *c
* At kprobes, tracpoints etc we report the calling thread ID to user space.
*/
e->tid = (__u32)get_current_pid_tgid();

/* Get 32-bit syscall emulation bit value. */
generic_setup_32bit_syscall(e, op);
}

static inline __attribute__((always_inline)) int
Expand Down
21 changes: 17 additions & 4 deletions bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ enum {
load_module_type = 26,
kernel_module_type = 27,

syscall64_type = 28,

nop_s64_ty = -10,
nop_u64_ty = -11,
nop_u32_ty = -12,
Expand Down Expand Up @@ -123,6 +125,8 @@ struct selector_arg_filters {

#define FLAGS_EARLY_FILTER BIT(0)

#define IS_32BIT 0x80000000

struct event_config {
__u32 func_id;
__s32 arg0;
Expand Down Expand Up @@ -1298,7 +1302,7 @@ filter_64ty_selector_val(struct selector_arg_filter *filter, char *args)
// use the selector value to determine a hash map, and do a lookup to determine whether the argument
// is in the defined set.
static inline __attribute__((always_inline)) long
filter_64ty_map(struct selector_arg_filter *filter, char *args)
filter_64ty_map(struct selector_arg_filter *filter, char *args, bool set32bit)
{
void *argmap;
__u32 map_idx = filter->value;
Expand All @@ -1308,6 +1312,10 @@ filter_64ty_map(struct selector_arg_filter *filter, char *args)
return 0;

__u64 arg = *((__u64 *)args);

if (set32bit)
arg |= IS_32BIT;

__u8 *pass = map_lookup_elem(argmap, &arg);

switch (filter->op) {
Expand All @@ -1320,7 +1328,7 @@ filter_64ty_map(struct selector_arg_filter *filter, char *args)
}

static inline __attribute__((always_inline)) long
filter_64ty(struct selector_arg_filter *filter, char *args)
filter_64ty(struct selector_arg_filter *filter, char *args, bool set32bit)
{
switch (filter->op) {
case op_filter_lt:
Expand All @@ -1331,7 +1339,7 @@ filter_64ty(struct selector_arg_filter *filter, char *args)
return filter_64ty_selector_val(filter, args);
case op_filter_inmap:
case op_filter_notinmap:
return filter_64ty_map(filter, args);
return filter_64ty_map(filter, args, set32bit);
}

return 0;
Expand Down Expand Up @@ -1640,6 +1648,8 @@ selector_arg_offset(__u8 *f, struct msg_generic_kprobe *e, __u32 selidx,
for (i = 0; i < 5; i++)
#endif
{
bool set32bit = false;

argsoff = filters->argoff[i];
asm volatile("%[argsoff] &= 0x3ff;\n" ::[argsoff] "+r"(argsoff)
:);
Expand Down Expand Up @@ -1679,9 +1689,11 @@ selector_arg_offset(__u8 *f, struct msg_generic_kprobe *e, __u32 selidx,
*/
pass &= filter_char_buf(filter, args, 8);
break;
case syscall64_type:
set32bit = e->sel.is32BitSyscall;
case s64_ty:
case u64_ty:
pass &= filter_64ty(filter, args);
pass &= filter_64ty(filter, args, set32bit);
break;
case size_type:
case int_type:
Expand Down Expand Up @@ -2427,6 +2439,7 @@ read_call_arg(void *ctx, struct msg_generic_kprobe *e, int index, int type,
case string_type:
size = copy_strings(args, arg);
break;
case syscall64_type:
case size_type:
case s64_ty:
case u64_ty:
Expand Down
6 changes: 5 additions & 1 deletion contrib/tester-progs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ PROGS = sigkill-tester \
threads-tester \
bench-reader \
threads-exit \
killer-tester
killer-tester \
killer-tester-32

all: $(PROGS)

Expand Down Expand Up @@ -61,6 +62,9 @@ uprobe-test-1: uprobe-test.c libuprobe.so
uprobe-test-2: uprobe-test-1
cp uprobe-test-1 uprobe-test-2

killer-tester-32: killer-tester.c
$(GCC) -Wall -m32 $< -o $@

lseek-pipe: FORCE
go build -o lseek-pipe ./go/lseek-pipe

Expand Down
42 changes: 42 additions & 0 deletions docs/content/en/docs/concepts/tracing-policy/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,24 @@ spec:
- "sys_close"
```

Syscalls specified with `sys_` prefix are translated to their 64 bit equivalent function names.

It's possible to specify 32 bit syscall by using its full function name that
includes specific architecture native prefix (like `__ia32_` for `x86`):

```yaml
spec:
lists:
- name: "dups"
type: "syscalls"
values:
- "sys_dup"
- "__ia32_sys_dup"
name: "another"
- "sys_open"
- "sys_close"
```

Specific list can be referenced in kprobe's `call` field with `"list:NAME"` value.

```yaml
Expand Down Expand Up @@ -520,3 +538,27 @@ spec:
values:
- "/usr/bin/kill"
```

Note that if syscall list is used in selector with InMap operator, the argument type needs to be `syscall64`, like.

```yaml
spec:
lists:
- name: "dups"
type: "syscalls"
values:
- "sys_dup"
- "__ia32_sys_dup"
tracepoints:
- subsystem: "raw_syscalls"
event: "sys_enter"
args:
- index: 4
type: "syscall64"
selectors:
- matchArgs:
- index: 0
operator: "InMap"
values:
- "list:dups"
```
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ spec:
event: "sys_enter"
args:
- index: 4
type: "uint64"
type: "syscall64"
selectors:
- matchArgs:
- index: 0
Expand Down
3 changes: 2 additions & 1 deletion examples/tracingpolicy/killer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ spec:
values:
- "sys_dup"
- "sys_dup2"
- "__ia32_sys_dup"
killers:
- syscalls:
- "list:dups"
Expand All @@ -17,7 +18,7 @@ spec:
event: "sys_enter"
args:
- index: 4
type: "uint64"
type: "syscall64"
selectors:
- matchArgs:
- index: 0
Expand Down
14 changes: 9 additions & 5 deletions pkg/arch/arch.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"testing"
)

var supportedArchPrefix = map[string]string{"amd64": "__x64_", "arm64": "__arm64_"}
var supportedArchPrefix = map[string]string{"amd64": "__x64_", "arm64": "__arm64_", "i386": "__ia32_"}

func addSyscallPrefix(symbol string, arch string) (string, error) {
for prefix_arch, prefix := range supportedArchPrefix {
Expand Down Expand Up @@ -59,11 +59,15 @@ func AddSyscallPrefixTestHelper(t *testing.T, symbol string) string {
}

// CutSyscallPrefix removes a potential arch specific prefix from the symbol
func CutSyscallPrefix(symbol string) string {
for _, prefix := range supportedArchPrefix {
// and returns true in second return argument if the prefix is 32 bits
func CutSyscallPrefix(symbol string) (string, bool) {
is32BitArch := func(arch string) bool {
return arch == "i386"
}
for arch, prefix := range supportedArchPrefix {
if strings.HasPrefix(symbol, prefix) {
return symbol[len(prefix):]
return symbol[len(prefix):], is32BitArch(arch)
}
}
return symbol
return symbol, false
}
3 changes: 2 additions & 1 deletion pkg/encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ func (p *CompactEncoder) EventToString(response *tetragon.GetEventsResponse) (st
return "", ErrMissingProcessInfo
}
processInfo, caps := p.Colorer.ProcessInfo(response.NodeName, kprobe.Process)
switch arch.CutSyscallPrefix(kprobe.FunctionName) {
sc, _ := arch.CutSyscallPrefix(kprobe.FunctionName)
switch sc {
case "sys_write":
event := p.Colorer.Blue.Sprintf("📝 %-7s", "write")
file := ""
Expand Down
4 changes: 4 additions & 0 deletions pkg/generictypes/generictypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const (
GenericLoadModule = 26
GenericKernelModule = 27

GenericSyscall64 = 28

GenericNopType = -1
GenericInvalidType = -2
)
Expand Down Expand Up @@ -97,6 +99,8 @@ func GenericTypeFromString(arg string) int {
return GenericLoadModule
case "module":
return GenericKernelModule
case "syscall64":
return GenericSyscall64
default:
return GenericInvalidType
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ spec:
- cred
- load_info
- module
- syscall64
type: string
required:
- index
Expand Down Expand Up @@ -202,6 +203,7 @@ spec:
- cred
- load_info
- module
- syscall64
type: string
required:
- index
Expand Down Expand Up @@ -752,6 +754,7 @@ spec:
- cred
- load_info
- module
- syscall64
type: string
required:
- index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ spec:
- cred
- load_info
- module
- syscall64
type: string
required:
- index
Expand Down Expand Up @@ -202,6 +203,7 @@ spec:
- cred
- load_info
- module
- syscall64
type: string
required:
- index
Expand Down Expand Up @@ -752,6 +754,7 @@ spec:
- cred
- load_info
- module
- syscall64
type: string
required:
- index
Expand Down
2 changes: 1 addition & 1 deletion pkg/k8s/apis/cilium.io/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type KProbeArg struct {
// +kubebuilder:validation:Minimum=0
// Position of the argument.
Index uint32 `json:"index"`
// +kubebuilder:validation:Enum=auto;int;uint32;int32;uint64;int64;char_buf;char_iovec;size_t;skb;sock;string;fd;file;filename;path;nop;bpf_attr;perf_event;bpf_map;user_namespace;capability;kiocb;iov_iter;cred;load_info;module;
// +kubebuilder:validation:Enum=auto;int;uint32;int32;uint64;int64;char_buf;char_iovec;size_t;skb;sock;string;fd;file;filename;path;nop;bpf_attr;perf_event;bpf_map;user_namespace;capability;kiocb;iov_iter;cred;load_info;module;syscall64;
// +kubebuilder:default=auto
// Argument type.
Type string `json:"type"`
Expand Down
Loading
Loading