| // SPDX-License-Identifier: GPL-2.0 |
| /* Copyright (c) 2024 Google */ |
| #include <vmlinux.h> |
| #include <bpf/bpf_helpers.h> |
| #include <bpf/bpf_tracing.h> |
| #include "bpf_experimental.h" |
| |
| char _license[] SEC("license") = "GPL"; |
| |
| #define SLAB_NAME_MAX 32 |
| |
| struct kmem_cache_result { |
| char name[SLAB_NAME_MAX]; |
| long obj_size; |
| }; |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_HASH); |
| __uint(key_size, sizeof(void *)); |
| __uint(value_size, SLAB_NAME_MAX); |
| __uint(max_entries, 1); |
| } slab_hash SEC(".maps"); |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_ARRAY); |
| __uint(key_size, sizeof(int)); |
| __uint(value_size, sizeof(struct kmem_cache_result)); |
| __uint(max_entries, 1024); |
| } slab_result SEC(".maps"); |
| |
| extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym; |
| |
| /* Result, will be checked by userspace */ |
| int task_struct_found; |
| int kmem_cache_seen; |
| int open_coded_seen; |
| |
| SEC("iter/kmem_cache") |
| int slab_info_collector(struct bpf_iter__kmem_cache *ctx) |
| { |
| struct seq_file *seq = ctx->meta->seq; |
| struct kmem_cache *s = ctx->s; |
| struct kmem_cache_result *r; |
| int idx; |
| |
| if (s) { |
| /* To make sure if the slab_iter implements the seq interface |
| * properly and it's also useful for debugging. |
| */ |
| BPF_SEQ_PRINTF(seq, "%s: %u\n", s->name, s->size); |
| |
| idx = kmem_cache_seen; |
| r = bpf_map_lookup_elem(&slab_result, &idx); |
| if (r == NULL) |
| return 0; |
| |
| kmem_cache_seen++; |
| |
| /* Save name and size to match /proc/slabinfo */ |
| bpf_probe_read_kernel_str(r->name, sizeof(r->name), s->name); |
| r->obj_size = s->size; |
| |
| if (!bpf_strncmp(r->name, 11, "task_struct")) |
| bpf_map_update_elem(&slab_hash, &s, r->name, BPF_NOEXIST); |
| } |
| |
| return 0; |
| } |
| |
| SEC("raw_tp/bpf_test_finish") |
| int BPF_PROG(check_task_struct) |
| { |
| u64 curr = bpf_get_current_task(); |
| struct kmem_cache *s; |
| char *name; |
| |
| s = bpf_get_kmem_cache(curr); |
| if (s == NULL) { |
| task_struct_found = -1; |
| return 0; |
| } |
| name = bpf_map_lookup_elem(&slab_hash, &s); |
| if (name && !bpf_strncmp(name, 11, "task_struct")) |
| task_struct_found = 1; |
| else |
| task_struct_found = -2; |
| return 0; |
| } |
| |
| SEC("syscall") |
| int open_coded_iter(const void *ctx) |
| { |
| struct kmem_cache *s; |
| |
| bpf_for_each(kmem_cache, s) { |
| struct kmem_cache_result *r; |
| |
| r = bpf_map_lookup_elem(&slab_result, &open_coded_seen); |
| if (!r) |
| break; |
| |
| if (r->obj_size != s->size) |
| break; |
| |
| open_coded_seen++; |
| } |
| return 0; |
| } |