From 834b5fe7d4063928cf7b89f61252637d833ca018 Mon Sep 17 00:00:00 2001 From: Kevin Sheldrake Date: Tue, 6 Feb 2024 13:25:21 +0000 Subject: [PATCH] String: Support longer exact match strings String matching is limited to strings of length 144 due to the way the hash look up tables were implemented (6 key sizes, 24 byte increments). This commit adds maps to support larger key/string sizes: 256, 512, 1024, 2048, and 4096. This will therefore permit exact string matches for strings of length up to 4096 (not including null terminator). Unfortunately, kernels v5.10 and lower restrict hash key lengths to 512 bytes, so on these kernels the maximum string length is 510 characters (512 - 2 bytes for embedded string length). And on older kernels (<5.3) the instruction and complexity limits mean the new approach is not feasible. Therefore on these kernels, the maximum string length is 144 characters (as before). Includes tests at map limits. Signed-off-by: Kevin Sheldrake --- bpf/Makefile | 21 ++- bpf/process/string_maps.h | 103 ++++++++++-- bpf/process/types/basic.h | 194 ++++++++++++++++++----- contrib/verify/verify.sh | 5 + pkg/kernels/kernels.go | 2 + pkg/selectors/kernel.go | 14 +- pkg/selectors/kernel_test.go | 39 +++-- pkg/selectors/selectors.go | 129 +++++++++++---- pkg/sensors/base/base.go | 2 + pkg/sensors/tracing/args.go | 9 +- pkg/sensors/tracing/generickprobe.go | 17 +- pkg/sensors/tracing/generictracepoint.go | 8 +- pkg/sensors/tracing/kprobe_test.go | 132 ++++++++++++++- pkg/sensors/tracing/selectors.go | 54 ++++++- 14 files changed, 615 insertions(+), 114 deletions(-) diff --git a/bpf/Makefile b/bpf/Makefile index 2e1ce7f86a7..b8947f5d262 100644 --- a/bpf/Makefile +++ b/bpf/Makefile @@ -20,6 +20,11 @@ PROCESS = bpf_execve_event.o bpf_execve_event_v53.o bpf_fork.o bpf_exit.o bpf_ge bpf_generic_tracepoint_v61.o \ bpf_multi_kprobe_v61.o bpf_multi_retkprobe_v61.o \ bpf_generic_uprobe_v61.o \ + bpf_execve_event_v511.o \ + bpf_generic_kprobe_v511.o bpf_generic_retkprobe_v511.o \ + bpf_generic_tracepoint_v511.o \ + bpf_multi_kprobe_v511.o bpf_multi_retkprobe_v511.o \ + bpf_generic_uprobe_v511.o \ bpf_loader.o \ bpf_killer.o bpf_multi_killer.o bpf_fmodret_killer.o @@ -66,6 +71,7 @@ endef # Generic build targets for each sub-dir $(eval $(call DEFINE_VARIANT,v53)) +$(eval $(call DEFINE_VARIANT,v511)) $(eval $(call DEFINE_VARIANT,v61)) # ALIGNCHECKER @@ -117,13 +123,22 @@ $(DEPSDIR)%_v53.d: $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@ objs/bpf_multi_kprobe_v61.ll objs/bpf_multi_retkprobe_v61.ll: - $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__V61_BPF_PROG -D__MULTI_KPROBE -c $< -o $@ + $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -D__V61_BPF_PROG -D__MULTI_KPROBE -c $< -o $@ objs/%_v61.ll: - $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__V61_BPF_PROG -c $< -o $@ + $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -D__V61_BPF_PROG -c $< -o $@ $(DEPSDIR)%_v61.d: - $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__V61_BPF_PROG -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@ + $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -D__V61_BPF_PROG -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@ + +objs/bpf_multi_kprobe_v511.ll objs/bpf_multi_retkprobe_v511.ll: + $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -D__MULTI_KPROBE -c $< -o $@ + +objs/%_v511.ll: + $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -c $< -o $@ + +$(DEPSDIR)%_v511.d: + $(CLANG) $(CLANG_FLAGS) -D__LARGE_BPF_PROG -D__LARGE_MAP_KEYS -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@ # BPFTESTDIR objs/%.ll: $(BPFTESTDIR)%.c diff --git a/bpf/process/string_maps.h b/bpf/process/string_maps.h index a27d6eff0de..a91cc7e4e59 100644 --- a/bpf/process/string_maps.h +++ b/bpf/process/string_maps.h @@ -32,19 +32,35 @@ * up are equally padded to the smallest key size that can accommodate them, and then * looked up in the related map. * - * The chosen key sizes are 25, 49, 73, 97, 121, 145 (6 maps). + * The chosen key sizes are 25, 49, 73, 97, 121, 145, 258, 514, 1026, 2050, 4098 (11 maps). + * The first 6 are sized for common uses and to minimise the hashing of empty bytes. The + * following 5 maps notionally double in size, with lengths equal to 2^k + 2. On kernels + * <5.11, the last four maps are replaced with a single map with key size 512. This is due + * to key size limitations on kernels <5.11. * * In order to distinguish between character buffers that end in 0s and similar buffers * that are padded with 0s, each string will be prefixed by its length stored in a - * single byte. + * single byte (for first 6 maps) or as a little endian u16 (latter maps). */ #define STRING_MAPS_KEY_INC_SIZE 24 -#define STRING_MAPS_SIZE_0 1 * STRING_MAPS_KEY_INC_SIZE + 1 -#define STRING_MAPS_SIZE_1 2 * STRING_MAPS_KEY_INC_SIZE + 1 -#define STRING_MAPS_SIZE_2 3 * STRING_MAPS_KEY_INC_SIZE + 1 -#define STRING_MAPS_SIZE_3 4 * STRING_MAPS_KEY_INC_SIZE + 1 -#define STRING_MAPS_SIZE_4 5 * STRING_MAPS_KEY_INC_SIZE + 1 -#define STRING_MAPS_SIZE_5 6 * STRING_MAPS_KEY_INC_SIZE + 1 +#define STRING_MAPS_SIZE_0 (1 * STRING_MAPS_KEY_INC_SIZE + 1) +#define STRING_MAPS_SIZE_1 (2 * STRING_MAPS_KEY_INC_SIZE + 1) +#define STRING_MAPS_SIZE_2 (3 * STRING_MAPS_KEY_INC_SIZE + 1) +#define STRING_MAPS_SIZE_3 (4 * STRING_MAPS_KEY_INC_SIZE + 1) +#define STRING_MAPS_SIZE_4 (5 * STRING_MAPS_KEY_INC_SIZE + 1) +#define STRING_MAPS_SIZE_5 (6 * STRING_MAPS_KEY_INC_SIZE + 1) +#define STRING_MAPS_SIZE_6 (256 + 2) +#ifdef __LARGE_MAP_KEYS +#define STRING_MAPS_SIZE_7 (512 + 2) +#define STRING_MAPS_SIZE_8 (1024 + 2) +#define STRING_MAPS_SIZE_9 (2048 + 2) +#define STRING_MAPS_SIZE_10 (4096 + 2) +#else +#define STRING_MAPS_SIZE_7 (512) +#endif +#define STRING_MAPS_HEAP_SIZE 16384 +#define STRING_MAPS_HEAP_MASK (8192 - 1) +#define STRING_MAPS_COPY_MASK 4095 struct { __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); @@ -124,18 +140,85 @@ struct { }); } string_maps_5 SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, STRING_MAPS_OUTER_MAX_ENTRIES); + __uint(key_size, sizeof(__u32)); + __array( + values, struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u8[STRING_MAPS_SIZE_6]); + __type(value, __u8); + }); +} string_maps_6 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, STRING_MAPS_OUTER_MAX_ENTRIES); + __uint(key_size, sizeof(__u32)); + __array( + values, struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u8[STRING_MAPS_SIZE_7]); + __type(value, __u8); + }); +} string_maps_7 SEC(".maps"); + +#ifdef __LARGE_MAP_KEYS +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, STRING_MAPS_OUTER_MAX_ENTRIES); + __uint(key_size, sizeof(__u32)); + __array( + values, struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u8[STRING_MAPS_SIZE_8]); + __type(value, __u8); + }); +} string_maps_8 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, STRING_MAPS_OUTER_MAX_ENTRIES); + __uint(key_size, sizeof(__u32)); + __array( + values, struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u8[STRING_MAPS_SIZE_9]); + __type(value, __u8); + }); +} string_maps_9 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); + __uint(max_entries, STRING_MAPS_OUTER_MAX_ENTRIES); + __uint(key_size, sizeof(__u32)); + __array( + values, struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u8[STRING_MAPS_SIZE_10]); + __type(value, __u8); + }); +} string_maps_10 SEC(".maps"); +#endif + struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); __uint(key_size, sizeof(__u32)); - __uint(value_size, 512); + __uint(value_size, STRING_MAPS_HEAP_SIZE); } string_maps_heap SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); __uint(key_size, sizeof(__u32)); - __uint(value_size, 512); + __uint(value_size, STRING_MAPS_HEAP_SIZE); } string_maps_ro_zero SEC(".maps"); #define STRING_PREFIX_MAX_LENGTH 256 diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index 5513fa58848..62dd8bfa6c4 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -192,7 +192,15 @@ struct event_config { * we will need to resize. TBD would be to size these at compile time using * buffer size information. */ -#define MAX_STRING 1024 +#ifdef __LARGE_BPF_PROG +#ifdef __LARGE_MAP_KEYS +#define MAX_STRING (STRING_MAPS_SIZE_10 - 2) +#else +#define MAX_STRING (STRING_MAPS_SIZE_7 - 2) +#endif +#else +#define MAX_STRING (STRING_MAPS_SIZE_5 - 1) +#endif #ifdef __MULTI_KPROBE static inline __attribute__((always_inline)) __u32 get_index(void *ctx) @@ -470,7 +478,9 @@ copy_strings(char *args, unsigned long arg) long size; // probe_read_str() always nul-terminates the string. - size = probe_read_str(&args[4], MAX_STRING, (char *)arg); + // So add one to the length to allow for it. This should + // result in us honouring our MAX_STRING correctly. + size = probe_read_str(&args[4], MAX_STRING + 1, (char *)arg); if (size <= 1) return invalid_ty; // Remove the nul character from end. @@ -703,31 +713,131 @@ copy_char_buf(void *ctx, long off, unsigned long arg, int argm, return __copy_char_buf(ctx, off, arg, bytes, has_max_data(argm), e, data_heap); } +static inline __attribute__((always_inline)) u16 +string_padded_len(u16 len) +{ + u16 padded_len = len; + + if (len < STRING_MAPS_SIZE_5) { + if (len % STRING_MAPS_KEY_INC_SIZE != 0) + padded_len = ((len / STRING_MAPS_KEY_INC_SIZE) + 1) * STRING_MAPS_KEY_INC_SIZE; + return padded_len; + } + if (len <= STRING_MAPS_SIZE_6 - 2) + return STRING_MAPS_SIZE_6 - 2; +#ifdef __LARGE_BPF_PROG +#ifdef __LARGE_MAP_KEYS + if (len <= STRING_MAPS_SIZE_7 - 2) + return STRING_MAPS_SIZE_7 - 2; + if (len <= STRING_MAPS_SIZE_8 - 2) + return STRING_MAPS_SIZE_8 - 2; + if (len <= STRING_MAPS_SIZE_9 - 2) + return STRING_MAPS_SIZE_9 - 2; + return STRING_MAPS_SIZE_10 - 2; +#else + return STRING_MAPS_SIZE_7 - 2; +#endif +#else + return STRING_MAPS_SIZE_5 - 1; +#endif +} + +static inline __attribute__((always_inline)) int +string_map_index(u16 padded_len) +{ + if (padded_len < STRING_MAPS_SIZE_5) + return (padded_len / STRING_MAPS_KEY_INC_SIZE) - 1; + +#ifdef __LARGE_BPF_PROG +#ifdef __LARGE_MAP_KEYS + switch (padded_len) { + case STRING_MAPS_SIZE_6 - 2: + return 6; + case STRING_MAPS_SIZE_7 - 2: + return 7; + case STRING_MAPS_SIZE_8 - 2: + return 8; + case STRING_MAPS_SIZE_9 - 2: + return 9; + } + return 10; +#else + if (padded_len == STRING_MAPS_SIZE_6 - 2) + return 6; + return 7; +#endif +#else + return 5; +#endif +} + +static inline __attribute__((always_inline)) void * +get_string_map(int index, __u32 map_idx) +{ + switch (index) { + case 0: + return map_lookup_elem(&string_maps_0, &map_idx); + case 1: + return map_lookup_elem(&string_maps_1, &map_idx); + case 2: + return map_lookup_elem(&string_maps_2, &map_idx); + case 3: + return map_lookup_elem(&string_maps_3, &map_idx); + case 4: + return map_lookup_elem(&string_maps_4, &map_idx); + case 5: + return map_lookup_elem(&string_maps_5, &map_idx); +#ifdef __LARGE_BPF_PROG + case 6: + return map_lookup_elem(&string_maps_6, &map_idx); + case 7: + return map_lookup_elem(&string_maps_7, &map_idx); +#ifdef __LARGE_MAP_KEYS + case 8: + return map_lookup_elem(&string_maps_8, &map_idx); + case 9: + return map_lookup_elem(&string_maps_9, &map_idx); + case 10: + return map_lookup_elem(&string_maps_10, &map_idx); +#endif +#endif + } + return 0; +} + static inline __attribute__((always_inline)) long filter_char_buf_equal(struct selector_arg_filter *filter, char *arg_str, uint orig_len) { __u32 *map_ids = (__u32 *)&filter->value; + char *heap, *zero_heap; void *string_map; + __u16 padded_len; __u32 map_idx; - __u8 len; - __u8 padded_len; - int index; - char *heap, *zero_heap; int zero = 0; + __u16 len; + int index; - if (orig_len >= STRING_MAPS_SIZE_5 || !orig_len) +#ifdef __LARGE_BPF_PROG +#ifdef __LARGE_MAP_KEYS + if (orig_len > STRING_MAPS_SIZE_10 - 2 || !orig_len) + return 0; +#else + if (orig_len > STRING_MAPS_SIZE_7 - 2 || !orig_len) + return 0; +#endif +#else + if (orig_len > STRING_MAPS_SIZE_5 - 1 || !orig_len) return 0; +#endif - len = (__u8)orig_len; + len = (__u16)orig_len; // Calculate padded string length - padded_len = len; - if (len % STRING_MAPS_KEY_INC_SIZE != 0) - padded_len = ((len / STRING_MAPS_KEY_INC_SIZE) + 1) * STRING_MAPS_KEY_INC_SIZE; + padded_len = string_padded_len(len); // Check if we have entries for this padded length. // Do this before we copy data for efficiency. - index = (padded_len / STRING_MAPS_KEY_INC_SIZE) - 1; - map_idx = map_ids[index & 0x7]; + index = string_map_index(padded_len); + map_idx = map_ids[index & 0xf]; if (map_idx == 0xffffffff) return 0; @@ -736,46 +846,46 @@ filter_char_buf_equal(struct selector_arg_filter *filter, char *arg_str, uint or if (!heap || !zero_heap) return 0; - // Copy string to heap, preceded by length + // Copy string to heap, preceded by length - + // u8 for first 6 maps; u16 for latter maps +#ifdef __LARGE_BPF_PROG + if (index <= 5) + heap[0] = len; + else + *(u16 *)heap = len; +#else heap[0] = len; +#endif - asm volatile("%[len] &= 0xff;\n" + asm volatile("%[len] &= %1;\n" : [len] "+r"(len) - :); + : "i"(STRING_MAPS_HEAP_MASK)); +#ifdef __LARGE_BPF_PROG + if (index <= 5) + probe_read(&heap[1], len, arg_str); + else + probe_read(&heap[2], len, arg_str); +#else probe_read(&heap[1], len, arg_str); +#endif // Pad string to multiple of key increment size if (padded_len > len) { - asm volatile("%[len] &= 0xff;\n" + asm volatile("%[len] &= %1;\n" : [len] "+r"(len) - :); - probe_read(heap + len + 1, (padded_len - len) & 0xff, zero_heap); + : "i"(STRING_MAPS_HEAP_MASK)); +#ifdef __LARGE_BPF_PROG + if (index <= 5) + probe_read(heap + len + 1, (padded_len - len) & STRING_MAPS_COPY_MASK, zero_heap); + else + probe_read(heap + len + 2, (padded_len - len) & STRING_MAPS_COPY_MASK, zero_heap); +#else + probe_read(heap + len + 1, (padded_len - len) & STRING_MAPS_COPY_MASK, zero_heap); +#endif } // Get map for this string length - switch (index) { - case 0: - string_map = map_lookup_elem(&string_maps_0, &map_idx); - break; - case 1: - string_map = map_lookup_elem(&string_maps_1, &map_idx); - break; - case 2: - string_map = map_lookup_elem(&string_maps_2, &map_idx); - break; - case 3: - string_map = map_lookup_elem(&string_maps_3, &map_idx); - break; - case 4: - string_map = map_lookup_elem(&string_maps_4, &map_idx); - break; - case 5: - string_map = map_lookup_elem(&string_maps_5, &map_idx); - break; - default: - return 0; - } - + string_map = get_string_map(index, map_idx); if (!string_map) return 0; diff --git a/contrib/verify/verify.sh b/contrib/verify/verify.sh index d5858d191cb..3f17a3e6fed 100755 --- a/contrib/verify/verify.sh +++ b/contrib/verify/verify.sh @@ -68,6 +68,11 @@ for obj in "$TETRAGONDIR"/*.o; do continue fi + # Skip v5.11 objects check for kernel < 5.11 + if [[ "$B" == *511.o && $(echo "$KERNEL < 5.11" | bc) == 1 ]]; then + continue + fi + # Skip bpf_loader for kernel < 5.19 if [[ "$B" == bpf_loader* && $(echo "$KERNEL < 5.19" | bc) == 1 ]]; then continue diff --git a/pkg/kernels/kernels.go b/pkg/kernels/kernels.go index 53ad548ed44..c85070f8d0b 100644 --- a/pkg/kernels/kernels.go +++ b/pkg/kernels/kernels.go @@ -155,6 +155,8 @@ func IsKernelVersionLessThan(version string) bool { func GenericKprobeObjs() (string, string) { if EnableV61Progs() { return "bpf_generic_kprobe_v61.o", "bpf_generic_retkprobe_v61.o" + } else if MinKernelVersion("5.11") { + return "bpf_generic_kprobe_v511.o", "bpf_generic_retkprobe_v511.o" } else if EnableLargeProgs() { return "bpf_generic_kprobe_v53.o", "bpf_generic_retkprobe_v53.o" } diff --git a/pkg/selectors/kernel.go b/pkg/selectors/kernel.go index 2eb91e221e6..be669001ab2 100644 --- a/pkg/selectors/kernel.go +++ b/pkg/selectors/kernel.go @@ -728,8 +728,18 @@ func writeMatchStrings(k *KernelSelectorState, values []string, ty uint32) error if err != nil { return fmt.Errorf("MatchArgs value %s invalid: %w", v, err) } - for sizeIdx := 0; sizeIdx < StringMapsNumSubMaps; sizeIdx++ { - if size == StringMapsSizes[sizeIdx] { + numSubMaps := StringMapsNumSubMaps + if !kernels.MinKernelVersion("5.11") { + numSubMaps = StringMapsNumSubMapsSmall + } + + for sizeIdx := 0; sizeIdx < numSubMaps; sizeIdx++ { + stringMapSize := StringMapsSizes[sizeIdx] + if sizeIdx == 7 && !kernels.MinKernelVersion("5.11") { + stringMapSize = StringMapSize7a + } + + if size == stringMapSize { maps[sizeIdx][value] = struct{}{} break } diff --git a/pkg/selectors/kernel_test.go b/pkg/selectors/kernel_test.go index 909af89f6d1..05824be58c9 100644 --- a/pkg/selectors/kernel_test.go +++ b/pkg/selectors/kernel_test.go @@ -231,7 +231,7 @@ func TestParseMatchArg(t *testing.T) { expected1 := []byte{ 0x01, 0x00, 0x00, 0x00, // Index == 1 0x03, 0x00, 0x00, 0x00, // operator == equal - 32, 0x00, 0x00, 0x00, // length == 32 + 52, 0x00, 0x00, 0x00, // length == 32 0x06, 0x00, 0x00, 0x00, // value type == string 0x00, 0x00, 0x00, 0x00, // map ID for strings <25 0xff, 0xff, 0xff, 0xff, // map ID for strings 25-48 @@ -239,6 +239,11 @@ func TestParseMatchArg(t *testing.T) { 0xff, 0xff, 0xff, 0xff, // map ID for strings 73-96 0xff, 0xff, 0xff, 0xff, // map ID for strings 97-120 0xff, 0xff, 0xff, 0xff, // map ID for strings 121-144 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 145-256 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 257-512 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 513-1024 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 1025-2048 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 2049-4096 } if err := ParseMatchArg(k, arg1, sig); err != nil || bytes.Equal(expected1, d.e[0:d.off]) == false { t.Errorf("parseMatchArg: error %v expected:\n%v\nbytes:\n%v\nparsing %v\n", err, expected1, d.e[0:d.off], arg1) @@ -314,9 +319,9 @@ func TestParseMatchArg(t *testing.T) { if kernels.EnableLargeProgs() { // multiple match args are supported only in kernels >= 5.4 length := []byte{ - 88, 0x00, 0x00, 0x00, + 108, 0x00, 0x00, 0x00, 24, 0x00, 0x00, 0x00, - 64, 0x00, 0x00, 0x00, + 84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -595,11 +600,11 @@ func TestInitKernelSelectors(t *testing.T) { } expected_selsize_small := []byte{ - 0xfc, 0x00, 0x00, 0x00, // size = pids + args + actions + namespaces + capabilities + 4 + 0x10, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + capabilities + 4 } expected_selsize_large := []byte{ - 0x30, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + namespacesChanges + capabilities + capabilityChanges + 4 + 0x44, 0x01, 0x00, 0x00, // size = pids + args + actions + namespaces + namespacesChanges + capabilities + capabilityChanges + 4 } expected_filters := []byte{ @@ -684,17 +689,17 @@ func TestInitKernelSelectors(t *testing.T) { expected_last_large := []byte{ // arg header - 88, 0x00, 0x00, 0x00, // size = sizeof(arg2) + sizeof(arg1) + 24 + 108, 0x00, 0x00, 0x00, // size = sizeof(arg2) + sizeof(arg1) + 24 24, 0x00, 0x00, 0x00, // arg[0] offset - 64, 0x00, 0x00, 0x00, // arg[1] offset + 84, 0x00, 0x00, 0x00, // arg[1] offset 0x00, 0x00, 0x00, 0x00, // arg[2] offset 0x00, 0x00, 0x00, 0x00, // arg[3] offset 0x00, 0x00, 0x00, 0x00, // arg[4] offset - //arg1 size = 40 + //arg1 size = 60 0x01, 0x00, 0x00, 0x00, // Index == 1 0x03, 0x00, 0x00, 0x00, // operator == equal - 32, 0x00, 0x00, 0x00, // length == 32 + 52, 0x00, 0x00, 0x00, // length == 32 0x06, 0x00, 0x00, 0x00, // value type == string 0x00, 0x00, 0x00, 0x00, // map ID for strings <25 0xff, 0xff, 0xff, 0xff, // map ID for strings 25-48 @@ -702,6 +707,11 @@ func TestInitKernelSelectors(t *testing.T) { 0xff, 0xff, 0xff, 0xff, // map ID for strings 73-96 0xff, 0xff, 0xff, 0xff, // map ID for strings 97-120 0xff, 0xff, 0xff, 0xff, // map ID for strings 121-144 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 145-256 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 257-512 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 513-1024 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 1025-2048 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 2049-4096 //arg2 size = 24 0x02, 0x00, 0x00, 0x00, // Index == 2 @@ -724,17 +734,17 @@ func TestInitKernelSelectors(t *testing.T) { expected_last_small := []byte{ // arg header - 64, 0x00, 0x00, 0x00, // size = sizeof(arg2) + sizeof(arg1) + 32 + 84, 0x00, 0x00, 0x00, // size = sizeof(arg1) + 24 24, 0x00, 0x00, 0x00, // arg[0] offset 0x00, 0x00, 0x00, 0x00, // arg[1] offset 0x00, 0x00, 0x00, 0x00, // arg[2] offset 0x00, 0x00, 0x00, 0x00, // arg[3] offset 0x00, 0x00, 0x00, 0x00, // arg[4] offset - //arg1 size = 40 + //arg1 size = 60 0x01, 0x00, 0x00, 0x00, // Index == 1 0x03, 0x00, 0x00, 0x00, // operator == equal - 32, 0x00, 0x00, 0x00, // length == 32 + 52, 0x00, 0x00, 0x00, // length == 32 0x06, 0x00, 0x00, 0x00, // value type == string 0x00, 0x00, 0x00, 0x00, // map ID for strings <25 0xff, 0xff, 0xff, 0xff, // map ID for strings 25-48 @@ -742,6 +752,11 @@ func TestInitKernelSelectors(t *testing.T) { 0xff, 0xff, 0xff, 0xff, // map ID for strings 73-96 0xff, 0xff, 0xff, 0xff, // map ID for strings 97-120 0xff, 0xff, 0xff, 0xff, // map ID for strings 121-144 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 145-256 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 257-512 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 513-1024 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 1025-2048 + 0xff, 0xff, 0xff, 0xff, // map ID for strings 2049-4096 // actions header 32, 0x00, 0x00, 0x00, // size = (4 * sizeof(uint32) * number of actions) + args + 4 diff --git a/pkg/selectors/selectors.go b/pkg/selectors/selectors.go index a17fb7faf71..27bd49fd82b 100644 --- a/pkg/selectors/selectors.go +++ b/pkg/selectors/selectors.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/cilium/tetragon/pkg/api/processapi" + "github.com/cilium/tetragon/pkg/kernels" ) type KernelLPMTrie4 struct { @@ -29,20 +30,45 @@ type ValueReader interface { } const ( - stringMapsKeyIncSize = 24 - StringMapsNumSubMaps = 6 - MaxStringMapsSize = 6*stringMapsKeyIncSize + 1 - StringPrefixMaxLength = 256 - StringPostfixMaxLength = 128 + stringMapsKeyIncSize = 24 + StringMapsNumSubMaps = 11 + StringMapsNumSubMapsSmall = 8 + MaxStringMapsSize = 4096 + 2 + StringPrefixMaxLength = 256 + StringPostfixMaxLength = 128 + + // Maps with key string length <256 only require a single byte + // to store string length. Maps with key string length >=256 + // require two bytes to store string length. + stringMapSize0 = 1*stringMapsKeyIncSize + 1 + stringMapSize1 = 2*stringMapsKeyIncSize + 1 + stringMapSize2 = 3*stringMapsKeyIncSize + 1 + stringMapSize3 = 4*stringMapsKeyIncSize + 1 + stringMapSize4 = 5*stringMapsKeyIncSize + 1 + stringMapSize5 = 6*stringMapsKeyIncSize + 1 + stringMapSize6 = 256 + 2 + stringMapSize7 = 512 + 2 + stringMapSize8 = 1024 + 2 + stringMapSize9 = 2048 + 2 + stringMapSize10 = 4096 + 2 + + StringMapSize7a = 512 ) var ( - StringMapsSizes = [StringMapsNumSubMaps]int{1*stringMapsKeyIncSize + 1, - 2*stringMapsKeyIncSize + 1, - 3*stringMapsKeyIncSize + 1, - 4*stringMapsKeyIncSize + 1, - 5*stringMapsKeyIncSize + 1, - 6*stringMapsKeyIncSize + 1} + StringMapsSizes = [StringMapsNumSubMaps]int{ + stringMapSize0, + stringMapSize1, + stringMapSize2, + stringMapSize3, + stringMapSize4, + stringMapSize5, + stringMapSize6, + stringMapSize7, + stringMapSize8, + stringMapSize9, + stringMapSize10, + } ) type StringMapLists [StringMapsNumSubMaps][]map[[MaxStringMapsSize]byte]struct{} @@ -283,6 +309,35 @@ func ArgSelectorValue(v string) ([]byte, uint32) { return b, uint32(len(b)) } +func stringPaddedLen(s int) int { + paddedLen := s + + if s <= 6*stringMapsKeyIncSize { + if s%stringMapsKeyIncSize != 0 { + paddedLen = ((s / stringMapsKeyIncSize) + 1) * stringMapsKeyIncSize + } + return paddedLen + } + // The '-2' is to reduce the key size to the key string size - + // the key includes a string length that is 2 bytes long. + if s <= stringMapSize6-2 { + return stringMapSize6 - 2 + } + if kernels.MinKernelVersion("5.11") { + if s <= stringMapSize7-2 { + return stringMapSize7 - 2 + } + if s <= stringMapSize8-2 { + return stringMapSize8 - 2 + } + if s <= stringMapSize9-2 { + return stringMapSize9 - 2 + } + return stringMapSize10 - 2 + } + return StringMapSize7a - 2 +} + func ArgStringSelectorValue(v string, removeNul bool) ([MaxStringMapsSize]byte, int, error) { if removeNul { // Remove any trailing nul characters ("\0" or 0x00) @@ -293,23 +348,38 @@ func ArgStringSelectorValue(v string, removeNul bool) ([MaxStringMapsSize]byte, ret := [MaxStringMapsSize]byte{} b := []byte(v) s := len(b) - if s >= MaxStringMapsSize { - return ret, 0, fmt.Errorf("string is too long") + if kernels.MinKernelVersion("5.11") { + if s > MaxStringMapsSize-2 { + return ret, 0, fmt.Errorf("string is too long") + } + } else if kernels.MinKernelVersion("5.4") { + if s > StringMapSize7a-2 { + return ret, 0, fmt.Errorf("string is too long") + } + } else { + if s > stringMapSize5-1 { + return ret, 0, fmt.Errorf("string is too long") + } } if s == 0 { return ret, 0, fmt.Errorf("string is empty") } - paddedLen := s // Calculate length of string padded to next multiple of key increment size - if s%stringMapsKeyIncSize != 0 { - paddedLen = ((s / stringMapsKeyIncSize) + 1) * stringMapsKeyIncSize + paddedLen := stringPaddedLen(s) + + // Add real length to start and padding to end. + // u8 for first 6 maps and u16 little endian for latter maps. + if paddedLen <= 6*stringMapsKeyIncSize { + ret[0] = byte(s) + copy(ret[1:], b) + // Total length is padded string len + prefixed length byte. + return ret, paddedLen + 1, nil } - - // Add real length to start and padding to end - ret[0] = byte(s) - copy(ret[1:], b) - // Total length is padded string len + prefixed length byte. - return ret, paddedLen + 1, nil + ret[0] = byte(s % 0x100) + ret[1] = byte(s / 0x100) + copy(ret[2:], b) + // Total length is padded string len + prefixed length half word. + return ret, paddedLen + 2, nil } func ArgPostfixSelectorValue(v string, removeNul bool) ([]byte, uint32) { @@ -359,21 +429,26 @@ func (k *KernelSelectorState) createStringMaps() SelectorStringMaps { {}, {}, {}, + {}, + {}, + {}, + {}, + {}, } } -// In BPF, the string "equal" operator uses six hash maps, each stored within a matching array. +// In BPF, the string "equal" operator uses 11 hash maps, each stored within a matching array. // For each kprobe there could be multiple string match selectors. Each of these selectors has -// up to six hash maps (of different sizes) that hold potential matches. Each kprobe could have +// up to 11 hash maps (of different sizes) that hold potential matches. Each kprobe could have // multiple string match selectors (for different parameters, and/or different actions). Arrays // of hash maps can only hold hash maps of a singular type; e.g. an array of hash maps with a // key size of 25 can only hold hash maps that have that key size – it can't hold hash maps with // different key sizes. // -// As we have six different key sizes (to facilitate faster look ups for shorter strings), each -// selector can potentially have six hash maps to look up the string in. And as each kprobe +// As we have 11 different key sizes (to facilitate faster look ups for shorter strings), each +// selector can potentially have 11 hash maps to look up the string in. And as each kprobe // could have multiple string match selectors, each kprobe could potentially have multiple hash -// maps for each key size. Each kprobe therefore has six arrays of hash maps to hold these hash +// maps for each key size. Each kprobe therefore has 11 arrays of hash maps to hold these hash // maps. // // In golang we create a list of hash maps for each key size. Each of these is inserted into the diff --git a/pkg/sensors/base/base.go b/pkg/sensors/base/base.go index 441e5ac9121..d6afd579b54 100644 --- a/pkg/sensors/base/base.go +++ b/pkg/sensors/base/base.go @@ -140,6 +140,8 @@ func GetInitialSensor() *sensors.Sensor { func ExecObj() string { if kernels.EnableV61Progs() { return "bpf_execve_event_v61.o" + } else if kernels.MinKernelVersion("5.11") { + return "bpf_execve_event_v511.o" } else if kernels.EnableLargeProgs() { return "bpf_execve_event_v53.o" } diff --git a/pkg/sensors/tracing/args.go b/pkg/sensors/tracing/args.go index 1d345f50d26..847c46b0951 100644 --- a/pkg/sensors/tracing/args.go +++ b/pkg/sensors/tracing/args.go @@ -15,6 +15,7 @@ import ( api "github.com/cilium/tetragon/pkg/api/tracingapi" gt "github.com/cilium/tetragon/pkg/generictypes" "github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1" + "github.com/cilium/tetragon/pkg/kernels" "github.com/cilium/tetragon/pkg/logger" "github.com/cilium/tetragon/pkg/observer" "github.com/cilium/tetragon/pkg/reader/network" @@ -519,7 +520,13 @@ func parseString(r io.Reader) (string, error) { } // limit the size of the string to avoid huge memory allocation and OOM kill in case of issue - if size > maxStringSize { + maxStrLen := int32(maxStringSize) + if !kernels.MinKernelVersion("5.4") { + maxStrLen = maxStringSizeTiny + } else if !kernels.MinKernelVersion("5.11") { + maxStrLen = maxStringSizeSmall + } + if size > maxStrLen { return "", fmt.Errorf("string size too large: %d, max size is %d", size, maxStringSize) } stringBuffer := make([]byte, size) diff --git a/pkg/sensors/tracing/generickprobe.go b/pkg/sensors/tracing/generickprobe.go index 4964a6505c5..d2f5cd1b28f 100644 --- a/pkg/sensors/tracing/generickprobe.go +++ b/pkg/sensors/tracing/generickprobe.go @@ -21,7 +21,6 @@ import ( "github.com/cilium/tetragon/pkg/arch" "github.com/cilium/tetragon/pkg/bpf" "github.com/cilium/tetragon/pkg/btf" - cachedbtf "github.com/cilium/tetragon/pkg/btf" "github.com/cilium/tetragon/pkg/eventhandler" "github.com/cilium/tetragon/pkg/grpc/tracing" "github.com/cilium/tetragon/pkg/idtable" @@ -211,7 +210,12 @@ func filterMaps(load *program.Program, pinPath string, kprobeEntry *genericKprob maps = append(maps, addr6FilterMaps) var stringFilterMap [selectors.StringMapsNumSubMaps]*program.Map - for string_map_index := 0; string_map_index < selectors.StringMapsNumSubMaps; string_map_index++ { + numSubMaps := selectors.StringMapsNumSubMaps + if !kernels.MinKernelVersion("5.11") { + numSubMaps = selectors.StringMapsNumSubMapsSmall + } + + for string_map_index := 0; string_map_index < numSubMaps; string_map_index++ { stringFilterMap[string_map_index] = program.MapBuilderPin(fmt.Sprintf("string_maps_%d", string_map_index), sensors.PathJoin(pinPath, fmt.Sprintf("string_maps_%d", string_map_index)), load) if state != nil && !kernels.MinKernelVersion("5.9") { @@ -264,6 +268,9 @@ func createMultiKprobeSensor(sensorPath string, multiIDs []idtable.EntryID) ([]* if kernels.EnableV61Progs() { loadProgName = "bpf_multi_kprobe_v61.o" loadProgRetName = "bpf_multi_retkprobe_v61.o" + } else if kernels.MinKernelVersion("5.11") { + loadProgName = "bpf_multi_kprobe_v511.o" + loadProgRetName = "bpf_multi_retkprobe_v511.o" } pinPath := multiKprobePinPath(sensorPath) @@ -369,7 +376,7 @@ func preValidateKprobes(name string, kprobes []v1alpha1.KProbeSpec, lists []v1al } if len(option.Config.KMods) > 0 { - btfobj, err = cachedbtf.AddModulesToSpec(btfobj, option.Config.KMods) + btfobj, err = btf.AddModulesToSpec(btfobj, option.Config.KMods) if err != nil { return fmt.Errorf("adding modules to spec failed: %w", err) } @@ -1012,7 +1019,9 @@ func loadGenericKprobeSensor(bpfDir, mapDir string, load *program.Program, verbo var errParseStringSize = errors.New("error parsing string size from binary") // this is from bpf/process/types/basic.h 'MAX_STRING' -const maxStringSize = 1024 +const maxStringSize = 4096 +const maxStringSizeSmall = 510 +const maxStringSizeTiny = 144 func getUrl(url string) { // We fire and forget URLs, and we don't care if they hit or not. diff --git a/pkg/sensors/tracing/generictracepoint.go b/pkg/sensors/tracing/generictracepoint.go index 7a3c281b669..ca5c8c8aa95 100644 --- a/pkg/sensors/tracing/generictracepoint.go +++ b/pkg/sensors/tracing/generictracepoint.go @@ -366,6 +366,8 @@ func createGenericTracepointSensor( progName := "bpf_generic_tracepoint.o" if kernels.EnableV61Progs() { progName = "bpf_generic_tracepoint_v61.o" + } else if kernels.MinKernelVersion("5.11") { + progName = "bpf_generic_tracepoint_v511.o" } else if kernels.EnableLargeProgs() { progName = "bpf_generic_tracepoint_v53.o" } @@ -428,7 +430,11 @@ func createGenericTracepointSensor( } maps = append(maps, addr6FilterMaps) - for string_map_index := 0; string_map_index < selectors.StringMapsNumSubMaps; string_map_index++ { + numSubMaps := selectors.StringMapsNumSubMaps + if !kernels.MinKernelVersion("5.11") { + numSubMaps = selectors.StringMapsNumSubMapsSmall + } + for string_map_index := 0; string_map_index < numSubMaps; string_map_index++ { stringFilterMap := program.MapBuilderPin(fmt.Sprintf("string_maps_%d", string_map_index), sensors.PathJoin(pinPath, fmt.Sprintf("string_maps_%d", string_map_index)), prog0) if !kernels.MinKernelVersion("5.9") { diff --git a/pkg/sensors/tracing/kprobe_test.go b/pkg/sensors/tracing/kprobe_test.go index 0779e8848de..cce5824ddcd 100644 --- a/pkg/sensors/tracing/kprobe_test.go +++ b/pkg/sensors/tracing/kprobe_test.go @@ -24,7 +24,6 @@ import ( "github.com/cilium/ebpf" "github.com/cilium/ebpf/asm" "github.com/cilium/tetragon/api/v1/tetragon" - "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker" ec "github.com/cilium/tetragon/api/v1/tetragon/codegen/eventchecker" "github.com/cilium/tetragon/pkg/arch" "github.com/cilium/tetragon/pkg/bpf" @@ -902,6 +901,129 @@ func TestKprobeStringMatchHash5Max(t *testing.T) { testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) } +func TestKprobeStringMatchHash6Min(t *testing.T) { + if !kernels.MinKernelVersion("5.4") { + t.Skip("Test requires kernel 5.4+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 145 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash6Max(t *testing.T) { + if !kernels.MinKernelVersion("5.4") { + t.Skip("Test requires kernel 5.4+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 256 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash7Min(t *testing.T) { + if !kernels.MinKernelVersion("5.4") { + t.Skip("Test requires kernel 5.4+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 257 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash7Max(t *testing.T) { + if !kernels.MinKernelVersion("5.4") { + t.Skip("Test requires kernel 5.4+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 512 + if !kernels.MinKernelVersion("5.11") { + pathLen = 510 + } + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash8Min(t *testing.T) { + if !kernels.MinKernelVersion("5.11") { + t.Skip("Test requires kernel 5.11+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 513 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash8Max(t *testing.T) { + if !kernels.MinKernelVersion("5.11") { + t.Skip("Test requires kernel 5.11+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 1024 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash9Min(t *testing.T) { + if !kernels.MinKernelVersion("5.11") { + t.Skip("Test requires kernel 5.11+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 1025 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash9Max(t *testing.T) { + if !kernels.MinKernelVersion("5.11") { + t.Skip("Test requires kernel 5.11+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 2048 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash10Min(t *testing.T) { + if !kernels.MinKernelVersion("5.11") { + t.Skip("Test requires kernel 5.11+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 2049 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + +func TestKprobeStringMatchHash10Max(t *testing.T) { + if !kernels.MinKernelVersion("5.11") { + t.Skip("Test requires kernel 5.11+") + } + pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) + pathLen := 4096 + fileLen := len("/testfile") + dir := strings.Repeat("A", pathLen-fileLen) + readHook := testKprobeStringMatchHook(pidStr, dir) + testKprobeStringMatch(t, readHook, getOpenatChecker(t, dir), dir) +} + func testKprobeObjectMultiValueOpenHook(pidStr string, path string) string { return ` apiVersion: cilium.io/v1alpha1 @@ -1346,7 +1468,7 @@ func testKprobeObjectFilterModeOpenHook(pidStr string, mode int, valueFmt string func testKprobeObjectFilterModeOpenMatch(t *testing.T, valueFmt string, modeCreate, modeCheck int) { pidStr := strconv.Itoa(int(observertesthelper.GetMyPid())) - checker := func(dir string) *eventchecker.UnorderedEventChecker { + checker := func(dir string) *ec.UnorderedEventChecker { return ec.NewUnorderedEventChecker( ec.NewProcessKprobeChecker(""). WithFunctionName(sm.Full(arch.AddSyscallPrefixTestHelper(t, "sys_openat"))). @@ -1501,7 +1623,7 @@ func TestKprobeObjectFilterReturnValueGTOk(t *testing.T) { path := dir + "/testfile" openHook := testKprobeObjectFilterReturnValueGTHook(pidStr, path) - checker := func(dir string) *eventchecker.UnorderedEventChecker { + checker := func(dir string) *ec.UnorderedEventChecker { return ec.NewUnorderedEventChecker( ec.NewProcessKprobeChecker(""). WithFunctionName(sm.Full(arch.AddSyscallPrefixTestHelper(t, "sys_openat"))). @@ -1551,7 +1673,7 @@ func TestKprobeObjectFilterReturnValueLTOk(t *testing.T) { path := dir + "/testfile" openHook := testKprobeObjectFilterReturnValueLTHook(pidStr, path) - checker := func(dir string) *eventchecker.UnorderedEventChecker { + checker := func(dir string) *ec.UnorderedEventChecker { return ec.NewUnorderedEventChecker( ec.NewProcessKprobeChecker(""). WithFunctionName(sm.Full(arch.AddSyscallPrefixTestHelper(t, "sys_openat"))). @@ -4238,7 +4360,7 @@ spec: t.Logf("got error (as expected): %s", err) } -func testMaxData(t *testing.T, data []byte, checker *eventchecker.UnorderedEventChecker, configHook string, fd int) { +func testMaxData(t *testing.T, data []byte, checker *ec.UnorderedEventChecker, configHook string, fd int) { var doneWG, readyWG sync.WaitGroup defer doneWG.Wait() diff --git a/pkg/sensors/tracing/selectors.go b/pkg/sensors/tracing/selectors.go index 43c6cc0a23d..cdf4992c4e9 100644 --- a/pkg/sensors/tracing/selectors.go +++ b/pkg/sensors/tracing/selectors.go @@ -17,7 +17,7 @@ import ( func selectorsMaploads(ks *selectors.KernelSelectorState, pinPathPrefix string, index uint32) []*program.MapLoad { selBuff := ks.Buffer() - return []*program.MapLoad{ + maps := []*program.MapLoad{ { Index: index, Name: "filter_map", @@ -54,6 +54,18 @@ func selectorsMaploads(ks *selectors.KernelSelectorState, pinPathPrefix string, Load: func(outerMap *ebpf.Map, index uint32) error { return populateMatchBinariesPathsMaps(ks, pinPathPrefix, outerMap) }, + }, { + Index: 0, + Name: "string_prefix_maps", + Load: func(outerMap *ebpf.Map, index uint32) error { + return populateStringPrefixFilterMaps(ks, pinPathPrefix, outerMap) + }, + }, { + Index: 0, + Name: "string_postfix_maps", + Load: func(outerMap *ebpf.Map, index uint32) error { + return populateStringPostfixFilterMaps(ks, pinPathPrefix, outerMap) + }, }, { Index: 0, Name: "string_maps_0", @@ -92,18 +104,42 @@ func selectorsMaploads(ks *selectors.KernelSelectorState, pinPathPrefix string, }, }, { Index: 0, - Name: "string_prefix_maps", + Name: "string_maps_6", Load: func(outerMap *ebpf.Map, index uint32) error { - return populateStringPrefixFilterMaps(ks, pinPathPrefix, outerMap) + return populateStringFilterMaps(ks, pinPathPrefix, outerMap, 6) }, }, { Index: 0, - Name: "string_postfix_maps", + Name: "string_maps_7", Load: func(outerMap *ebpf.Map, index uint32) error { - return populateStringPostfixFilterMaps(ks, pinPathPrefix, outerMap) + return populateStringFilterMaps(ks, pinPathPrefix, outerMap, 7) }, }, } + if kernels.MinKernelVersion("5.11") { + maps = append(maps, []*program.MapLoad{ + { + Index: 0, + Name: "string_maps_8", + Load: func(outerMap *ebpf.Map, index uint32) error { + return populateStringFilterMaps(ks, pinPathPrefix, outerMap, 8) + }, + }, { + Index: 0, + Name: "string_maps_9", + Load: func(outerMap *ebpf.Map, index uint32) error { + return populateStringFilterMaps(ks, pinPathPrefix, outerMap, 9) + }, + }, { + Index: 0, + Name: "string_maps_10", + Load: func(outerMap *ebpf.Map, index uint32) error { + return populateStringFilterMaps(ks, pinPathPrefix, outerMap, 10) + }, + }, + }...) + } + return maps } func populateArgFilterMaps( @@ -315,11 +351,15 @@ func populateStringFilterMap( innerData map[[selectors.MaxStringMapsSize]byte]struct{}, maxEntries uint32, ) error { + mapKeySize := selectors.StringMapsSizes[subMap] + if subMap == 7 && !kernels.MinKernelVersion("5.11") { + mapKeySize = selectors.StringMapSize7a + } innerName := fmt.Sprintf("string_maps_%d_%d", subMap, innerID) innerSpec := &ebpf.MapSpec{ Name: innerName, Type: ebpf.Hash, - KeySize: uint32(selectors.StringMapsSizes[subMap]), + KeySize: uint32(mapKeySize), ValueSize: uint32(1), MaxEntries: maxEntries, } @@ -333,7 +373,7 @@ func populateStringFilterMap( one := uint8(1) for rawVal := range innerData { - val := rawVal[:selectors.StringMapsSizes[subMap]] + val := rawVal[:mapKeySize] err := innerMap.Update(val, one, 0) if err != nil { return fmt.Errorf("failed to insert value into %s: %w", innerName, err)