1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024 Google */ 3 #include <vmlinux.h> 4 #include <bpf/bpf_helpers.h> 5 #include <bpf/bpf_tracing.h> 6 #include "bpf_experimental.h" 7 8 char _license[] SEC("license") = "GPL"; 9 10 #define SLAB_NAME_MAX 32 11 12 struct kmem_cache_result { 13 char name[SLAB_NAME_MAX]; 14 long obj_size; 15 }; 16 17 struct { 18 __uint(type, BPF_MAP_TYPE_HASH); 19 __uint(key_size, sizeof(void *)); 20 __uint(value_size, SLAB_NAME_MAX); 21 __uint(max_entries, 1); 22 } slab_hash SEC(".maps"); 23 24 struct { 25 __uint(type, BPF_MAP_TYPE_ARRAY); 26 __uint(key_size, sizeof(int)); 27 __uint(value_size, sizeof(struct kmem_cache_result)); 28 __uint(max_entries, 1024); 29 } slab_result SEC(".maps"); 30 31 extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym; 32 33 /* Result, will be checked by userspace */ 34 int task_struct_found; 35 int kmem_cache_seen; 36 int open_coded_seen; 37 38 SEC("iter/kmem_cache") 39 int slab_info_collector(struct bpf_iter__kmem_cache *ctx) 40 { 41 struct seq_file *seq = ctx->meta->seq; 42 struct kmem_cache *s = ctx->s; 43 struct kmem_cache_result *r; 44 int idx; 45 46 if (s) { 47 /* To make sure if the slab_iter implements the seq interface 48 * properly and it's also useful for debugging. 49 */ 50 BPF_SEQ_PRINTF(seq, "%s: %u\n", s->name, s->size); 51 52 idx = kmem_cache_seen; 53 r = bpf_map_lookup_elem(&slab_result, &idx); 54 if (r == NULL) 55 return 0; 56 57 kmem_cache_seen++; 58 59 /* Save name and size to match /proc/slabinfo */ 60 bpf_probe_read_kernel_str(r->name, sizeof(r->name), s->name); 61 r->obj_size = s->size; 62 63 if (!bpf_strncmp(r->name, 11, "task_struct")) 64 bpf_map_update_elem(&slab_hash, &s, r->name, BPF_NOEXIST); 65 } 66 67 return 0; 68 } 69 70 SEC("raw_tp/bpf_test_finish") 71 int BPF_PROG(check_task_struct) 72 { 73 u64 curr = bpf_get_current_task(); 74 struct kmem_cache *s; 75 char *name; 76 77 s = bpf_get_kmem_cache(curr); 78 if (s == NULL) { 79 task_struct_found = -1; 80 return 0; 81 } 82 name = bpf_map_lookup_elem(&slab_hash, &s); 83 if (name && !bpf_strncmp(name, 11, "task_struct")) 84 task_struct_found = 1; 85 else 86 task_struct_found = -2; 87 return 0; 88 } 89 90 SEC("syscall") 91 int open_coded_iter(const void *ctx) 92 { 93 struct kmem_cache *s; 94 95 bpf_for_each(kmem_cache, s) { 96 struct kmem_cache_result *r; 97 98 r = bpf_map_lookup_elem(&slab_result, &open_coded_seen); 99 if (!r) 100 break; 101 102 if (r->obj_size != s->size) 103 break; 104 105 open_coded_seen++; 106 } 107 return 0; 108 } 109