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