1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2025 Google LLC */ 3 #include <vmlinux.h> 4 #include <bpf/bpf_core_read.h> 5 #include <bpf/bpf_helpers.h> 6 7 /* From uapi/linux/dma-buf.h */ 8 #define DMA_BUF_NAME_LEN 32 9 10 char _license[] SEC("license") = "GPL"; 11 12 struct { 13 __uint(type, BPF_MAP_TYPE_HASH); 14 __uint(key_size, DMA_BUF_NAME_LEN); 15 __type(value, bool); 16 __uint(max_entries, 5); 17 } testbuf_hash SEC(".maps"); 18 19 /* 20 * Fields output by this iterator are delimited by newlines. Convert any 21 * newlines in user-provided printed strings to spaces. 22 */ 23 static void sanitize_string(char *src, size_t size) 24 { 25 for (char *c = src; (size_t)(c - src) < size && *c; ++c) 26 if (*c == '\n') 27 *c = ' '; 28 } 29 30 SEC("iter/dmabuf") 31 int dmabuf_collector(struct bpf_iter__dmabuf *ctx) 32 { 33 const struct dma_buf *dmabuf = ctx->dmabuf; 34 struct seq_file *seq = ctx->meta->seq; 35 unsigned long inode = 0; 36 size_t size; 37 const char *pname, *exporter; 38 char name[DMA_BUF_NAME_LEN] = {'\0'}; 39 40 if (!dmabuf) 41 return 0; 42 43 if (BPF_CORE_READ_INTO(&inode, dmabuf, file, f_inode, i_ino) || 44 bpf_core_read(&size, sizeof(size), &dmabuf->size) || 45 bpf_core_read(&pname, sizeof(pname), &dmabuf->name) || 46 bpf_core_read(&exporter, sizeof(exporter), &dmabuf->exp_name)) 47 return 1; 48 49 /* Buffers are not required to be named */ 50 if (pname) { 51 if (bpf_probe_read_kernel(name, sizeof(name), pname)) 52 return 1; 53 54 /* Name strings can be provided by userspace */ 55 sanitize_string(name, sizeof(name)); 56 } 57 58 BPF_SEQ_PRINTF(seq, "%lu\n%llu\n%s\n%s\n", inode, size, name, exporter); 59 return 0; 60 } 61 62 SEC("syscall") 63 int iter_dmabuf_for_each(const void *ctx) 64 { 65 struct dma_buf *d; 66 67 bpf_for_each(dmabuf, d) { 68 char name[DMA_BUF_NAME_LEN]; 69 const char *pname; 70 bool *found; 71 long len; 72 int i; 73 74 if (bpf_core_read(&pname, sizeof(pname), &d->name)) 75 return 1; 76 77 /* Buffers are not required to be named */ 78 if (!pname) 79 continue; 80 81 len = bpf_probe_read_kernel_str(name, sizeof(name), pname); 82 if (len < 0) 83 return 1; 84 85 /* 86 * The entire name buffer is used as a map key. 87 * Zeroize any uninitialized trailing bytes after the NUL. 88 */ 89 bpf_for(i, len, DMA_BUF_NAME_LEN) 90 name[i] = 0; 91 92 found = bpf_map_lookup_elem(&testbuf_hash, name); 93 if (found) { 94 bool t = true; 95 96 bpf_map_update_elem(&testbuf_hash, name, &t, BPF_EXIST); 97 } 98 } 99 100 return 0; 101 } 102