xref: /aosp_15_r20/external/bcc/libbpf-tools/capable.bpf.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Unique filtering based on
4 // https://github.com/libbpf/libbpf-rs/tree/master/examples/capable
5 //
6 // Copyright 2022 Sony Group Corporation
7 
8 #include <vmlinux.h>
9 #include <bpf/bpf_helpers.h>
10 #include <bpf/bpf_tracing.h>
11 #include "capable.h"
12 
13 #define MAX_ENTRIES	10240
14 
15 extern int LINUX_KERNEL_VERSION __kconfig;
16 
17 const volatile pid_t my_pid = -1;
18 const volatile enum uniqueness unique_type = UNQ_OFF;
19 const volatile bool kernel_stack = false;
20 const volatile bool user_stack = false;
21 const volatile bool filter_cg = false;
22 const volatile pid_t targ_pid = -1;
23 
24 struct args_t {
25 	int cap;
26 	int cap_opt;
27 };
28 
29 struct unique_key {
30 	int cap;
31 	u32 tgid;
32 	u64 cgroupid;
33 };
34 
35 struct {
36 	__uint(type, BPF_MAP_TYPE_HASH);
37 	__uint(max_entries, 10240);
38 	__type(key, u64);
39 	__type(value, struct args_t);
40 } start SEC(".maps");
41 
42 struct {
43 	__uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
44 	__type(key, u32);
45 	__type(value, u32);
46 	__uint(max_entries, 1);
47 } cgroup_map SEC(".maps");
48 
49 struct {
50 	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
51 	__uint(key_size, sizeof(__u32));
52 	__uint(value_size, sizeof(__u32));
53 } events SEC(".maps");
54 
55 struct {
56 	__uint(type, BPF_MAP_TYPE_STACK_TRACE);
57 	__uint(key_size, sizeof(u32));
58 } stackmap SEC(".maps");
59 
60 struct {
61 	__uint(type, BPF_MAP_TYPE_HASH);
62 	__type(key, struct key_t);
63 	__type(value, struct cap_event);
64 	__uint(max_entries, MAX_ENTRIES);
65 } info SEC(".maps");
66 
67 struct {
68 	__uint(type, BPF_MAP_TYPE_HASH);
69 	__uint(max_entries, 10240);
70 	__type(key, struct unique_key);
71 	__type(value, u64);
72 } seen SEC(".maps");
73 
74 SEC("kprobe/cap_capable")
BPF_KPROBE(kprobe__cap_capable_entry,const struct cred * cred,struct user_namespace * targ_ns,int cap,int cap_opt)75 int BPF_KPROBE(kprobe__cap_capable_entry, const struct cred *cred, struct user_namespace *targ_ns, int cap, int cap_opt)
76 {
77 	__u32 pid;
78 	__u64 pid_tgid;
79 
80 	if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
81 		return 0;
82 
83 	pid_tgid = bpf_get_current_pid_tgid();
84 	pid = pid_tgid >> 32;
85 
86 	if (pid == my_pid)
87 		return 0;
88 
89 	if (targ_pid != -1 && targ_pid != pid)
90 		return 0;
91 
92 	struct args_t args = {};
93 	args.cap = cap;
94 	args.cap_opt = cap_opt;
95 	bpf_map_update_elem(&start, &pid_tgid, &args, 0);
96 
97 	return 0;
98 }
99 
100 SEC("kretprobe/cap_capable")
BPF_KRETPROBE(kprobe__cap_capable_exit)101 int BPF_KRETPROBE(kprobe__cap_capable_exit)
102 {
103 	__u64 pid_tgid;
104 	struct args_t *ap;
105 	struct key_t i_key;
106 
107 	pid_tgid = bpf_get_current_pid_tgid();
108 	ap = bpf_map_lookup_elem(&start, &pid_tgid);
109 	if (!ap)
110 		return 0;   /* missed entry */
111 
112 	bpf_map_delete_elem(&start, &pid_tgid);
113 
114 	struct cap_event event = {};
115 	event.pid = pid_tgid >> 32;
116 	event.tgid = pid_tgid;
117 	event.cap = ap->cap;
118 	event.uid = bpf_get_current_uid_gid();
119 	bpf_get_current_comm(&event.task, sizeof(event.task));
120 	event.ret = PT_REGS_RC(ctx);
121 
122 	if (LINUX_KERNEL_VERSION >= KERNEL_VERSION(5, 1, 0)) {
123 		/* @opts: Bitmask of options defined in include/linux/security.h */
124 		event.audit = (ap->cap_opt & 0b10) == 0;
125 		event.insetid = (ap->cap_opt & 0b100) != 0;
126 	} else {
127 		event.audit = ap->cap_opt;
128 		event.insetid = -1;
129 	}
130 
131 	if (unique_type) {
132 		struct unique_key key = {.cap = ap->cap};
133 		if (unique_type == UNQ_CGROUP)
134 			key.cgroupid = bpf_get_current_cgroup_id();
135 		else
136 			key.tgid = pid_tgid;
137 
138 		if (bpf_map_lookup_elem(&seen, &key) != NULL)
139 			return 0;
140 
141 		u64 zero = 0;
142 		bpf_map_update_elem(&seen, &key, &zero, 0);
143 	}
144 
145 	if (kernel_stack || user_stack) {
146 		i_key.pid = pid_tgid >> 32;
147 		i_key.tgid = pid_tgid;
148 
149 		i_key.kern_stack_id = i_key.user_stack_id = -1;
150 		if (user_stack)
151 			i_key.user_stack_id = bpf_get_stackid(ctx, &stackmap, BPF_F_USER_STACK);
152 		if (kernel_stack)
153 			i_key.kern_stack_id = bpf_get_stackid(ctx, &stackmap, 0);
154 
155 		bpf_map_update_elem(&info, &i_key, &event, BPF_NOEXIST);
156 	}
157 	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
158 
159 	return 0;
160 }
161 
162 char LICENSE[] SEC("license") = "GPL";
163