Skip to content

Commit

Permalink
Add effective and permitted caps to fork and exec events. (#172)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
nicholasberlin authored Aug 29, 2023
1 parent bd875dd commit c8f96f3
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/workflows/multikernel-tester.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
sudo apt-get install -y --no-install-recommends \
gcc-aarch64-linux-gnu \
libc6-dev-arm64-cross \
libcap-dev \
parallel \
qemu-system-x86 \
qemu-system-arm \
Expand Down
3 changes: 3 additions & 0 deletions GPL/Events/EbpfEventProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ struct ebpf_cred_info {
uint32_t egid; // Effective group ID
uint32_t suid; // Saved user ID
uint32_t sgid; // Saved group ID
uint64_t cap_permitted;
uint64_t cap_effective;
} __attribute__((packed));

struct ebpf_tty_winsize {
Expand Down Expand Up @@ -150,6 +152,7 @@ struct ebpf_process_fork_event {
struct ebpf_event_header hdr;
struct ebpf_pid_info parent_pids;
struct ebpf_pid_info child_pids;
struct ebpf_cred_info creds;

// Variable length fields: pids_ss_cgroup_path
struct ebpf_varlen_fields_start vl_fields;
Expand Down
43 changes: 43 additions & 0 deletions GPL/Events/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,49 @@ static void ebpf_cred_info__fill(struct ebpf_cred_info *ci, const struct task_st
ci->rgid = BPF_CORE_READ(task, cred, gid.val);
ci->egid = BPF_CORE_READ(task, cred, egid.val);
ci->sgid = BPF_CORE_READ(task, cred, sgid.val);

// This check is to determine when the kernel_cap_t definition changed.
//
// Previously it was:
// typedef struct kernel_cap_struct {
// __u32 cap[_KERNEL_CAPABILITY_U32S];
// } kernel_cap_t;
//
// Currently it is:
// typedef struct { u64 val; } kernel_cap_t;
//
// See https://github.com/torvalds/linux/commit/f122a08b197d076ccf136c73fae0146875812a88
//
if (bpf_core_field_exists(task->cred->cap_permitted.cap)) {
kernel_cap_t dest;

dest.cap[0] = 0;
dest.cap[1] = 0;
dest = BPF_CORE_READ(task, cred, cap_permitted);
ci->cap_permitted = (((u64)dest.cap[1]) << 32) + dest.cap[0];

dest.cap[0] = 0;
dest.cap[1] = 0;
dest = BPF_CORE_READ(task, cred, cap_effective);
ci->cap_effective = (((u64)dest.cap[1]) << 32) + dest.cap[0];
} else {
const struct cred *cred = BPF_CORE_READ(task, cred);
const void *cap = NULL;

struct new_kernel_cap_struct {
u64 val;
} dest;

dest.val = 0;
cap = &cred->cap_permitted;
bpf_core_read(&dest, bpf_core_type_size(struct new_kernel_cap_struct), cap);
ci->cap_permitted = dest.val;

dest.val = 0;
cap = &cred->cap_effective;
bpf_core_read(&dest, bpf_core_type_size(struct new_kernel_cap_struct), cap);
ci->cap_effective = dest.val;
}
}

static bool is_kernel_thread(const struct task_struct *task)
Expand Down
1 change: 1 addition & 0 deletions GPL/Events/Process/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ int BPF_PROG(sched_process_fork, const struct task_struct *parent, const struct
event->hdr.ts = bpf_ktime_get_ns();
ebpf_pid_info__fill(&event->parent_pids, parent);
ebpf_pid_info__fill(&event->child_pids, child);
ebpf_cred_info__fill(&event->creds, parent);

// Variable length fields
ebpf_vl_fields__init(&event->vl_fields);
Expand Down
7 changes: 7 additions & 0 deletions non-GPL/Events/EventsTrace/EventsTrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ static void out_cred_info(const char *name, struct ebpf_cred_info *cred_info)
out_int("suid", cred_info->suid);
out_comma();
out_int("sgid", cred_info->sgid);
out_comma();
printf("\"cap_permitted\": \"%lu\"", cred_info->cap_permitted);
out_comma();
printf("\"cap_effective\": \"%lu\"", cred_info->cap_effective);
out_object_end();
}

Expand Down Expand Up @@ -429,6 +433,9 @@ static void out_process_fork(struct ebpf_process_fork_event *evt)
out_comma();

out_pid_info("child_pids", &evt->child_pids);
out_comma();

out_cred_info("creds", &evt->creds);

struct ebpf_varlen_field *field;
FOR_EACH_VARLEN_FIELD(evt->vl_fields, field)
Expand Down
17 changes: 15 additions & 2 deletions testing/test_bins/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

#include <stdio.h>
#include <sys/capability.h>
#include <sys/types.h>
#include <syscall.h>
#include <unistd.h>
Expand All @@ -29,6 +30,18 @@ pid_t gettid()

void gen_pid_info_json(char *buf, size_t size)
{
snprintf(buf, size, "{\"tid\": %d, \"ppid\": %d, \"tgid\": %d, \"sid\": %d, \"pgid\": %d}",
gettid(), getppid(), getpid(), getsid(0), getpgid(0));
struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
struct __user_cap_data_struct data[2] = {{0}};
uint64_t cap_permitted = 0;
uint64_t cap_effective = 0;

(void)capget(&hdr, data);
cap_permitted = ((uint64_t)data[1].permitted << 32) + (uint64_t)data[0].permitted;
cap_effective = ((uint64_t)data[1].effective << 32) + (uint64_t)data[0].effective;

snprintf(buf, size,
"{\"tid\": %d, \"ppid\": %d, \"tgid\": %d, \"sid\": %d, \"pgid\": %d, "
"\"cap_permitted\": \"%lu\", \"cap_effective\":\"%lu\"}",
(pid_t)syscall(SYS_gettid), getppid(), getpid(), getsid(0), getpgid(0), cap_permitted,
cap_effective);
}
9 changes: 9 additions & 0 deletions testing/test_bins/fork_exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
int main()
{
pid_t pid;
struct __user_cap_header_struct hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
struct __user_cap_data_struct data[2] = {{0}};

data[0].permitted = 0xffffffff;
data[1].permitted = 0;
data[0].effective = 0xf0f0f0f0;
data[1].effective = 0;
CHECK(capset(&hdr, &data[0]), -1);

CHECK(pid = fork(), -1);

if (pid != 0) {
Expand Down
4 changes: 4 additions & 0 deletions testing/testrunner/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ func TestForkExec(et *EventsTraceInstance) {
}
}

AssertUint64Equal(uint64(forkEvent.Creds.CapPermitted), uint64(0x00000000ffffffff))
AssertUint64Equal(uint64(forkEvent.Creds.CapEffective), uint64(0x00000000f0f0f0f0))
AssertUint64Equal(uint64(execEvent.Creds.CapPermitted), uint64(0x000001ffffffffff))
AssertUint64Equal(uint64(execEvent.Creds.CapEffective), uint64(0x000001ffffffffff))
AssertStringsEqual(execEvent.FileName, "./do_nothing")
AssertStringsEqual(execEvent.Argv[0], "./do_nothing")
AssertStringsEqual(execEvent.Env[0], "TEST_ENV_KEY1=TEST_ENV_VAL1")
Expand Down
11 changes: 11 additions & 0 deletions testing/testrunner/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type TestPidInfo struct {
Ppid int64 `json:"ppid"`
Pgid int64 `json:"pgid"`
Sid int64 `json:"sid"`
CapPermitted uint64 `json:"cap_permitted,string"`
CapEffective uint64 `json:"cap_effective,string"`
}

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

type TtyInfo struct {
Expand All @@ -77,6 +81,7 @@ type NetInfo struct {
type ProcessForkEvent struct {
ParentPids PidInfo `json:"parent_pids"`
ChildPids PidInfo `json:"child_pids"`
Creds CredInfo `json:"creds"`
}

type ProcessExecEvent struct {
Expand Down Expand Up @@ -223,6 +228,12 @@ func AssertInt64NotEqual(a, b int64) {
}
}

func AssertUint64Equal(a, b uint64) {
if a != b {
TestFail(fmt.Sprintf("Test assertion failed 0x%016x != 0x%016x", a, b))
}
}

func PrintBPFDebugOutput() {
file, err := os.Open("/sys/kernel/debug/tracing/trace")
if err != nil {
Expand Down

0 comments on commit c8f96f3

Please sign in to comment.