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

tetragon: store caps during fork #2275

Merged
merged 5 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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: 0 additions & 1 deletion bpf/alignchecker/bpf_alignchecker.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ struct msg_exit _msg_exit;
struct msg_test _msg_test;
struct msg_cgroup_event _msg_cgroup_event;
struct msg_cred _msg_cred;
struct msg_cred_minimal _msg_cred_minimal;

// from maps
struct event _event;
Expand Down
24 changes: 0 additions & 24 deletions bpf/lib/bpf_cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,6 @@ struct msg_cred {
struct msg_user_namespace user_ns;
} __attribute__((packed));

/*
* TODO: we have msg_cred above that includes the full credentials
* definition and is used in kprobes.
* However since we are also moving to use creds for
* exec events, so let's do it step by step, as we already
* have the capabilities in execve inside the execve_map and
* the user space cache, so we start with this minimal
* credential object that holds only uids/gids, then we follow
* up by moving the capabilities into it, and make this cred
* the new storage in execve_map and user space process cache.
*/
struct msg_cred_minimal {
__u32 uid;
__u32 gid;
__u32 suid;
__u32 sgid;
__u32 euid;
__u32 egid;
__u32 fsuid;
__u32 fsgid;
__u32 securebits;
__u32 pad;
} __attribute__((packed));

/* Execution and cred related flags shared with userspace */
#define EXEC_SETUID 0x01 /* This is a set-user-id execution */
#define EXEC_SETGID 0x02 /* This is a set-group-id execution */
Expand Down
4 changes: 1 addition & 3 deletions bpf/lib/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,7 @@ struct msg_execve_event {
struct msg_k8s kube;
struct msg_execve_key parent;
__u64 parent_flags;
struct msg_capabilities caps;
/* TODO: convert this msg_cred_minimal to msg_cred and include caps above inside */
struct msg_cred_minimal creds;
struct msg_cred creds;
struct msg_ns ns;
struct msg_execve_key cleanup_key;
/* if add anything above please also update the args of
Expand Down
13 changes: 5 additions & 8 deletions bpf/process/bpf_execve_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,7 @@ event_execve(struct sched_execve_args *ctx)

BPF_CORE_READ_INTO(&event->kube.net_ns, task, nsproxy, net_ns, ns.inum);

// At this time objective and subjective creds are same
get_current_subj_caps(&event->caps, task);
get_current_subj_creds_uids(&event->creds, task);
get_current_subj_creds(&event->creds, task);
get_namespaces(&event->ns, task);
p->flags |= __event_get_cgroup_info(task, &event->kube);

Expand Down Expand Up @@ -296,9 +294,9 @@ execve_send(struct sched_execve_args *ctx)
#endif
#ifdef __CAP_CHANGES_FILTER
if (init_curr) {
curr->caps.permitted = event->caps.permitted;
curr->caps.effective = event->caps.effective;
curr->caps.inheritable = event->caps.inheritable;
curr->caps.permitted = event->creds.caps.permitted;
curr->caps.effective = event->creds.caps.effective;
curr->caps.inheritable = event->creds.caps.inheritable;
}
#endif
// buffer can be written at clone stage with parent's info, if previous
Expand Down Expand Up @@ -327,8 +325,7 @@ execve_send(struct sched_execve_args *ctx)
size = validate_msg_execve_size(
sizeof(struct msg_common) + sizeof(struct msg_k8s) +
sizeof(struct msg_execve_key) + sizeof(__u64) +
sizeof(struct msg_capabilities) +
sizeof(struct msg_cred_minimal) + sizeof(struct msg_ns) +
sizeof(struct msg_cred) + sizeof(struct msg_ns) +
sizeof(struct msg_execve_key) + p->size);
perf_event_output_metric(ctx, MSG_OP_EXECVE, &tcpmon_map, BPF_F_CURRENT_CPU, event, size);
return 0;
Expand Down
10 changes: 10 additions & 0 deletions bpf/process/bpf_fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ BPF_KPROBE(event_wake_up_new_task, struct task_struct *task)
{
struct execve_map_value *curr, *parent;
struct msg_clone_event msg;
struct msg_capabilities caps;
u64 msg_size = sizeof(struct msg_clone_event);
u32 tgid = 0;

Expand Down Expand Up @@ -56,6 +57,15 @@ BPF_KPROBE(event_wake_up_new_task, struct task_struct *task)
memcpy(&curr->bin, &parent->bin, sizeof(curr->bin));
curr->pkey = parent->key;

/* Store the thread leader capabilities so we can check later
* before the execve hook point if they changed or not.
* This needs to be converted later to credentials.
*/
get_current_subj_caps(&caps, task);
curr->caps.permitted = caps.permitted;
curr->caps.effective = caps.effective;
curr->caps.inheritable = caps.inheritable;

/* Setup the msg_clone_event and sent to the user. */
msg.common.op = MSG_OP_CLONE;
msg.common.size = msg_size;
Expand Down
5 changes: 4 additions & 1 deletion bpf/process/bpf_process_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ get_current_subj_caps(struct msg_capabilities *msg, struct task_struct *task)
}

static inline __attribute__((always_inline)) void
get_current_subj_creds_uids(struct msg_cred_minimal *info, struct task_struct *task)
get_current_subj_creds(struct msg_cred *info, struct task_struct *task)
{
const struct cred *cred;

Expand All @@ -484,6 +484,9 @@ get_current_subj_creds_uids(struct msg_cred_minimal *info, struct task_struct *t
probe_read(&info->fsuid, sizeof(__u32), _(&cred->fsuid));
probe_read(&info->fsgid, sizeof(__u32), _(&cred->fsgid));
probe_read(&info->securebits, sizeof(__u32), _(&cred->securebits));

/* Get capabilities */
__get_caps(&info->caps, cred);
}

static inline __attribute__((always_inline)) void
Expand Down
3 changes: 1 addition & 2 deletions pkg/alignchecker/alignchecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ func CheckStructAlignments(pathToObj string) error {
"msg_execve_key": {processapi.MsgExecveKey{}},
"execve_map_value": {execvemap.ExecveValue{}},
"msg_cgroup_event": {processapi.MsgCgroupEvent{}},
"msg_cred": {tracingapi.MsgGenericCred{}},
"msg_cred_minimal": {processapi.MsgGenericCredMinimal{}},
"msg_cred": {processapi.MsgGenericCred{}},

// configuration
"event_config": {tracingapi.EventConfig{}},
Expand Down
7 changes: 4 additions & 3 deletions pkg/api/processapi/processapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ type MsgK8sUnix struct {
Docker string
}

type MsgGenericCredMinimal struct {
type MsgGenericCred struct {
Uid uint32
Gid uint32
Suid uint32
Expand All @@ -101,15 +101,16 @@ type MsgGenericCredMinimal struct {
FSgid uint32
SecureBits uint32
Pad uint32
Cap MsgCapabilities
UserNs MsgUserNamespace
}

type MsgExecveEvent struct {
Common MsgCommon
Kube MsgK8s
Parent MsgExecveKey
ParentFlags uint64
Capabilities MsgCapabilities
Creds MsgGenericCredMinimal
Creds MsgGenericCred
Namespaces MsgNamespaces
CleanupProcess MsgExecveKey
}
Expand Down
15 changes: 0 additions & 15 deletions pkg/api/tracingapi/client_kprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,21 +271,6 @@ func (m MsgGenericKprobeArgNetDev) IsReturnArg() bool {
return m.Index == ReturnArgIndex
}

type MsgGenericCred struct {
Uid uint32
Gid uint32
Suid uint32
Sgid uint32
Euid uint32
Egid uint32
FSuid uint32
FSgid uint32
SecureBits uint32
Pad uint32
Cap processapi.MsgCapabilities
UserNs processapi.MsgUserNamespace
}

type MsgGenericKprobeArgCred struct {
Index uint64
Uid uint32
Expand Down
12 changes: 6 additions & 6 deletions pkg/grpc/process_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,16 @@ func TestProcessManager_GetProcessExec(t *testing.T) {
Common: processapi.MsgCommon{
Ktime: 1234,
},
Creds: processapi.MsgGenericCredMinimal{
Creds: processapi.MsgGenericCred{
Uid: 1000,
Gid: 1000,
Euid: 10000,
Egid: 10000,
},
Capabilities: processapi.MsgCapabilities{
Permitted: 1,
Effective: 1,
Inheritable: 1,
Cap: processapi.MsgCapabilities{
Permitted: 1,
Effective: 1,
Inheritable: 1,
},
},
},
Process: processapi.MsgProcess{
Expand Down
4 changes: 2 additions & 2 deletions pkg/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,10 @@ func initProcessInternalExec(
} else {
parentExecID = GetProcessID(0, 1)
}
creds := &event.Msg.Creds
execID := GetExecID(&process)
protoPod := GetPodInfo(containerID, process.Filename, args, process.NSPID)
apiCaps := caps.GetMsgCapabilities(event.Msg.Capabilities)
apiCaps := caps.GetMsgCapabilities(event.Msg.Creds.Cap)
binary := path.GetBinaryAbsolutePath(process.Filename, cwd)
apiNs, err := namespace.GetMsgNamespaces(event.Msg.Namespaces)
if err != nil {
Expand All @@ -294,7 +295,6 @@ func initProcessInternalExec(
}).Warn("ExecveEvent: parsing namespaces failed")
}

creds := &event.Msg.Creds
apiCreds := &tetragon.ProcessCredentials{
Uid: &wrapperspb.UInt32Value{Value: creds.Uid},
Gid: &wrapperspb.UInt32Value{Value: creds.Gid},
Expand Down
19 changes: 16 additions & 3 deletions pkg/sensors/exec/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/cilium/tetragon/pkg/observer/observertesthelper"
"github.com/cilium/tetragon/pkg/option"
proc "github.com/cilium/tetragon/pkg/process"
"github.com/cilium/tetragon/pkg/reader/caps"
"github.com/cilium/tetragon/pkg/reader/namespace"
"github.com/cilium/tetragon/pkg/sensors"
"github.com/cilium/tetragon/pkg/sensors/base"
Expand Down Expand Up @@ -260,9 +261,14 @@ func TestEventExecve(t *testing.T) {

testNop := testutils.RepoRootPath("contrib/tester-progs/nop")

myCaps := ec.NewCapabilitiesChecker().FromCapabilities(caps.GetCurrentCapabilities())
myNs := ec.NewNamespacesChecker().FromNamespaces(namespace.GetCurrentNamespace())

procChecker := ec.NewProcessChecker().
WithBinary(sm.Full(testNop)).
WithArguments(sm.Full("arg1 arg2 arg3"))
WithArguments(sm.Full("arg1 arg2 arg3")).
WithCap(myCaps).
WithNs(myNs)

execChecker := ec.NewProcessExecChecker("").WithProcess(procChecker)
checker := ec.NewUnorderedEventChecker(execChecker)
Expand Down Expand Up @@ -892,6 +898,9 @@ func TestExecProcessCredentials(t *testing.T) {
}
})

myCaps := ec.NewCapabilitiesChecker().FromCapabilities(caps.GetCurrentCapabilities())
myNs := ec.NewNamespacesChecker().FromNamespaces(namespace.GetCurrentNamespace())

if err := exec.Command(testNop).Run(); err != nil {
t.Fatalf("Failed to execute test binary: %s\n", err)
}
Expand All @@ -905,10 +914,14 @@ func TestExecProcessCredentials(t *testing.T) {
WithGid(0).WithEgid(gid).WithSgid(gid).WithFsgid(gid)

procExecChecker := ec.NewProcessChecker().
WithBinary(sm.Full(testNop)).WithProcessCredentials(creds).WithBinaryProperties(nil)
WithBinary(sm.Full(testNop)).WithProcessCredentials(creds).WithBinaryProperties(nil).
WithCap(myCaps).
WithNs(myNs)

procGidExecChecker := ec.NewProcessChecker().
WithBinary(sm.Full(testNop)).WithProcessCredentials(gidCreds).WithBinaryProperties(nil)
WithBinary(sm.Full(testNop)).WithProcessCredentials(gidCreds).WithBinaryProperties(nil).
WithCap(myCaps).
WithNs(myNs)

execChecker := ec.NewProcessExecChecker("exec").WithProcess(procExecChecker)
execGidChecker := ec.NewProcessExecChecker("exec").WithProcess(procGidExecChecker)
Expand Down
13 changes: 8 additions & 5 deletions pkg/sensors/exec/procevents/proc_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func pushExecveEvents(p procs) {
m.Unix.Msg.Parent.Pid = p.ppid
m.Unix.Msg.Parent.Ktime = p.pktime

m.Unix.Msg.Capabilities = processapi.MsgCapabilities{}
m.Unix.Msg.Creds.Cap = processapi.MsgCapabilities{}
m.Unix.Msg.Namespaces = processapi.MsgNamespaces{}

m.Unix.Process.Size = p.size
Expand Down Expand Up @@ -244,9 +244,11 @@ func pushExecveEvents(p procs) {
m.Unix.Msg.Parent.Pid = p.ppid
m.Unix.Msg.Parent.Ktime = p.pktime

m.Unix.Msg.Capabilities.Permitted = p.permitted
m.Unix.Msg.Capabilities.Effective = p.effective
m.Unix.Msg.Capabilities.Inheritable = p.inheritable
caps := processapi.MsgCapabilities{
Permitted: p.permitted,
Effective: p.effective,
Inheritable: p.inheritable,
}

m.Unix.Msg.Namespaces.UtsInum = p.uts_ns
m.Unix.Msg.Namespaces.IpcInum = p.ipc_ns
Expand All @@ -266,9 +268,10 @@ func pushExecveEvents(p procs) {
// use euid to be compatible with ps
m.Unix.Process.UID = p.uids[1]
m.Unix.Process.AUID = p.auid
m.Unix.Msg.Creds = processapi.MsgGenericCredMinimal{
m.Unix.Msg.Creds = processapi.MsgGenericCred{
Uid: p.uids[0], Euid: p.uids[1], Suid: p.uids[2], FSuid: p.uids[3],
Gid: p.gids[0], Egid: p.gids[1], Sgid: p.gids[2], FSgid: p.gids[3],
Cap: caps,
}
m.Unix.Process.Flags = p.flags | flags
m.Unix.Process.Ktime = p.ktime
Expand Down
6 changes: 3 additions & 3 deletions pkg/sensors/tracing/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"io"

"github.com/cilium/tetragon/pkg/api/dataapi"
"github.com/cilium/tetragon/pkg/api/tracingapi"
processapi "github.com/cilium/tetragon/pkg/api/processapi"
api "github.com/cilium/tetragon/pkg/api/tracingapi"
gt "github.com/cilium/tetragon/pkg/generictypes"
"github.com/cilium/tetragon/pkg/k8s/apis/cilium.io/v1alpha1"
Expand Down Expand Up @@ -74,7 +74,7 @@ func getTracepointMetaValue(arg *v1alpha1.KProbeArg) int {
return 0
}

func getArg(r *bytes.Reader, a argPrinter) tracingapi.MsgGenericKprobeArg {
func getArg(r *bytes.Reader, a argPrinter) api.MsgGenericKprobeArg {
var err error

switch a.ty {
Expand Down Expand Up @@ -176,7 +176,7 @@ func getArg(r *bytes.Reader, a argPrinter) tracingapi.MsgGenericKprobeArg {
arg.Label = a.label
return arg
case gt.GenericCredType:
var cred api.MsgGenericCred
var cred processapi.MsgGenericCred
var arg api.MsgGenericKprobeArgCred

err := binary.Read(r, binary.LittleEndian, &cred)
Expand Down
12 changes: 9 additions & 3 deletions pkg/sensors/tracing/kprobe_threads_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/cilium/tetragon/pkg/logger"
sm "github.com/cilium/tetragon/pkg/matchers/stringmatcher"
"github.com/cilium/tetragon/pkg/observer/observertesthelper"
"github.com/cilium/tetragon/pkg/reader/caps"
"github.com/cilium/tetragon/pkg/testutils"
tus "github.com/cilium/tetragon/pkg/testutils/sensors"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -90,10 +91,13 @@ spec:

cti.AssertPidsTids(t)

myCaps := ec.NewCapabilitiesChecker().FromCapabilities(caps.GetCurrentCapabilities())

parentCheck := ec.NewProcessChecker().
WithBinary(sm.Suffix("threads-tester")).
WithPid(cti.ParentPid).
WithTid(cti.ParentTid)
WithTid(cti.ParentTid).
WithCap(myCaps)

execCheck := ec.NewProcessExecChecker("").
WithProcess(parentCheck)
Expand All @@ -104,15 +108,17 @@ spec:
child1Checker := ec.NewProcessChecker().
WithBinary(sm.Suffix("threads-tester")).
WithPid(cti.Child1Pid).
WithTid(cti.Child1Tid)
WithTid(cti.Child1Tid).
WithCap(myCaps)

child1KpChecker := ec.NewProcessKprobeChecker("").
WithProcess(child1Checker).WithParent(parentCheck)

thread1Checker := ec.NewProcessChecker().
WithBinary(sm.Suffix("threads-tester")).
WithPid(cti.Thread1Pid).
WithTid(cti.Thread1Tid)
WithTid(cti.Thread1Tid).
WithCap(myCaps)

thread1KpChecker := ec.NewProcessKprobeChecker("").
WithProcess(thread1Checker).WithParent(parentCheck)
Expand Down
Loading