// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2024 Google */ #include #include #include #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; }