Skip to content

Commit f08e686

Browse files
chethanahyonghong-song
authored andcommitted
Support libbpf-tools based capable tool
Based on capable(8) in BCC, support capable tool for libbpf-tools. Also support stack trace, PID filtering, cgroup filtering and verdict. Signed-off-by: Chethan Suresh <[email protected]> Reviewed-by: Kenta Tada <[email protected]> Signed-off-by: Kenta Tada <[email protected]>
1 parent 691ed59 commit f08e686

File tree

5 files changed

+611
-0
lines changed

5 files changed

+611
-0
lines changed

libbpf-tools/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/btrfsdist
1212
/btrfsslower
1313
/cachestat
14+
/capable
1415
/cpudist
1516
/cpufreq
1617
/drsnoop

libbpf-tools/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ APPS = \
4444
biotop \
4545
bitesize \
4646
cachestat \
47+
capable \
4748
cpudist \
4849
cpufreq \
4950
drsnoop \

libbpf-tools/capable.bpf.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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")
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")
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";

0 commit comments

Comments
 (0)