xref: /linux/tools/testing/selftests/bpf/progs/dmabuf_iter.c (revision 0ce92d548b44649a8de706f9bb9e74a4ed2f18a7)
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