Skip to content

Commit c8f96f3

Browse files
Add effective and permitted caps to fork and exec events. (#172)
* Add effective and permitted caps * Fix formatting * Add caps dev package * Fix copy-paste error * Test the correct value * Add docs about kernel_cap_t changes
1 parent bd875dd commit c8f96f3

File tree

9 files changed

+94
-2
lines changed

9 files changed

+94
-2
lines changed

.github/workflows/multikernel-tester.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
sudo apt-get install -y --no-install-recommends \
3232
gcc-aarch64-linux-gnu \
3333
libc6-dev-arm64-cross \
34+
libcap-dev \
3435
parallel \
3536
qemu-system-x86 \
3637
qemu-system-arm \

GPL/Events/EbpfEventProto.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ struct ebpf_cred_info {
9494
uint32_t egid; // Effective group ID
9595
uint32_t suid; // Saved user ID
9696
uint32_t sgid; // Saved group ID
97+
uint64_t cap_permitted;
98+
uint64_t cap_effective;
9799
} __attribute__((packed));
98100

99101
struct ebpf_tty_winsize {
@@ -150,6 +152,7 @@ struct ebpf_process_fork_event {
150152
struct ebpf_event_header hdr;
151153
struct ebpf_pid_info parent_pids;
152154
struct ebpf_pid_info child_pids;
155+
struct ebpf_cred_info creds;
153156

154157
// Variable length fields: pids_ss_cgroup_path
155158
struct ebpf_varlen_fields_start vl_fields;

GPL/Events/Helpers.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,49 @@ static void ebpf_cred_info__fill(struct ebpf_cred_info *ci, const struct task_st
235235
ci->rgid = BPF_CORE_READ(task, cred, gid.val);
236236
ci->egid = BPF_CORE_READ(task, cred, egid.val);
237237
ci->sgid = BPF_CORE_READ(task, cred, sgid.val);
238+
239+
// This check is to determine when the kernel_cap_t definition changed.
240+
//
241+
// Previously it was:
242+
// typedef struct kernel_cap_struct {
243+
// __u32 cap[_KERNEL_CAPABILITY_U32S];
244+
// } kernel_cap_t;
245+
//
246+
// Currently it is:
247+
// typedef struct { u64 val; } kernel_cap_t;
248+
//
249+
// See https://github.com/torvalds/linux/commit/f122a08b197d076ccf136c73fae0146875812a88
250+
//
251+
if (bpf_core_field_exists(task->cred->cap_permitted.cap)) {
252+
kernel_cap_t dest;
253+
254+
dest.cap[0] = 0;
255+
dest.cap[1] = 0;
256+
dest = BPF_CORE_READ(task, cred, cap_permitted);
257+
ci->cap_permitted = (((u64)dest.cap[1]) << 32) + dest.cap[0];
258+
259+
dest.cap[0] = 0;
260+
dest.cap[1] = 0;
261+
dest = BPF_CORE_READ(task, cred, cap_effective);
262+
ci->cap_effective = (((u64)dest.cap[1]) << 32) + dest.cap[0];
263+
} else {
264+
const struct cred *cred = BPF_CORE_READ(task, cred);
265+
const void *cap = NULL;
266+
267+
struct new_kernel_cap_struct {
268+
u64 val;
269+
} dest;
270+
271+
dest.val = 0;
272+
cap = &cred->cap_permitted;
273+
bpf_core_read(&dest, bpf_core_type_size(struct new_kernel_cap_struct), cap);
274+
ci->cap_permitted = dest.val;
275+
276+
dest.val = 0;
277+
cap = &cred->cap_effective;
278+
bpf_core_read(&dest, bpf_core_type_size(struct new_kernel_cap_struct), cap);
279+
ci->cap_effective = dest.val;
280+
}
238281
}
239282

240283
static bool is_kernel_thread(const struct task_struct *task)

GPL/Events/Process/Probe.bpf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ int BPF_PROG(sched_process_fork, const struct task_struct *parent, const struct
4949
event->hdr.ts = bpf_ktime_get_ns();
5050
ebpf_pid_info__fill(&event->parent_pids, parent);
5151
ebpf_pid_info__fill(&event->child_pids, child);
52+
ebpf_cred_info__fill(&event->creds, parent);
5253

5354
// Variable length fields
5455
ebpf_vl_fields__init(&event->vl_fields);

non-GPL/Events/EventsTrace/EventsTrace.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ static void out_cred_info(const char *name, struct ebpf_cred_info *cred_info)
295295
out_int("suid", cred_info->suid);
296296
out_comma();
297297
out_int("sgid", cred_info->sgid);
298+
out_comma();
299+
printf("\"cap_permitted\": \"%lu\"", cred_info->cap_permitted);
300+
out_comma();
301+
printf("\"cap_effective\": \"%lu\"", cred_info->cap_effective);
298302
out_object_end();
299303
}
300304

@@ -429,6 +433,9 @@ static void out_process_fork(struct ebpf_process_fork_event *evt)
429433
out_comma();
430434

431435
out_pid_info("child_pids", &evt->child_pids);
436+
out_comma();
437+
438+
out_cred_info("creds", &evt->creds);
432439

433440
struct ebpf_varlen_field *field;
434441
FOR_EACH_VARLEN_FIELD(evt->vl_fields, field)

testing/test_bins/common.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <stdio.h>
11+
#include <sys/capability.h>
1112
#include <sys/types.h>
1213
#include <syscall.h>
1314
#include <unistd.h>
@@ -29,6 +30,18 @@ pid_t gettid()
2930

3031
void gen_pid_info_json(char *buf, size_t size)
3132
{
32-
snprintf(buf, size, "{\"tid\": %d, \"ppid\": %d, \"tgid\": %d, \"sid\": %d, \"pgid\": %d}",
33-
gettid(), getppid(), getpid(), getsid(0), getpgid(0));
33+
struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
34+
struct __user_cap_data_struct data[2] = {{0}};
35+
uint64_t cap_permitted = 0;
36+
uint64_t cap_effective = 0;
37+
38+
(void)capget(&hdr, data);
39+
cap_permitted = ((uint64_t)data[1].permitted << 32) + (uint64_t)data[0].permitted;
40+
cap_effective = ((uint64_t)data[1].effective << 32) + (uint64_t)data[0].effective;
41+
42+
snprintf(buf, size,
43+
"{\"tid\": %d, \"ppid\": %d, \"tgid\": %d, \"sid\": %d, \"pgid\": %d, "
44+
"\"cap_permitted\": \"%lu\", \"cap_effective\":\"%lu\"}",
45+
(pid_t)syscall(SYS_gettid), getppid(), getpid(), getsid(0), getpgid(0), cap_permitted,
46+
cap_effective);
3447
}

testing/test_bins/fork_exec.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@
1717
int main()
1818
{
1919
pid_t pid;
20+
struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
21+
struct __user_cap_data_struct data[2] = {{0}};
22+
23+
data[0].permitted = 0xffffffff;
24+
data[1].permitted = 0;
25+
data[0].effective = 0xf0f0f0f0;
26+
data[1].effective = 0;
27+
CHECK(capset(&hdr, &data[0]), -1);
28+
2029
CHECK(pid = fork(), -1);
2130

2231
if (pid != 0) {

testing/testrunner/tests.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ func TestForkExec(et *EventsTraceInstance) {
130130
}
131131
}
132132

133+
AssertUint64Equal(uint64(forkEvent.Creds.CapPermitted), uint64(0x00000000ffffffff))
134+
AssertUint64Equal(uint64(forkEvent.Creds.CapEffective), uint64(0x00000000f0f0f0f0))
135+
AssertUint64Equal(uint64(execEvent.Creds.CapPermitted), uint64(0x000001ffffffffff))
136+
AssertUint64Equal(uint64(execEvent.Creds.CapEffective), uint64(0x000001ffffffffff))
133137
AssertStringsEqual(execEvent.FileName, "./do_nothing")
134138
AssertStringsEqual(execEvent.Argv[0], "./do_nothing")
135139
AssertStringsEqual(execEvent.Env[0], "TEST_ENV_KEY1=TEST_ENV_VAL1")

testing/testrunner/utils.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ type TestPidInfo struct {
3131
Ppid int64 `json:"ppid"`
3232
Pgid int64 `json:"pgid"`
3333
Sid int64 `json:"sid"`
34+
CapPermitted uint64 `json:"cap_permitted,string"`
35+
CapEffective uint64 `json:"cap_effective,string"`
3436
}
3537

3638
// Definitions of types printed by EventsTrace for conversion from JSON
@@ -57,6 +59,8 @@ type CredInfo struct {
5759
Egid int64 `json:"egid"`
5860
Suid int64 `json:"suid"`
5961
Sgid int64 `json:"sgid"`
62+
CapPermitted uint64 `json:"cap_permitted,string"`
63+
CapEffective uint64 `json:"cap_effective,string"`
6064
}
6165

6266
type TtyInfo struct {
@@ -77,6 +81,7 @@ type NetInfo struct {
7781
type ProcessForkEvent struct {
7882
ParentPids PidInfo `json:"parent_pids"`
7983
ChildPids PidInfo `json:"child_pids"`
84+
Creds CredInfo `json:"creds"`
8085
}
8186

8287
type ProcessExecEvent struct {
@@ -223,6 +228,12 @@ func AssertInt64NotEqual(a, b int64) {
223228
}
224229
}
225230

231+
func AssertUint64Equal(a, b uint64) {
232+
if a != b {
233+
TestFail(fmt.Sprintf("Test assertion failed 0x%016x != 0x%016x", a, b))
234+
}
235+
}
236+
226237
func PrintBPFDebugOutput() {
227238
file, err := os.Open("/sys/kernel/debug/tracing/trace")
228239
if err != nil {

0 commit comments

Comments
 (0)