Skip to content

cgroups: add basic cgroups tracking and make it part of the testing framework #471

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

Merged
merged 27 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
20f4ff9
bpf:cgroup: add Cgroup operations definition
tixxdz Aug 22, 2022
2f5874d
bpf:cgroup: add cgroups tracking structures and maps
tixxdz Sep 20, 2022
5c1e8f0
bpf:cgroups: add cgroup helpers to retrieve cgroup level and ancestors
tixxdz Sep 20, 2022
95c833b
bpf:conf: update tetragon_conf with necessary fields
tixxdz Sep 20, 2022
5c3d841
bpf::cgroup: add send cgroup events helper
tixxdz Oct 30, 2022
f2584ea
bpf:cgroup: add bpf programs to track cgroup creation and deletion
tixxdz Oct 21, 2022
697d9de
bpf:cgroup: track cgroups that belong to the right hierarchy
tixxdz Oct 31, 2022
7bbc00d
bpf:make: compile new bpf cgroup programs
tixxdz Oct 12, 2022
5af6747
tetragon:conf: store loglevel and cgroupFsMagic into BPF conf
tixxdz Oct 10, 2022
cdb50fe
pkg:api: add Cgroup message definition
tixxdz Oct 10, 2022
ad8d8eb
pkg:api: add Cgroup operation and message definitions
tixxdz Oct 12, 2022
6f1c2ca
pkg:sensors: register cgroup events handler
tixxdz Sep 22, 2022
cac2771
pkg:sensors: add cgrouptrackmap to read tracked cgroups from bpf maps
tixxdz Oct 10, 2022
4a076f3
pkg:sensors: add helper to read Tetragon Runtime configuration
tixxdz Oct 11, 2022
3bb2c46
pkg:observer: pass custom BPF maps root dir to UpdateRuntimeConf()
tixxdz Oct 13, 2022
51cd989
pkg:cgroups: add GetCgroupFSPath() to get real cgroupfs path
tixxdz Oct 13, 2022
8fb1389
tests:ops: add Cgroup Operation code and state test
tixxdz Aug 25, 2022
d3003aa
tests:processapi: check Cgroup Structs against alignchecker
tixxdz Oct 31, 2022
9a56c51
tests:cgrouptrackmap: check CgrpTrackingValue struct against alignche…
tixxdz Oct 31, 2022
931c795
tests:cgrouptrackmap: add test for DeepCopyMapValue()
tixxdz Oct 10, 2022
ffd54d3
tests:cgroups: assert c strings conversion to golang ones
tixxdz Oct 10, 2022
9a100ac
tests:cgroups: test cgroupfs path and magic number helpers
tixxdz Oct 11, 2022
ac8e0aa
tests:sensors: add bpf cgroups sensor to test
tixxdz Oct 12, 2022
28d6815
tests:cgroups: add load cgroup bpf programs test
tixxdz Oct 11, 2022
44372c5
tests:sensors: add TestTgRuntimeConf() to test runtime conf
tixxdz Oct 12, 2022
59654da
tests:cgroups: ensure that we do not get bpf cgroup events
tixxdz Oct 13, 2022
84fc957
tests:cgroups: ensure that we get cgroup mkdir and rmdir events
tixxdz Oct 31, 2022
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
12 changes: 11 additions & 1 deletion bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ SHELL=/bin/bash # needed for the *.{o,ll,i,s} pattern in the clean target

ALIGNCHECKERDIR = alignchecker/
PROCESSDIR := process/
CGROUPDIR := cgroup/
BPFTESTDIR := test/

ALIGNCHECKER = bpf_alignchecker.o
PROCESS = bpf_execve_event.o bpf_execve_event_v53.o bpf_fork.o bpf_exit.o bpf_generic_kprobe.o \
bpf_generic_kprobe_v53.o bpf_generic_retkprobe.o bpf_generic_retkprobe_v53.o \
bpf_multi_kprobe_v53.o bpf_multi_retkprobe_v53.o \
bpf_generic_tracepoint.o bpf_generic_tracepoint_v53.o
CGROUP = bpf_cgroup_mkdir.o bpf_cgroup_rmdir.o bpf_cgroup_release.o
BPFTEST = bpf_lseek.o bpf_globals.o

IDIR = ./include/
Expand All @@ -38,9 +40,10 @@ DEPSDIR := deps/
TLSOBJ := $(addprefix $(OBJSDIR),$(TLS))
NOPOBJ := $(addprefix $(OBJSDIR),$(NOP))
PROCESSOBJ := $(addprefix $(OBJSDIR),$(PROCESS))
CGROUPOBJ := $(addprefix $(OBJSDIR),$(CGROUP))
TESTOBJ := $(addprefix $(OBJSDIR),$(BPFTEST))
ALIGNCHECKEROBJ := $(addprefix $(OBJSDIR),$(ALIGNCHECKER))
OBJS := $(PROCESSOBJ) $(TESTOBJ) $(NOPOBJ) $(ALIGNCHECKEROBJ)
OBJS := $(PROCESSOBJ) $(CGROUPOBJ) $(TESTOBJ) $(NOPOBJ) $(ALIGNCHECKEROBJ)
LLOBJS := $(patsubst $(OBJSDIR)%.o,$(OBJSDIR)%.ll,$(OBJS))
DEPS := $(patsubst $(OBJSDIR)%.ll,$(DEPSDIR)%.d,$(LLOBJS))

Expand Down Expand Up @@ -103,6 +106,13 @@ objs/%.ll: $(BPFTESTDIR)%.c
$(DEPSDIR)%.d: $(BPFTESTDIR)%.c
$(CLANG) $(CLANG_FLAGS) -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@

# CGROUPDIR
objs/%.ll: $(CGROUPDIR)%.c
$(CLANG) $(CLANG_FLAGS) -c $< -o $@

$(DEPSDIR)%.d: $(CGROUPDIR)%.c
$(CLANG) $(CLANG_FLAGS) -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@

# Remaining objects are built without mcpu=v2
objs/%.o: objs/%.ll
$(LLC) $(LLC_FLAGS) -filetype=obj $< -o $@
Expand Down
2 changes: 2 additions & 0 deletions bpf/alignchecker/bpf_alignchecker.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ int main(void)
DECLARE(struct, msg_execve_event, iter);
DECLARE(struct, msg_exit, iter);
DECLARE(struct, msg_test, iter);
DECLARE(struct, msg_cgroup_event, iter);

// from maps
DECLARE(struct, event, iter);
DECLARE(struct, msg_execve_key, iter);
DECLARE(struct, execve_map_value, iter);
DECLARE(struct, event_config, iter);
DECLARE(struct, tetragon_conf, iter);
DECLARE(struct, cgroup_tracking_value, iter);

return 0;
}
59 changes: 59 additions & 0 deletions bpf/cgroup/bpf_cgroup_events.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright Authors of Tetragon */

#ifndef _BPF_CGROUP_EVENTS__
#define _BPF_CGROUP_EVENTS__

#include "bpf_helpers.h"
#include "bpf_events.h"
#include "environ_conf.h"

/* This function will send the cgroup events to the ring buffer */
static inline __attribute__((always_inline)) int
send_cgrp_event(struct bpf_raw_tracepoint_args *ctx,
struct cgroup_tracking_value *cgrp_track, __u64 cgrpid,
__u32 op)
{
pid_t pid;
char *path;
int zero = 0;
uint64_t size;
struct execve_map_value *curr;
struct msg_cgroup_event *msg;

msg = map_lookup_elem(&tg_cgrps_msg_heap, &zero);
if (!msg)
return 0;

size = sizeof(struct msg_cgroup_event);
msg->common.op = MSG_OP_CGROUP;
msg->common.size = size;

path = (char *)ctx->args[1];
pid = (get_current_pid_tgid() >> 32);

curr = execve_map_get(pid);
if (curr) {
msg->common.ktime = curr->key.ktime;
msg->parent = curr->pkey;
msg->flags = curr->flags;
msg->ktime = curr->key.ktime;
}
msg->cgrp_op = op;
msg->pid = pid;
msg->nspid = get_task_pid_vnr();
msg->cgrpid = cgrpid;
/* It is same as we are not tracking nested cgroups */
msg->cgrpid_tracker = cgrpid;
msg->cgrp_data.state = cgrp_track->state;
msg->cgrp_data.level = cgrp_track->level;
msg->cgrp_data.hierarchy_id = cgrp_track->hierarchy_id;
memcpy(&msg->cgrp_data.name, &cgrp_track->name, KN_NAME_LENGTH);
probe_read_str(&msg->path, PATH_MAP_SIZE - 1, path);

perf_event_output(ctx, &tcpmon_map, BPF_F_CURRENT_CPU, msg, size);

return 0;
}

#endif
78 changes: 78 additions & 0 deletions bpf/cgroup/bpf_cgroup_mkdir.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright Authors of Tetragon */

#include "vmlinux.h"
#include "api.h"

#include "hubble_msg.h"
#include "bpf_cgroup.h"
#include "bpf_events.h"
#include "bpf_cgroup_events.h"

char _license[] __attribute__((section(("license")), used)) = "GPL";
#ifdef VMLINUX_KERNEL_VERSION
int _version __attribute__((section(("version")), used)) =
VMLINUX_KERNEL_VERSION;
#endif

__attribute__((section(("raw_tracepoint/cgroup_mkdir")), used)) int
tg_tp_cgrp_mkdir(struct bpf_raw_tracepoint_args *ctx)
{
uint64_t cgrpid;
int level, hierarchy_id, zero = 0;
struct cgroup *cgrp;
struct cgroup_tracking_value *cgrp_heap;
struct tetragon_conf *config;

config = map_lookup_elem(&tg_conf_map, &zero);
if (!config || config->tg_cgrp_level == 0)
return 0;

cgrp = (struct cgroup *)ctx->args[0];

hierarchy_id = get_cgroup_hierarchy_id(cgrp);
/*
* In a cgroupv1 setup, there can be multiple cgroup hierarchies but
* we want to track only one If this is not the hierarchy we care
* about, exit.
*/
if (config->tg_cgrp_hierarchy != hierarchy_id)
return 0;

level = get_cgroup_level(cgrp);
/* This should never happen as the cgroup hierarchy has already been
* set (e.g., by systemd)
*/
if (level == 0)
return 0;

cgrpid = get_cgroup_id(cgrp);
/* This should never happen unless the bpf helper failed */
if (cgrpid == 0)
return 0;

/* We want to track all processes of a container system so that we can
* provide proper identity to events. To do that, we use a certain cgroup
* level. Any cgroups that are created under that level, we ignore.
* That is, if we are monitoring level 5, we do not care about cgroup
* events with level >5.
*/
if (level <= config->tg_cgrp_level) {
cgrp_heap = __init_cgrp_tracking_val_heap(cgrp, CGROUP_NEW);
if (!cgrp_heap)
return 0;

/* We track only for now cgroups that are at same or above tetragon
* level (ancestors level)
*/
map_update_elem(&tg_cgrps_tracking_map, &cgrpid, cgrp_heap,
BPF_ANY);

/* We forward bpf events only under TraceLevel */
if (unlikely(config->loglevel == LOG_TRACE_LEVEL))
send_cgrp_event(ctx, cgrp_heap, cgrpid,
MSG_OP_CGROUP_MKDIR);
}

return 0;
}
53 changes: 53 additions & 0 deletions bpf/cgroup/bpf_cgroup_release.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright Authors of Tetragon */

#include "vmlinux.h"
#include "api.h"

#include "hubble_msg.h"
#include "bpf_cgroup.h"
#include "bpf_events.h"
#include "bpf_cgroup_events.h"

char _license[] __attribute__((section(("license")), used)) = "GPL";
#ifdef VMLINUX_KERNEL_VERSION
int _version __attribute__((section(("version")), used)) =
VMLINUX_KERNEL_VERSION;
#endif

/* Ensure to remove tracked cgroups from bpf map */
__attribute__((section(("raw_tracepoint/cgroup_release")), used)) int
tg_tp_cgrp_release(struct bpf_raw_tracepoint_args *ctx)
{
int zero = 0;
uint64_t cgrpid;
struct cgroup *cgrp;
struct tetragon_conf *conf;
struct cgroup_tracking_value *cgrp_track;

cgrp = (struct cgroup *)ctx->args[0];
cgrpid = get_cgroup_id(cgrp);
/* This should never happen unless our helper failed */
if (cgrpid == 0)
return 0;

cgrp_track = map_lookup_elem(&tg_cgrps_tracking_map, &cgrpid);
/* TODO: check cgroup level if it is under our tracking level
* then we probably did miss it and should report this.
* Otherwise the cgroup was never tracked and let's exit.
*/
if (!cgrp_track)
return 0;

map_delete_elem(&tg_cgrps_tracking_map, &cgrpid);

conf = map_lookup_elem(&tg_conf_map, &zero);
if (!conf)
return 0;

/* We forward bpf events only under TraceLevel */
if (unlikely(conf->loglevel == LOG_TRACE_LEVEL))
send_cgrp_event(ctx, cgrp_track, cgrpid, MSG_OP_CGROUP_RELEASE);

return 0;
}
53 changes: 53 additions & 0 deletions bpf/cgroup/bpf_cgroup_rmdir.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright Authors of Tetragon */

#include "vmlinux.h"
#include "api.h"

#include "hubble_msg.h"
#include "bpf_cgroup.h"
#include "bpf_events.h"
#include "bpf_cgroup_events.h"

char _license[] __attribute__((section(("license")), used)) = "GPL";
#ifdef VMLINUX_KERNEL_VERSION
int _version __attribute__((section(("version")), used)) =
VMLINUX_KERNEL_VERSION;
#endif

/* Remove tracked cgroups from bpf map */
__attribute__((section(("raw_tracepoint/cgroup_rmdir")), used)) int
tg_tp_cgrp_rmdir(struct bpf_raw_tracepoint_args *ctx)
{
int zero = 0;
uint64_t cgrpid;
struct cgroup *cgrp;
struct tetragon_conf *conf;
struct cgroup_tracking_value *cgrp_track;

cgrp = (struct cgroup *)ctx->args[0];
cgrpid = get_cgroup_id(cgrp);
/* This should never happen unless the bpf helper failed */
if (cgrpid == 0)
return 0;

cgrp_track = map_lookup_elem(&tg_cgrps_tracking_map, &cgrpid);
/* TODO: check cgroup level if it is under our tracking level
* then we probably did miss it and should report this.
* Otherwise the cgroup was never tracked and let's exit.
*/
if (!cgrp_track)
return 0;

map_delete_elem(&tg_cgrps_tracking_map, &cgrpid);

conf = map_lookup_elem(&tg_conf_map, &zero);
if (!conf)
return 0;

/* We forward bpf events only under TraceLevel */
if (unlikely(conf->loglevel == LOG_TRACE_LEVEL))
send_cgrp_event(ctx, cgrp_track, cgrpid, MSG_OP_CGROUP_RMDIR);

return 0;
}
Loading