Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add effective and permitted caps to fork and exec events. #172

Merged
merged 6 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
31 changes: 31 additions & 0 deletions GPL/Events/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,37 @@ 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);

if (bpf_core_field_exists(task->cred->cap_permitted.cap)) {
nicholasberlin marked this conversation as resolved.
Show resolved Hide resolved
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
Loading