diff --git a/bpf/process/string_maps.h b/bpf/process/string_maps.h index 1142443386f..a27d6eff0de 100644 --- a/bpf/process/string_maps.h +++ b/bpf/process/string_maps.h @@ -171,7 +171,7 @@ struct { #ifdef __LARGE_BPF_PROG #define STRING_POSTFIX_MAX_MATCH_LENGTH STRING_POSTFIX_MAX_LENGTH #else -#define STRING_POSTFIX_MAX_MATCH_LENGTH 96 +#define STRING_POSTFIX_MAX_MATCH_LENGTH 95 #endif struct string_postfix_lpm_trie { diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index ce49f8cc2b0..96d32fec6db 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -775,17 +775,25 @@ filter_char_buf_prefix(struct selector_arg_filter *filter, char *arg_str, uint a int zero = 0; addrmap = map_lookup_elem(&string_prefix_maps, &map_idx); - if (!addrmap) + if (!addrmap || !arg_len) return 0; - if (arg_len > STRING_PREFIX_MAX_LENGTH || !arg_len) - return 0; + // If the string to check is longer than the prefix map allows, then only check the longest + // substring that the map allows. + if (arg_len >= STRING_PREFIX_MAX_LENGTH) + arg_len = STRING_PREFIX_MAX_LENGTH - 1; arg = (struct string_prefix_lpm_trie *)map_lookup_elem(&string_prefix_maps_heap, &zero); if (!arg) return 0; arg->prefixlen = arg_len * 8; // prefix is in bits + + // Force the verifier to recheck the arg_len after register spilling on 4.19. + asm volatile("%[arg_len] &= %[mask] ;\n" + : [arg_len] "+r"(arg_len) + : [mask] "i"(STRING_PREFIX_MAX_LENGTH - 1)); + probe_read(arg->data, arg_len & (STRING_PREFIX_MAX_LENGTH - 1), arg_str); __u8 *pass = map_lookup_elem(addrmap, arg); @@ -793,8 +801,11 @@ filter_char_buf_prefix(struct selector_arg_filter *filter, char *arg_str, uint a return !!pass; } +// Define a mask for the maximum path length on Linux. +#define PATH_MASK (4096 - 1) + static inline __attribute__((always_inline)) void -copy_reverse(__u8 *dest, uint len, __u8 *src) +copy_reverse(__u8 *dest, uint len, __u8 *src, uint offset) { uint i; @@ -813,8 +824,8 @@ copy_reverse(__u8 *dest, uint len, __u8 *src) // Alternative (prettier) fixes resulted in a confused verifier // unfortunately. for (i = 0; i < (STRING_POSTFIX_MAX_MATCH_LENGTH - 1); i++) { - dest[i & STRING_POSTFIX_MAX_MASK] = src[(len - 1 - i) & STRING_POSTFIX_MAX_MASK]; - if (len == (i + 1)) + dest[i & STRING_POSTFIX_MAX_MASK] = src[(len + offset - 1 - i) & PATH_MASK]; + if (len + offset == (i + 1)) return; } } @@ -825,21 +836,22 @@ filter_char_buf_postfix(struct selector_arg_filter *filter, char *arg_str, uint void *addrmap; __u32 map_idx = *(__u32 *)&filter->value; struct string_postfix_lpm_trie *arg; + uint orig_len = arg_len; int zero = 0; addrmap = map_lookup_elem(&string_postfix_maps, &map_idx); - if (!addrmap) + if (!addrmap || !arg_len) return 0; - if (arg_len > STRING_POSTFIX_MAX_LENGTH || !arg_len) - return 0; + if (arg_len >= STRING_POSTFIX_MAX_MATCH_LENGTH) + arg_len = STRING_POSTFIX_MAX_MATCH_LENGTH - 1; arg = (struct string_postfix_lpm_trie *)map_lookup_elem(&string_postfix_maps_heap, &zero); if (!arg) return 0; arg->prefixlen = arg_len * 8; // prefix is in bits - copy_reverse(arg->data, arg_len, (__u8 *)arg_str); + copy_reverse(arg->data, arg_len, (__u8 *)arg_str, orig_len - arg_len); __u8 *pass = map_lookup_elem(addrmap, arg); diff --git a/pkg/sensors/tracing/kprobe_test.go b/pkg/sensors/tracing/kprobe_test.go index 22d96a03f46..b1bf7df5c6d 100644 --- a/pkg/sensors/tracing/kprobe_test.go +++ b/pkg/sensors/tracing/kprobe_test.go @@ -1057,6 +1057,25 @@ func TestKprobeObjectFilterPrefixOpen(t *testing.T) { testKprobeObjectFiltered(t, readHook, getOpenatChecker(t, dir), false, dir, false, syscall.O_RDWR, 0x770) } +func TestKprobeObjectFilterPrefixOpenSuperLong(t *testing.T) { + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + dir := t.TempDir() + readHook := testKprobeObjectFilterPrefixOpenHook(pidStr, dir) + firstDir := dir + "/testfoo" + longDir := firstDir + "/1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + if err := os.Mkdir(firstDir, 0755); err != nil { + t.Logf("Mkdir %s failed: %s\n", firstDir, err) + t.Skip() + } + if err := os.Mkdir(longDir, 0755); err != nil { + t.Logf("Mkdir %s failed: %s\n", longDir, err) + t.Skip() + } + testKprobeObjectFiltered(t, readHook, getOpenatChecker(t, longDir), false, longDir, false, syscall.O_RDWR, 0x770) +} + func TestKprobeObjectFilterPrefixOpenMount(t *testing.T) { pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) dir := t.TempDir() @@ -1244,6 +1263,50 @@ func TestKprobeObjectPostfixOpenWithNull(t *testing.T) { testKprobeObjectPostfixOpen(t, true) } +func TestKprobeObjectPostfixOpenSuperLong(t *testing.T) { + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + dir := t.TempDir() + readHook := ` +apiVersion: cilium.io/v1alpha1 +kind: TracingPolicy +metadata: + name: "sys-read" +spec: + kprobes: + - call: "sys_openat" + return: false + syscall: true + args: + - index: 0 + type: int + - index: 1 + type: "string" + - index: 2 + type: "int" + selectors: + - matchPIDs: + - operator: In + followForks: true + values: + - ` + pidStr + ` + matchArgs: + - index: 1 + operator: "Postfix" + values: + - "` + testKprobeObjectPostfixOpenFileName(false) + `" +` + + longDir := dir + "/1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + + "123456789012345678901234567890123456789012345678901234567890" + if err := os.Mkdir(longDir, 0755); err != nil { + t.Logf("Mkdir %s failed: %s\n", longDir, err) + t.Skip() + } + + testKprobeObjectFiltered(t, readHook, getOpenatChecker(t, longDir), false, longDir, false, syscall.O_RDWR, 0x770) +} + func testKprobeObjectFilterModeOpenHook(pidStr string, mode int, valueFmt string) string { return ` apiVersion: cilium.io/v1alpha1