diff --git a/docs/cloud-workload-security/backend_linux.md b/docs/cloud-workload-security/backend_linux.md index 1b9507d49c7c..af008d34c86e 100644 --- a/docs/cloud-workload-security/backend_linux.md +++ b/docs/cloud-workload-security/backend_linux.md @@ -1343,6 +1343,10 @@ Workload Protection events for Linux systems have the following JSON schema: "type": "integer", "description": "Parent Process ID" }, + "sid": { + "type": "integer", + "description": "Session ID" + }, "tid": { "type": "integer", "description": "Thread ID" @@ -1505,6 +1509,7 @@ Workload Protection events for Linux systems have the following JSON schema: "additionalProperties": false, "type": "object", "required": [ + "sid", "fork_flags", "uid", "gid" @@ -1521,6 +1526,10 @@ Workload Protection events for Linux systems have the following JSON schema: "type": "integer", "description": "Parent Process ID" }, + "sid": { + "type": "integer", + "description": "Session ID" + }, "tid": { "type": "integer", "description": "Thread ID" @@ -1698,6 +1707,7 @@ Workload Protection events for Linux systems have the following JSON schema: "additionalProperties": false, "type": "object", "required": [ + "sid", "fork_flags", "uid", "gid" @@ -4554,6 +4564,10 @@ Workload Protection events for Linux systems have the following JSON schema: "type": "integer", "description": "Parent Process ID" }, + "sid": { + "type": "integer", + "description": "Session ID" + }, "tid": { "type": "integer", "description": "Thread ID" @@ -4716,6 +4730,7 @@ Workload Protection events for Linux systems have the following JSON schema: "additionalProperties": false, "type": "object", "required": [ + "sid", "fork_flags", "uid", "gid" @@ -4729,6 +4744,7 @@ Workload Protection events for Linux systems have the following JSON schema: | ----- | ----------- | | `pid` | Process ID | | `ppid` | Parent Process ID | +| `sid` | Session ID | | `tid` | Thread ID | | `fork_flags` | ForkFlags | | `uid` | User ID | @@ -4790,6 +4806,10 @@ Workload Protection events for Linux systems have the following JSON schema: "type": "integer", "description": "Parent Process ID" }, + "sid": { + "type": "integer", + "description": "Session ID" + }, "tid": { "type": "integer", "description": "Thread ID" @@ -4967,6 +4987,7 @@ Workload Protection events for Linux systems have the following JSON schema: "additionalProperties": false, "type": "object", "required": [ + "sid", "fork_flags", "uid", "gid" @@ -4980,6 +5001,7 @@ Workload Protection events for Linux systems have the following JSON schema: | ----- | ----------- | | `pid` | Process ID | | `ppid` | Parent Process ID | +| `sid` | Session ID | | `tid` | Thread ID | | `fork_flags` | ForkFlags | | `uid` | User ID | diff --git a/docs/cloud-workload-security/backend_linux.schema.json b/docs/cloud-workload-security/backend_linux.schema.json index f51544f3fd6c..67bb9a3de627 100644 --- a/docs/cloud-workload-security/backend_linux.schema.json +++ b/docs/cloud-workload-security/backend_linux.schema.json @@ -1332,6 +1332,10 @@ "type": "integer", "description": "Parent Process ID" }, + "sid": { + "type": "integer", + "description": "Session ID" + }, "tid": { "type": "integer", "description": "Thread ID" @@ -1494,6 +1498,7 @@ "additionalProperties": false, "type": "object", "required": [ + "sid", "fork_flags", "uid", "gid" @@ -1510,6 +1515,10 @@ "type": "integer", "description": "Parent Process ID" }, + "sid": { + "type": "integer", + "description": "Session ID" + }, "tid": { "type": "integer", "description": "Thread ID" @@ -1687,6 +1696,7 @@ "additionalProperties": false, "type": "object", "required": [ + "sid", "fork_flags", "uid", "gid" diff --git a/docs/cloud-workload-security/linux_expressions.md b/docs/cloud-workload-security/linux_expressions.md index d25c3198d02f..c425c6a05169 100644 --- a/docs/cloud-workload-security/linux_expressions.md +++ b/docs/cloud-workload-security/linux_expressions.md @@ -285,6 +285,7 @@ The *file.rights* attribute can now be used in addition to *file.mode*. *file.mo | [`process.ancestors.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`process.ancestors.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`process.ancestors.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`process.ancestors.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`process.ancestors.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`process.ancestors.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`process.ancestors.uid`](#common-credentials-uid-doc) | UID of the process | @@ -489,6 +490,7 @@ The *file.rights* attribute can now be used in addition to *file.mode*. *file.mo | [`process.parent.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`process.parent.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`process.parent.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`process.parent.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`process.parent.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`process.parent.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`process.parent.uid`](#common-credentials-uid-doc) | UID of the process | @@ -507,6 +509,7 @@ The *file.rights* attribute can now be used in addition to *file.mode*. *file.mo | [`process.parent.user_session.ssh_session_id`](#common-sshsessioncontext-ssh_session_id-doc) | Unique identifier of the SSH user session on the host | | [`process.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`process.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`process.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`process.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`process.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`process.uid`](#common-credentials-uid-doc) | UID of the process | @@ -896,6 +899,7 @@ A process was executed (does not trigger on fork syscalls). | [`exec.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`exec.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`exec.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`exec.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`exec.syscall.path`](#exec-syscall-path-doc) | path argument of the syscall | | [`exec.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`exec.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | @@ -1017,6 +1021,7 @@ A process was terminated | [`exit.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`exit.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`exit.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`exit.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`exit.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`exit.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`exit.uid`](#common-credentials-uid-doc) | UID of the process | @@ -1483,6 +1488,7 @@ A ptrace command was executed | [`ptrace.tracee.ancestors.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`ptrace.tracee.ancestors.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`ptrace.tracee.ancestors.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`ptrace.tracee.ancestors.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`ptrace.tracee.ancestors.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`ptrace.tracee.ancestors.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`ptrace.tracee.ancestors.uid`](#common-credentials-uid-doc) | UID of the process | @@ -1687,6 +1693,7 @@ A ptrace command was executed | [`ptrace.tracee.parent.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`ptrace.tracee.parent.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`ptrace.tracee.parent.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`ptrace.tracee.parent.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`ptrace.tracee.parent.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`ptrace.tracee.parent.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`ptrace.tracee.parent.uid`](#common-credentials-uid-doc) | UID of the process | @@ -1705,6 +1712,7 @@ A ptrace command was executed | [`ptrace.tracee.parent.user_session.ssh_session_id`](#common-sshsessioncontext-ssh_session_id-doc) | Unique identifier of the SSH user session on the host | | [`ptrace.tracee.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`ptrace.tracee.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`ptrace.tracee.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`ptrace.tracee.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`ptrace.tracee.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`ptrace.tracee.uid`](#common-credentials-uid-doc) | UID of the process | @@ -1989,6 +1997,7 @@ A setrlimit command was executed | [`setrlimit.target.ancestors.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`setrlimit.target.ancestors.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`setrlimit.target.ancestors.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`setrlimit.target.ancestors.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`setrlimit.target.ancestors.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`setrlimit.target.ancestors.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`setrlimit.target.ancestors.uid`](#common-credentials-uid-doc) | UID of the process | @@ -2193,6 +2202,7 @@ A setrlimit command was executed | [`setrlimit.target.parent.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`setrlimit.target.parent.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`setrlimit.target.parent.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`setrlimit.target.parent.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`setrlimit.target.parent.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`setrlimit.target.parent.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`setrlimit.target.parent.uid`](#common-credentials-uid-doc) | UID of the process | @@ -2211,6 +2221,7 @@ A setrlimit command was executed | [`setrlimit.target.parent.user_session.ssh_session_id`](#common-sshsessioncontext-ssh_session_id-doc) | Unique identifier of the SSH user session on the host | | [`setrlimit.target.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`setrlimit.target.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`setrlimit.target.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`setrlimit.target.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`setrlimit.target.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`setrlimit.target.uid`](#common-credentials-uid-doc) | UID of the process | @@ -2400,6 +2411,7 @@ A signal was sent | [`signal.target.ancestors.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`signal.target.ancestors.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`signal.target.ancestors.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`signal.target.ancestors.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`signal.target.ancestors.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`signal.target.ancestors.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`signal.target.ancestors.uid`](#common-credentials-uid-doc) | UID of the process | @@ -2604,6 +2616,7 @@ A signal was sent | [`signal.target.parent.netns`](#common-pidcontext-netns-doc) | NetNS ID of the process | | [`signal.target.parent.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`signal.target.parent.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`signal.target.parent.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`signal.target.parent.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`signal.target.parent.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`signal.target.parent.uid`](#common-credentials-uid-doc) | UID of the process | @@ -2622,6 +2635,7 @@ A signal was sent | [`signal.target.parent.user_session.ssh_session_id`](#common-sshsessioncontext-ssh_session_id-doc) | Unique identifier of the SSH user session on the host | | [`signal.target.pid`](#common-pidcontext-pid-doc) | Process ID of the process (also called thread group ID) | | [`signal.target.ppid`](#common-pidcontext-ppid-doc) | Parent process ID | +| [`signal.target.sid`](#common-pidcontext-sid-doc) | Session ID of the process | | [`signal.target.tid`](#common-pidcontext-tid-doc) | Thread ID of the thread | | [`signal.target.tty_name`](#common-process-tty_name-doc) | Name of the TTY associated with the process | | [`signal.target.uid`](#common-credentials-uid-doc) | UID of the process | @@ -3618,6 +3632,15 @@ Definition: Type of the user session `exec.user_session` `exit.user_session` `process.ancestors.user_session` `process.parent.user_session` `process.user_session` `ptrace.tracee.ancestors.user_session` `ptrace.tracee.parent.user_session` `ptrace.tracee.user_session` `setrlimit.target.ancestors.user_session` `setrlimit.target.parent.user_session` `setrlimit.target.user_session` `signal.target.ancestors.user_session` `signal.target.parent.user_session` `signal.target.user_session` +### `*.sid` {#common-pidcontext-sid-doc} +Type: int + +Definition: Session ID of the process + +`*.sid` has 14 possible prefixes: +`exec` `exit` `process` `process.ancestors` `process.parent` `ptrace.tracee` `ptrace.tracee.ancestors` `ptrace.tracee.parent` `setrlimit.target` `setrlimit.target.ancestors` `setrlimit.target.parent` `signal.target` `signal.target.ancestors` `signal.target.parent` + + ### `*.size` {#common-networkcontext-size-doc} Type: int diff --git a/docs/cloud-workload-security/secl_linux.json b/docs/cloud-workload-security/secl_linux.json index 9c04d0af18fb..6a04574ede4b 100644 --- a/docs/cloud-workload-security/secl_linux.json +++ b/docs/cloud-workload-security/secl_linux.json @@ -532,6 +532,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "process.ancestors.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "process.ancestors.tid", "definition": "Thread ID of the thread", @@ -1552,6 +1557,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "process.parent.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "process.parent.tid", "definition": "Thread ID of the thread", @@ -1642,6 +1652,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "process.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "process.tid", "definition": "Thread ID of the thread", @@ -3255,6 +3270,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "exec.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "exec.syscall.path", "definition": "path argument of the syscall", @@ -3834,6 +3854,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "exit.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "exit.tid", "definition": "Thread ID of the thread", @@ -5842,6 +5867,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "ptrace.tracee.ancestors.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "ptrace.tracee.ancestors.tid", "definition": "Thread ID of the thread", @@ -6862,6 +6892,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "ptrace.tracee.parent.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "ptrace.tracee.parent.tid", "definition": "Thread ID of the thread", @@ -6952,6 +6987,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "ptrace.tracee.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "ptrace.tracee.tid", "definition": "Thread ID of the thread", @@ -8216,6 +8256,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "setrlimit.target.ancestors.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "setrlimit.target.ancestors.tid", "definition": "Thread ID of the thread", @@ -9236,6 +9281,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "setrlimit.target.parent.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "setrlimit.target.parent.tid", "definition": "Thread ID of the thread", @@ -9326,6 +9376,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "setrlimit.target.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "setrlimit.target.tid", "definition": "Thread ID of the thread", @@ -10167,6 +10222,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "signal.target.ancestors.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "signal.target.ancestors.tid", "definition": "Thread ID of the thread", @@ -11187,6 +11247,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "signal.target.parent.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "signal.target.parent.tid", "definition": "Thread ID of the thread", @@ -11277,6 +11342,11 @@ "definition": "Parent process ID", "property_doc_link": "common-pidcontext-ppid-doc" }, + { + "name": "signal.target.sid", + "definition": "Session ID of the process", + "property_doc_link": "common-pidcontext-sid-doc" + }, { "name": "signal.target.tid", "definition": "Thread ID of the thread", @@ -14735,6 +14805,31 @@ "constants_link": "", "examples": [] }, + { + "name": "*.sid", + "link": "common-pidcontext-sid-doc", + "type": "int", + "definition": "Session ID of the process", + "prefixes": [ + "exec", + "exit", + "process", + "process.ancestors", + "process.parent", + "ptrace.tracee", + "ptrace.tracee.ancestors", + "ptrace.tracee.parent", + "setrlimit.target", + "setrlimit.target.ancestors", + "setrlimit.target.parent", + "signal.target", + "signal.target.ancestors", + "signal.target.parent" + ], + "constants": "", + "constants_link": "", + "examples": [] + }, { "name": "*.size", "link": "common-networkcontext-size-doc", diff --git a/pkg/security/ebpf/c/include/constants/enums.h b/pkg/security/ebpf/c/include/constants/enums.h index cf49c639b206..2d438af28abd 100644 --- a/pkg/security/ebpf/c/include/constants/enums.h +++ b/pkg/security/ebpf/c/include/constants/enums.h @@ -75,6 +75,7 @@ enum event_type EVENT_TRACER_MEMFD_CREATE, EVENT_TRACER_MEMFD_SEAL, EVENT_PIVOT_ROOT, + EVENT_SETSID, EVENT_NOP, EVENT_MAX, // has to be the last one diff --git a/pkg/security/ebpf/c/include/helpers/process.h b/pkg/security/ebpf/c/include/helpers/process.h index 4d9b331c617a..14e20822f4ca 100644 --- a/pkg/security/ebpf/c/include/helpers/process.h +++ b/pkg/security/ebpf/c/include/helpers/process.h @@ -41,6 +41,7 @@ void __attribute__((always_inline)) copy_pid_cache_except_exit_ts(struct pid_cac dst->user_session_id = src->user_session_id; dst->fork_timestamp = src->fork_timestamp; dst->fork_flags = src->fork_flags; + dst->sid = src->sid; dst->credentials = src->credentials; } @@ -110,8 +111,9 @@ static struct proc_cache_t *__attribute__((always_inline)) fill_process_context_ return NULL; } - // copy user session id + // copy user session id and sid data->user_session_id = pid_entry->user_session_id; + data->sid = pid_entry->sid; struct proc_cache_t *pc = get_proc_from_cookie(pid_entry->cookie); if (pc) { diff --git a/pkg/security/ebpf/c/include/hooks/all.h b/pkg/security/ebpf/c/include/hooks/all.h index d2fd43afc2d9..d8a6ad6d0fa4 100644 --- a/pkg/security/ebpf/c/include/hooks/all.h +++ b/pkg/security/ebpf/c/include/hooks/all.h @@ -38,6 +38,7 @@ #include "on_demand.h" #include "chdir.h" #include "setrlimit.h" +#include "setsid.h" #include "caps.h" #include "prctl.h" #include "memfd.h" diff --git a/pkg/security/ebpf/c/include/hooks/exec.h b/pkg/security/ebpf/c/include/hooks/exec.h index ab9bf11b95a3..20ed7e319132 100644 --- a/pkg/security/ebpf/c/include/hooks/exec.h +++ b/pkg/security/ebpf/c/include/hooks/exec.h @@ -250,6 +250,9 @@ int __attribute__((always_inline)) sched_process_fork_common(void *ctx, u32 pid, // ensure pid and ppid have the same credentials event->pid_entry.credentials = parent_pid_entry->credentials; + // inherit session id from parent + event->pid_entry.sid = parent_pid_entry->sid; + // fetch the parent proc cache entry u64 on_stack_cookie = event->pid_entry.cookie; struct proc_cache_t *parent_pc = get_proc_from_cookie(on_stack_cookie); diff --git a/pkg/security/ebpf/c/include/hooks/setsid.h b/pkg/security/ebpf/c/include/hooks/setsid.h new file mode 100644 index 000000000000..193f5491912f --- /dev/null +++ b/pkg/security/ebpf/c/include/hooks/setsid.h @@ -0,0 +1,42 @@ +#ifndef _HOOKS_SETSID_H_ +#define _HOOKS_SETSID_H_ + +#include "constants/syscall_macro.h" +#include "helpers/syscalls.h" + +static int __attribute__((always_inline)) sys_set_sid_ret(void *ctx, int retval) { + if (pop_syscall(EVENT_SETSID) == NULL) { + return 0; + } + if (retval < 0) { + return 0; + } + // After a successful setsid(2), the calling task is the new session leader, + // so its session ID equals its (host-namespace) PID by definition. + u32 pid = bpf_get_current_pid_tgid() >> 32; + struct pid_cache_t *pid_entry = (struct pid_cache_t *)bpf_map_lookup_elem(&pid_cache, &pid); + if (!pid_entry) { + return 0; + } + pid_entry->sid = pid; + return 0; +} + +HOOK_SYSCALL_ENTRY0(setsid) { + struct syscall_cache_t syscall = { + .type = EVENT_SETSID, + }; + cache_syscall(&syscall); + return 0; +} + +TAIL_CALL_TRACEPOINT_FNC(handle_sys_setsid_exit, struct tracepoint_raw_syscalls_sys_exit_t *args) { + return sys_set_sid_ret(args, args->ret); +} + +HOOK_SYSCALL_EXIT(setsid) { + int retval = (int)SYSCALL_PARMRET(ctx); + return sys_set_sid_ret(ctx, retval); +} + +#endif diff --git a/pkg/security/ebpf/c/include/structs/events_context.h b/pkg/security/ebpf/c/include/structs/events_context.h index f4a39354d5ab..24f1ed7fd49e 100644 --- a/pkg/security/ebpf/c/include/structs/events_context.h +++ b/pkg/security/ebpf/c/include/structs/events_context.h @@ -31,6 +31,8 @@ struct process_context_t { u32 mntns; u32 is_kworker; u32 ppid; + u32 sid; + u32 padding_sid; u64 inode; u64 user_session_id; }; diff --git a/pkg/security/ebpf/c/include/structs/process.h b/pkg/security/ebpf/c/include/structs/process.h index 1339f80ef503..758d231ad5e6 100644 --- a/pkg/security/ebpf/c/include/structs/process.h +++ b/pkg/security/ebpf/c/include/structs/process.h @@ -37,6 +37,8 @@ struct pid_cache_t { u64 exit_timestamp; u64 user_session_id; u64 fork_flags; + u32 sid; + u32 padding_sid; struct credentials_t credentials; }; diff --git a/pkg/security/ebpf/probes/all.go b/pkg/security/ebpf/probes/all.go index e0f0f8638871..6b7bd8f8d71b 100644 --- a/pkg/security/ebpf/probes/all.go +++ b/pkg/security/ebpf/probes/all.go @@ -119,6 +119,7 @@ func AllProbes(fentry bool, cgroup2MountPoint string) []*manager.Probe { allProbes = append(allProbes, getPrCtlProbes(fentry)...) allProbes = append(allProbes, getSocketProbes(cgroup2MountPoint)...) allProbes = append(allProbes, getMemfdProbes(fentry)...) + allProbes = appendSyscallProbes(allProbes, fentry, EntryAndExit, false, "setsid") allProbes = append(allProbes, &manager.Probe{ diff --git a/pkg/security/ebpf/probes/event_types.go b/pkg/security/ebpf/probes/event_types.go index 4b4bedcaefbc..98b88e259672 100644 --- a/pkg/security/ebpf/probes/event_types.go +++ b/pkg/security/ebpf/probes/event_types.go @@ -209,6 +209,7 @@ func GetSelectorsPerEventType(hasFentry bool, hasCgroupSocket bool) map[eval.Eve &manager.BestEffort{Selectors: ExpandSyscallProbesSelector(SecurityAgentUID, "setresgid", hasFentry, EntryAndExit)}, &manager.BestEffort{Selectors: ExpandSyscallProbesSelector(SecurityAgentUID, "setresgid16", hasFentry, EntryAndExit)}, &manager.BestEffort{Selectors: ExpandSyscallProbesSelector(SecurityAgentUID, "capset", hasFentry, EntryAndExit)}, + &manager.BestEffort{Selectors: ExpandSyscallProbesSelector(SecurityAgentUID, "setsid", hasFentry, EntryAndExit)}, // File Attributes hookFunc("hook_security_inode_setattr"), diff --git a/pkg/security/ebpf/probes/raw_sys_exit.go b/pkg/security/ebpf/probes/raw_sys_exit.go index 4acefd8007de..5cae59db962d 100644 --- a/pkg/security/ebpf/probes/raw_sys_exit.go +++ b/pkg/security/ebpf/probes/raw_sys_exit.go @@ -233,5 +233,12 @@ func getSysExitTailCallRoutes() []manager.TailCallRoute { EBPFFuncName: tailCallTracepointFnc("handle_sys_pivot_root_exit"), }, }, + { + ProgArrayName: "sys_exit_progs", + Key: uint32(model.SetSidEventType), + ProbeIdentificationPair: manager.ProbeIdentificationPair{ + EBPFFuncName: tailCallTracepointFnc("handle_sys_setsid_exit"), + }, + }, } } diff --git a/pkg/security/ebpf/probes/rawpacket/pcap.go b/pkg/security/ebpf/probes/rawpacket/pcap.go index 1597e12d7fbe..892b1e162bbd 100644 --- a/pkg/security/ebpf/probes/rawpacket/pcap.go +++ b/pkg/security/ebpf/probes/rawpacket/pcap.go @@ -33,8 +33,8 @@ const ( // raw packet data, see kernel definition // pahole /opt/datadog-agent/embedded/share/system-probe/ebpf/runtime-security-syscall-wrapper.o -y raw_packet_event_t -E --structs -V structRawPacketEventPidOffset = 16 - structRawPacketEventCgroupIdOffset = 80 - structRawPacketEventDataOffset = 108 + structRawPacketEventCgroupIdOffset = 88 + structRawPacketEventDataOffset = 116 // payload size structRawPacketEventDataSize = 256 diff --git a/pkg/security/probe/probe_ebpf.go b/pkg/security/probe/probe_ebpf.go index 75ab4de80be1..c65030e25a61 100644 --- a/pkg/security/probe/probe_ebpf.go +++ b/pkg/security/probe/probe_ebpf.go @@ -1137,6 +1137,12 @@ func (p *EBPFProbe) setProcessContext(eventType model.EventType, event *model.Ev p.Resolvers.ProcessResolver.TryReparentFromKernelPPid(entry, event.PIDContext.PPid, newEntryCb) } + // If the kernel reports a different SID than the one in our + // cache, the process called setsid(). Update the cache entry. + if event.PIDContext.SID != 0 { + entry.SID = event.PIDContext.SID + } + // Attempt to repair the lineage of processes that were orphaned // during subreaper reparenting (the exit tracepoint may fire // before the kernel has completed forget_original_parent). diff --git a/pkg/security/resolvers/process/resolver_ebpf.go b/pkg/security/resolvers/process/resolver_ebpf.go index 5e08b6a148a3..3d630b423c1c 100644 --- a/pkg/security/resolvers/process/resolver_ebpf.go +++ b/pkg/security/resolvers/process/resolver_ebpf.go @@ -657,6 +657,7 @@ func (p *EBPFResolver) enrichEventFromProcfs(entry *model.ProcessCacheEntry, pro entry.ForkTime = entry.ExecTime entry.Comm = filledProc.Name entry.PPid = uint32(filledProc.Ppid) + entry.SID = utils.PidSID(uint32(filledProc.Pid)) entry.TTYName = utils.PidTTY(uint32(filledProc.Pid)) entry.ProcessContext.Pid = pid entry.ProcessContext.Tid = pid diff --git a/pkg/security/secl/model/accessors_unix.go b/pkg/security/secl/model/accessors_unix.go index 7e8c3bceed44..487d3149e2b8 100644 --- a/pkg/security/secl/model/accessors_unix.go +++ b/pkg/security/secl/model/accessors_unix.go @@ -3400,6 +3400,17 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "exec.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + return int(ev.Exec.Process.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "exec.syscall.path": return &eval.StringEvaluator{ EvalFnc: func(ctx *eval.Context) string { @@ -4814,6 +4825,17 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "exit.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + return int(ev.Exit.Process.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "exit.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -11038,6 +11060,33 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.IteratorWeight, Offset: offset, }, nil + case "process.ancestors.sid": + return &eval.IntArrayEvaluator{ + EvalFnc: func(ctx *eval.Context) []int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + iterator := &ProcessAncestorsIterator{Root: ev.BaseEvent.ProcessContext.Ancestor} + if regID != "" { + element := iterator.At(ctx, regID, ctx.Registers[regID]) + if element == nil { + return nil + } + result := int(element.ProcessContext.Process.PIDContext.SID) + return []int{result} + } + if result, ok := ctx.IntCache[field]; ok { + return result + } + results := newIterator(iterator, "BaseEvent.ProcessContext.Ancestor", ctx, nil, func(ev *Event, current *ProcessCacheEntry) int { + return int(current.ProcessContext.Process.PIDContext.SID) + }) + ctx.IntCache[field] = results + return results + }, + Field: field, + Weight: eval.IteratorWeight, + Offset: offset, + }, nil case "process.ancestors.tid": return &eval.IntArrayEvaluator{ EvalFnc: func(ctx *eval.Context) []int { @@ -14131,6 +14180,20 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "process.parent.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + if !ev.BaseEvent.ProcessContext.HasParent() { + return 0 + } + return int(ev.BaseEvent.ProcessContext.Parent.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "process.parent.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -14377,6 +14440,17 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "process.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + return int(ev.BaseEvent.ProcessContext.Process.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "process.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -17461,6 +17535,33 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.IteratorWeight, Offset: offset, }, nil + case "ptrace.tracee.ancestors.sid": + return &eval.IntArrayEvaluator{ + EvalFnc: func(ctx *eval.Context) []int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + iterator := &ProcessAncestorsIterator{Root: ev.PTrace.Tracee.Ancestor} + if regID != "" { + element := iterator.At(ctx, regID, ctx.Registers[regID]) + if element == nil { + return nil + } + result := int(element.ProcessContext.Process.PIDContext.SID) + return []int{result} + } + if result, ok := ctx.IntCache[field]; ok { + return result + } + results := newIterator(iterator, "PTrace.Tracee.Ancestor", ctx, nil, func(ev *Event, current *ProcessCacheEntry) int { + return int(current.ProcessContext.Process.PIDContext.SID) + }) + ctx.IntCache[field] = results + return results + }, + Field: field, + Weight: eval.IteratorWeight, + Offset: offset, + }, nil case "ptrace.tracee.ancestors.tid": return &eval.IntArrayEvaluator{ EvalFnc: func(ctx *eval.Context) []int { @@ -20554,6 +20655,20 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "ptrace.tracee.parent.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + if !ev.PTrace.Tracee.HasParent() { + return 0 + } + return int(ev.PTrace.Tracee.Parent.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "ptrace.tracee.parent.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -20800,6 +20915,17 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "ptrace.tracee.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + return int(ev.PTrace.Tracee.Process.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "ptrace.tracee.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -25312,6 +25438,33 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.IteratorWeight, Offset: offset, }, nil + case "setrlimit.target.ancestors.sid": + return &eval.IntArrayEvaluator{ + EvalFnc: func(ctx *eval.Context) []int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + iterator := &ProcessAncestorsIterator{Root: ev.Setrlimit.Target.Ancestor} + if regID != "" { + element := iterator.At(ctx, regID, ctx.Registers[regID]) + if element == nil { + return nil + } + result := int(element.ProcessContext.Process.PIDContext.SID) + return []int{result} + } + if result, ok := ctx.IntCache[field]; ok { + return result + } + results := newIterator(iterator, "Setrlimit.Target.Ancestor", ctx, nil, func(ev *Event, current *ProcessCacheEntry) int { + return int(current.ProcessContext.Process.PIDContext.SID) + }) + ctx.IntCache[field] = results + return results + }, + Field: field, + Weight: eval.IteratorWeight, + Offset: offset, + }, nil case "setrlimit.target.ancestors.tid": return &eval.IntArrayEvaluator{ EvalFnc: func(ctx *eval.Context) []int { @@ -28405,6 +28558,20 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "setrlimit.target.parent.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + if !ev.Setrlimit.Target.HasParent() { + return 0 + } + return int(ev.Setrlimit.Target.Parent.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "setrlimit.target.parent.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -28651,6 +28818,17 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "setrlimit.target.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + return int(ev.Setrlimit.Target.Process.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "setrlimit.target.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -32257,6 +32435,33 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.IteratorWeight, Offset: offset, }, nil + case "signal.target.ancestors.sid": + return &eval.IntArrayEvaluator{ + EvalFnc: func(ctx *eval.Context) []int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + iterator := &ProcessAncestorsIterator{Root: ev.Signal.Target.Ancestor} + if regID != "" { + element := iterator.At(ctx, regID, ctx.Registers[regID]) + if element == nil { + return nil + } + result := int(element.ProcessContext.Process.PIDContext.SID) + return []int{result} + } + if result, ok := ctx.IntCache[field]; ok { + return result + } + results := newIterator(iterator, "Signal.Target.Ancestor", ctx, nil, func(ev *Event, current *ProcessCacheEntry) int { + return int(current.ProcessContext.Process.PIDContext.SID) + }) + ctx.IntCache[field] = results + return results + }, + Field: field, + Weight: eval.IteratorWeight, + Offset: offset, + }, nil case "signal.target.ancestors.tid": return &eval.IntArrayEvaluator{ EvalFnc: func(ctx *eval.Context) []int { @@ -35350,6 +35555,20 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "signal.target.parent.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + if !ev.Signal.Target.HasParent() { + return 0 + } + return int(ev.Signal.Target.Parent.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "signal.target.parent.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -35596,6 +35815,17 @@ func (_ *Model) GetEvaluator(field eval.Field, regID eval.RegisterID, offset int Weight: eval.FunctionWeight, Offset: offset, }, nil + case "signal.target.sid": + return &eval.IntEvaluator{ + EvalFnc: func(ctx *eval.Context) int { + ctx.AppendResolvedField(field) + ev := ctx.Event.(*Event) + return int(ev.Signal.Target.Process.PIDContext.SID) + }, + Field: field, + Weight: eval.FunctionWeight, + Offset: offset, + }, nil case "signal.target.tid": return &eval.IntEvaluator{ EvalFnc: func(ctx *eval.Context) int { @@ -37195,6 +37425,7 @@ func (ev *Event) GetFields() []eval.Field { "exec.netns", "exec.pid", "exec.ppid", + "exec.sid", "exec.syscall.path", "exec.tid", "exec.tty_name", @@ -37309,6 +37540,7 @@ func (ev *Event) GetFields() []eval.Field { "exit.netns", "exit.pid", "exit.ppid", + "exit.sid", "exit.tid", "exit.tty_name", "exit.uid", @@ -37687,6 +37919,7 @@ func (ev *Event) GetFields() []eval.Field { "process.ancestors.netns", "process.ancestors.pid", "process.ancestors.ppid", + "process.ancestors.sid", "process.ancestors.tid", "process.ancestors.tty_name", "process.ancestors.uid", @@ -37891,6 +38124,7 @@ func (ev *Event) GetFields() []eval.Field { "process.parent.netns", "process.parent.pid", "process.parent.ppid", + "process.parent.sid", "process.parent.tid", "process.parent.tty_name", "process.parent.uid", @@ -37909,6 +38143,7 @@ func (ev *Event) GetFields() []eval.Field { "process.parent.user_session.ssh_session_id", "process.pid", "process.ppid", + "process.sid", "process.tid", "process.tty_name", "process.uid", @@ -38023,6 +38258,7 @@ func (ev *Event) GetFields() []eval.Field { "ptrace.tracee.ancestors.netns", "ptrace.tracee.ancestors.pid", "ptrace.tracee.ancestors.ppid", + "ptrace.tracee.ancestors.sid", "ptrace.tracee.ancestors.tid", "ptrace.tracee.ancestors.tty_name", "ptrace.tracee.ancestors.uid", @@ -38227,6 +38463,7 @@ func (ev *Event) GetFields() []eval.Field { "ptrace.tracee.parent.netns", "ptrace.tracee.parent.pid", "ptrace.tracee.parent.ppid", + "ptrace.tracee.parent.sid", "ptrace.tracee.parent.tid", "ptrace.tracee.parent.tty_name", "ptrace.tracee.parent.uid", @@ -38245,6 +38482,7 @@ func (ev *Event) GetFields() []eval.Field { "ptrace.tracee.parent.user_session.ssh_session_id", "ptrace.tracee.pid", "ptrace.tracee.ppid", + "ptrace.tracee.sid", "ptrace.tracee.tid", "ptrace.tracee.tty_name", "ptrace.tracee.uid", @@ -38487,6 +38725,7 @@ func (ev *Event) GetFields() []eval.Field { "setrlimit.target.ancestors.netns", "setrlimit.target.ancestors.pid", "setrlimit.target.ancestors.ppid", + "setrlimit.target.ancestors.sid", "setrlimit.target.ancestors.tid", "setrlimit.target.ancestors.tty_name", "setrlimit.target.ancestors.uid", @@ -38691,6 +38930,7 @@ func (ev *Event) GetFields() []eval.Field { "setrlimit.target.parent.netns", "setrlimit.target.parent.pid", "setrlimit.target.parent.ppid", + "setrlimit.target.parent.sid", "setrlimit.target.parent.tid", "setrlimit.target.parent.tty_name", "setrlimit.target.parent.uid", @@ -38709,6 +38949,7 @@ func (ev *Event) GetFields() []eval.Field { "setrlimit.target.parent.user_session.ssh_session_id", "setrlimit.target.pid", "setrlimit.target.ppid", + "setrlimit.target.sid", "setrlimit.target.tid", "setrlimit.target.tty_name", "setrlimit.target.uid", @@ -38870,6 +39111,7 @@ func (ev *Event) GetFields() []eval.Field { "signal.target.ancestors.netns", "signal.target.ancestors.pid", "signal.target.ancestors.ppid", + "signal.target.ancestors.sid", "signal.target.ancestors.tid", "signal.target.ancestors.tty_name", "signal.target.ancestors.uid", @@ -39074,6 +39316,7 @@ func (ev *Event) GetFields() []eval.Field { "signal.target.parent.netns", "signal.target.parent.pid", "signal.target.parent.ppid", + "signal.target.parent.sid", "signal.target.parent.tid", "signal.target.parent.tty_name", "signal.target.parent.uid", @@ -39092,6 +39335,7 @@ func (ev *Event) GetFields() []eval.Field { "signal.target.parent.user_session.ssh_session_id", "signal.target.pid", "signal.target.ppid", + "signal.target.sid", "signal.target.tid", "signal.target.tty_name", "signal.target.uid", @@ -39789,6 +40033,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "exec", reflect.Int, "int", false, nil case "exec.ppid": return "exec", reflect.Int, "int", false, nil + case "exec.sid": + return "exec", reflect.Int, "int", false, nil case "exec.syscall.path": return "exec", reflect.String, "string", false, nil case "exec.tid": @@ -40017,6 +40263,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "exit", reflect.Int, "int", false, nil case "exit.ppid": return "exit", reflect.Int, "int", false, nil + case "exit.sid": + return "exit", reflect.Int, "int", false, nil case "exit.tid": return "exit", reflect.Int, "int", false, nil case "exit.tty_name": @@ -40773,6 +41021,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "", reflect.Int, "int", false, nil case "process.ancestors.ppid": return "", reflect.Int, "int", false, nil + case "process.ancestors.sid": + return "", reflect.Int, "int", false, nil case "process.ancestors.tid": return "", reflect.Int, "int", false, nil case "process.ancestors.tty_name": @@ -41181,6 +41431,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "", reflect.Int, "int", false, nil case "process.parent.ppid": return "", reflect.Int, "int", false, nil + case "process.parent.sid": + return "", reflect.Int, "int", false, nil case "process.parent.tid": return "", reflect.Int, "int", false, nil case "process.parent.tty_name": @@ -41217,6 +41469,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "", reflect.Int, "int", false, nil case "process.ppid": return "", reflect.Int, "int", false, nil + case "process.sid": + return "", reflect.Int, "int", false, nil case "process.tid": return "", reflect.Int, "int", false, nil case "process.tty_name": @@ -41445,6 +41699,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.ancestors.ppid": return "ptrace", reflect.Int, "int", false, nil + case "ptrace.tracee.ancestors.sid": + return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.ancestors.tid": return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.ancestors.tty_name": @@ -41853,6 +42109,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.parent.ppid": return "ptrace", reflect.Int, "int", false, nil + case "ptrace.tracee.parent.sid": + return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.parent.tid": return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.parent.tty_name": @@ -41889,6 +42147,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.ppid": return "ptrace", reflect.Int, "int", false, nil + case "ptrace.tracee.sid": + return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.tid": return "ptrace", reflect.Int, "int", false, nil case "ptrace.tracee.tty_name": @@ -42373,6 +42633,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.ancestors.ppid": return "setrlimit", reflect.Int, "int", false, nil + case "setrlimit.target.ancestors.sid": + return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.ancestors.tid": return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.ancestors.tty_name": @@ -42781,6 +43043,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.parent.ppid": return "setrlimit", reflect.Int, "int", false, nil + case "setrlimit.target.parent.sid": + return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.parent.tid": return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.parent.tty_name": @@ -42817,6 +43081,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.ppid": return "setrlimit", reflect.Int, "int", false, nil + case "setrlimit.target.sid": + return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.tid": return "setrlimit", reflect.Int, "int", false, nil case "setrlimit.target.tty_name": @@ -43139,6 +43405,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "signal", reflect.Int, "int", false, nil case "signal.target.ancestors.ppid": return "signal", reflect.Int, "int", false, nil + case "signal.target.ancestors.sid": + return "signal", reflect.Int, "int", false, nil case "signal.target.ancestors.tid": return "signal", reflect.Int, "int", false, nil case "signal.target.ancestors.tty_name": @@ -43547,6 +43815,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "signal", reflect.Int, "int", false, nil case "signal.target.parent.ppid": return "signal", reflect.Int, "int", false, nil + case "signal.target.parent.sid": + return "signal", reflect.Int, "int", false, nil case "signal.target.parent.tid": return "signal", reflect.Int, "int", false, nil case "signal.target.parent.tty_name": @@ -43583,6 +43853,8 @@ func (ev *Event) GetFieldMetadata(field eval.Field) (eval.EventType, reflect.Kin return "signal", reflect.Int, "int", false, nil case "signal.target.ppid": return "signal", reflect.Int, "int", false, nil + case "signal.target.sid": + return "signal", reflect.Int, "int", false, nil case "signal.target.tid": return "signal", reflect.Int, "int", false, nil case "signal.target.tty_name": @@ -44532,6 +44804,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("exec.pid", &ev.Exec.Process.PIDContext.Pid, value) case "exec.ppid": return ev.setUint32FieldValue("exec.ppid", &ev.Exec.Process.PIDContext.PPid, value) + case "exec.sid": + return ev.setUint32FieldValue("exec.sid", &ev.Exec.Process.PIDContext.SID, value) case "exec.syscall.path": return ev.setStringFieldValue("exec.syscall.path", &ev.Exec.SyscallContext.StrArg1, value) case "exec.tid": @@ -44875,6 +45149,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("exit.pid", &ev.Exit.Process.PIDContext.Pid, value) case "exit.ppid": return ev.setUint32FieldValue("exit.ppid", &ev.Exit.Process.PIDContext.PPid, value) + case "exit.sid": + return ev.setUint32FieldValue("exit.sid", &ev.Exit.Process.PIDContext.SID, value) case "exit.tid": return ev.setUint32FieldValue("exit.tid", &ev.Exit.Process.PIDContext.Tid, value) case "exit.tty_name": @@ -45812,6 +46088,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("process.ancestors.pid", &ev.BaseEvent.ProcessContext.Ancestor.ProcessContext.Process.PIDContext.Pid, value) case "process.ancestors.ppid": return ev.setUint32FieldValue("process.ancestors.ppid", &ev.BaseEvent.ProcessContext.Ancestor.ProcessContext.Process.PIDContext.PPid, value) + case "process.ancestors.sid": + return ev.setUint32FieldValue("process.ancestors.sid", &ev.BaseEvent.ProcessContext.Ancestor.ProcessContext.Process.PIDContext.SID, value) case "process.ancestors.tid": return ev.setUint32FieldValue("process.ancestors.tid", &ev.BaseEvent.ProcessContext.Ancestor.ProcessContext.Process.PIDContext.Tid, value) case "process.ancestors.tty_name": @@ -46445,6 +46723,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("process.parent.pid", &ev.BaseEvent.ProcessContext.Parent.PIDContext.Pid, value) case "process.parent.ppid": return ev.setUint32FieldValue("process.parent.ppid", &ev.BaseEvent.ProcessContext.Parent.PIDContext.PPid, value) + case "process.parent.sid": + return ev.setUint32FieldValue("process.parent.sid", &ev.BaseEvent.ProcessContext.Parent.PIDContext.SID, value) case "process.parent.tid": return ev.setUint32FieldValue("process.parent.tid", &ev.BaseEvent.ProcessContext.Parent.PIDContext.Tid, value) case "process.parent.tty_name": @@ -46486,6 +46766,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("process.pid", &ev.BaseEvent.ProcessContext.Process.PIDContext.Pid, value) case "process.ppid": return ev.setUint32FieldValue("process.ppid", &ev.BaseEvent.ProcessContext.Process.PIDContext.PPid, value) + case "process.sid": + return ev.setUint32FieldValue("process.sid", &ev.BaseEvent.ProcessContext.Process.PIDContext.SID, value) case "process.tid": return ev.setUint32FieldValue("process.tid", &ev.BaseEvent.ProcessContext.Process.PIDContext.Tid, value) case "process.tty_name": @@ -46829,6 +47111,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("ptrace.tracee.ancestors.pid", &ev.PTrace.Tracee.Ancestor.ProcessContext.Process.PIDContext.Pid, value) case "ptrace.tracee.ancestors.ppid": return ev.setUint32FieldValue("ptrace.tracee.ancestors.ppid", &ev.PTrace.Tracee.Ancestor.ProcessContext.Process.PIDContext.PPid, value) + case "ptrace.tracee.ancestors.sid": + return ev.setUint32FieldValue("ptrace.tracee.ancestors.sid", &ev.PTrace.Tracee.Ancestor.ProcessContext.Process.PIDContext.SID, value) case "ptrace.tracee.ancestors.tid": return ev.setUint32FieldValue("ptrace.tracee.ancestors.tid", &ev.PTrace.Tracee.Ancestor.ProcessContext.Process.PIDContext.Tid, value) case "ptrace.tracee.ancestors.tty_name": @@ -47462,6 +47746,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("ptrace.tracee.parent.pid", &ev.PTrace.Tracee.Parent.PIDContext.Pid, value) case "ptrace.tracee.parent.ppid": return ev.setUint32FieldValue("ptrace.tracee.parent.ppid", &ev.PTrace.Tracee.Parent.PIDContext.PPid, value) + case "ptrace.tracee.parent.sid": + return ev.setUint32FieldValue("ptrace.tracee.parent.sid", &ev.PTrace.Tracee.Parent.PIDContext.SID, value) case "ptrace.tracee.parent.tid": return ev.setUint32FieldValue("ptrace.tracee.parent.tid", &ev.PTrace.Tracee.Parent.PIDContext.Tid, value) case "ptrace.tracee.parent.tty_name": @@ -47503,6 +47789,8 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { return ev.setUint32FieldValue("ptrace.tracee.pid", &ev.PTrace.Tracee.Process.PIDContext.Pid, value) case "ptrace.tracee.ppid": return ev.setUint32FieldValue("ptrace.tracee.ppid", &ev.PTrace.Tracee.Process.PIDContext.PPid, value) + case "ptrace.tracee.sid": + return ev.setUint32FieldValue("ptrace.tracee.sid", &ev.PTrace.Tracee.Process.PIDContext.SID, value) case "ptrace.tracee.tid": return ev.setUint32FieldValue("ptrace.tracee.tid", &ev.PTrace.Tracee.Process.PIDContext.Tid, value) case "ptrace.tracee.tty_name": @@ -48678,6 +48966,14 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { ev.Setrlimit.Target.Ancestor = &ProcessCacheEntry{} } return ev.setUint32FieldValue("setrlimit.target.ancestors.ppid", &ev.Setrlimit.Target.Ancestor.ProcessContext.Process.PIDContext.PPid, value) + case "setrlimit.target.ancestors.sid": + if ev.Setrlimit.Target == nil { + ev.Setrlimit.Target = &ProcessContext{} + } + if ev.Setrlimit.Target.Ancestor == nil { + ev.Setrlimit.Target.Ancestor = &ProcessCacheEntry{} + } + return ev.setUint32FieldValue("setrlimit.target.ancestors.sid", &ev.Setrlimit.Target.Ancestor.ProcessContext.Process.PIDContext.SID, value) case "setrlimit.target.ancestors.tid": if ev.Setrlimit.Target == nil { ev.Setrlimit.Target = &ProcessContext{} @@ -50256,6 +50552,14 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { ev.Setrlimit.Target.Parent = &Process{} } return ev.setUint32FieldValue("setrlimit.target.parent.ppid", &ev.Setrlimit.Target.Parent.PIDContext.PPid, value) + case "setrlimit.target.parent.sid": + if ev.Setrlimit.Target == nil { + ev.Setrlimit.Target = &ProcessContext{} + } + if ev.Setrlimit.Target.Parent == nil { + ev.Setrlimit.Target.Parent = &Process{} + } + return ev.setUint32FieldValue("setrlimit.target.parent.sid", &ev.Setrlimit.Target.Parent.PIDContext.SID, value) case "setrlimit.target.parent.tid": if ev.Setrlimit.Target == nil { ev.Setrlimit.Target = &ProcessContext{} @@ -50399,6 +50703,11 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { ev.Setrlimit.Target = &ProcessContext{} } return ev.setUint32FieldValue("setrlimit.target.ppid", &ev.Setrlimit.Target.Process.PIDContext.PPid, value) + case "setrlimit.target.sid": + if ev.Setrlimit.Target == nil { + ev.Setrlimit.Target = &ProcessContext{} + } + return ev.setUint32FieldValue("setrlimit.target.sid", &ev.Setrlimit.Target.Process.PIDContext.SID, value) case "setrlimit.target.tid": if ev.Setrlimit.Target == nil { ev.Setrlimit.Target = &ProcessContext{} @@ -51470,6 +51779,14 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { ev.Signal.Target.Ancestor = &ProcessCacheEntry{} } return ev.setUint32FieldValue("signal.target.ancestors.ppid", &ev.Signal.Target.Ancestor.ProcessContext.Process.PIDContext.PPid, value) + case "signal.target.ancestors.sid": + if ev.Signal.Target == nil { + ev.Signal.Target = &ProcessContext{} + } + if ev.Signal.Target.Ancestor == nil { + ev.Signal.Target.Ancestor = &ProcessCacheEntry{} + } + return ev.setUint32FieldValue("signal.target.ancestors.sid", &ev.Signal.Target.Ancestor.ProcessContext.Process.PIDContext.SID, value) case "signal.target.ancestors.tid": if ev.Signal.Target == nil { ev.Signal.Target = &ProcessContext{} @@ -53048,6 +53365,14 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { ev.Signal.Target.Parent = &Process{} } return ev.setUint32FieldValue("signal.target.parent.ppid", &ev.Signal.Target.Parent.PIDContext.PPid, value) + case "signal.target.parent.sid": + if ev.Signal.Target == nil { + ev.Signal.Target = &ProcessContext{} + } + if ev.Signal.Target.Parent == nil { + ev.Signal.Target.Parent = &Process{} + } + return ev.setUint32FieldValue("signal.target.parent.sid", &ev.Signal.Target.Parent.PIDContext.SID, value) case "signal.target.parent.tid": if ev.Signal.Target == nil { ev.Signal.Target = &ProcessContext{} @@ -53191,6 +53516,11 @@ func (ev *Event) SetFieldValue(field eval.Field, value interface{}) error { ev.Signal.Target = &ProcessContext{} } return ev.setUint32FieldValue("signal.target.ppid", &ev.Signal.Target.Process.PIDContext.PPid, value) + case "signal.target.sid": + if ev.Signal.Target == nil { + ev.Signal.Target = &ProcessContext{} + } + return ev.setUint32FieldValue("signal.target.sid", &ev.Signal.Target.Process.PIDContext.SID, value) case "signal.target.tid": if ev.Signal.Target == nil { ev.Signal.Target = &ProcessContext{} diff --git a/pkg/security/secl/model/event_deep_copy_unix.go b/pkg/security/secl/model/event_deep_copy_unix.go index ba1606a48793..6324a3b8711c 100644 --- a/pkg/security/secl/model/event_deep_copy_unix.go +++ b/pkg/security/secl/model/event_deep_copy_unix.go @@ -192,6 +192,7 @@ func deepCopyPIDContext(fieldToCopy PIDContext) PIDContext { copied.NetNS = fieldToCopy.NetNS copied.PPid = fieldToCopy.PPid copied.Pid = fieldToCopy.Pid + copied.SID = fieldToCopy.SID copied.Tid = fieldToCopy.Tid copied.UserSessionID = fieldToCopy.UserSessionID return copied diff --git a/pkg/security/secl/model/events.go b/pkg/security/secl/model/events.go index fa0abcdf7e0e..7977bb35f34d 100644 --- a/pkg/security/secl/model/events.go +++ b/pkg/security/secl/model/events.go @@ -145,6 +145,8 @@ const ( TracerMemfdSealEventType // PivotRootEventType is sent when pivot_root completes successfully PivotRootEventType + // SetSidEventType is sent when setsid completes successfully + SetSidEventType // NopEventType nop event NopEventType // MaxKernelEventType is used internally to get the maximum number of kernel events. diff --git a/pkg/security/secl/model/marshallers_linux.go b/pkg/security/secl/model/marshallers_linux.go index 936bbde90dc6..1d6defe6a49a 100644 --- a/pkg/security/secl/model/marshallers_linux.go +++ b/pkg/security/secl/model/marshallers_linux.go @@ -14,7 +14,7 @@ import ( const ( // PidCacheEntrySize is the size of the pid_cache_t - PidCacheEntrySize = 88 + PidCacheEntrySize = 96 ) // BinaryMarshaler interface implemented by every event type @@ -147,7 +147,9 @@ func (e *Process) MarshalPidCache(data []byte, bootTime time.Time) (int, error) marshalTime(data[16:24], e.ExitTime.Sub(bootTime)) binary.NativeEndian.PutUint64(data[24:32], e.UserSession.K8SSessionID) binary.NativeEndian.PutUint64(data[32:40], e.ForkFlags) - written := 40 + binary.NativeEndian.PutUint32(data[40:44], e.PIDContext.SID) + binary.NativeEndian.PutUint32(data[44:48], 0) // padding + written := 48 n, err := MarshalBinary(data[written:], &e.Credentials) if err != nil { diff --git a/pkg/security/secl/model/model_unix.go b/pkg/security/secl/model/model_unix.go index 070c6f4a1718..3c718b60ee04 100644 --- a/pkg/security/secl/model/model_unix.go +++ b/pkg/security/secl/model/model_unix.go @@ -673,6 +673,7 @@ type PIDContext struct { MntNS uint32 `field:"mntns"` // SECLDoc[mntns] Definition:`MNTNS ID of the process` IsKworker bool `field:"is_kworker"` // SECLDoc[is_kworker] Definition:`Indicates whether the process is a kworker/kthread` PPid uint32 `field:"ppid"` // SECLDoc[ppid] Definition:`Parent process ID` + SID uint32 `field:"sid"` // SECLDoc[sid] Definition:`Session ID of the process` ExecInode uint64 `field:"-"` // used to track exec and event loss UserSessionID uint64 `field:"-"` // used to track user sessions from kernel space // used for ebpfless diff --git a/pkg/security/secl/model/unmarshallers_fuzz_linux_test.go b/pkg/security/secl/model/unmarshallers_fuzz_linux_test.go index 3cbb5e703b7a..829c0745bfdc 100644 --- a/pkg/security/secl/model/unmarshallers_fuzz_linux_test.go +++ b/pkg/security/secl/model/unmarshallers_fuzz_linux_test.go @@ -139,7 +139,7 @@ func FuzzSELinuxEvent_UnmarshalBinary(f *testing.F) { } func FuzzPIDContext_UnmarshalBinary(f *testing.F) { - fuzzUnmarshaller(f, func() BinaryUnmarshaler { return &PIDContext{} }, 40) + fuzzUnmarshaller(f, func() BinaryUnmarshaler { return &PIDContext{} }, 48) } func FuzzSyscallEvent_UnmarshalBinary(f *testing.F) { @@ -171,7 +171,7 @@ func FuzzArgsEnvsEvent_UnmarshalBinary(f *testing.F) { } func FuzzProcess_UnmarshalBinary(f *testing.F) { - fuzzUnmarshaller(f, func() BinaryUnmarshaler { return &Process{} }, 292) + fuzzUnmarshaller(f, func() BinaryUnmarshaler { return &Process{} }, 300) } func FuzzBPFEvent_UnmarshalBinary(f *testing.F) { diff --git a/pkg/security/secl/model/unmarshallers_linux.go b/pkg/security/secl/model/unmarshallers_linux.go index 9de4dace6852..f20e96e39ff3 100644 --- a/pkg/security/secl/model/unmarshallers_linux.go +++ b/pkg/security/secl/model/unmarshallers_linux.go @@ -228,20 +228,22 @@ func (e *Process) UnmarshalPidCacheBinary(data []byte) (int, error) { e.ExitTime = unmarshalTime(data[16:24]) e.UserSession.K8SSessionID = binary.NativeEndian.Uint64(data[24:32]) e.ForkFlags = binary.NativeEndian.Uint64(data[32:40]) + e.PIDContext.SID = binary.NativeEndian.Uint32(data[40:44]) + // [44:48] padding_sid // Unmarshal the credentials contained in pid_cache_t - read, err := e.Credentials.UnmarshalBinary(data[40:]) + read, err := e.Credentials.UnmarshalBinary(data[48:]) if err != nil { return 0, err } - read += 40 + read += 48 return validateReadSize(size, read) } // UnmarshalBinary unmarshalls a binary representation of itself func (e *Process) UnmarshalBinary(data []byte) (int, error) { - const size = 292 // size of struct exec_event_t starting from process_entry_t, inclusive + const size = 300 // size of struct exec_event_t starting from process_entry_t, inclusive if len(data) < size { return 0, ErrNotEnoughData } @@ -586,7 +588,7 @@ func (e *SELinuxEvent) UnmarshalBinary(data []byte) (int, error) { // UnmarshalBinary unmarshalls a binary representation of itself, process_context_t kernel side func (p *PIDContext) UnmarshalBinary(data []byte) (int, error) { - if len(data) < 40 { + if len(data) < 48 { return 0, ErrNotEnoughData } @@ -596,10 +598,12 @@ func (p *PIDContext) UnmarshalBinary(data []byte) (int, error) { p.MntNS = binary.NativeEndian.Uint32(data[12:16]) p.IsKworker = binary.NativeEndian.Uint32(data[16:20]) > 0 p.PPid = binary.NativeEndian.Uint32(data[20:24]) - p.ExecInode = binary.NativeEndian.Uint64(data[24:32]) - p.UserSessionID = binary.NativeEndian.Uint64(data[32:40]) + p.SID = binary.NativeEndian.Uint32(data[24:28]) + // [28:32] padding_sid + p.ExecInode = binary.NativeEndian.Uint64(data[32:40]) + p.UserSessionID = binary.NativeEndian.Uint64(data[40:48]) - return 40, nil + return 48, nil } // UnmarshalBinary unmarshalls a binary representation of itself diff --git a/pkg/security/serializers/serializers_base_linux_easyjson.go b/pkg/security/serializers/serializers_base_linux_easyjson.go index 6dfc16866896..70b96b9e7655 100644 --- a/pkg/security/serializers/serializers_base_linux_easyjson.go +++ b/pkg/security/serializers/serializers_base_linux_easyjson.go @@ -830,6 +830,12 @@ func easyjsonA1e47abeDecodeGithubComDataDogDatadogAgentPkgSecuritySerializers6(i *out.PPid = uint32(in.Uint32()) } } + case "sid": + if in.IsNull() { + in.Skip() + } else { + out.SID = uint32(in.Uint32()) + } case "tid": if in.IsNull() { in.Skip() @@ -1333,24 +1339,24 @@ func easyjsonA1e47abeEncodeGithubComDataDogDatadogAgentPkgSecuritySerializers6(o } out.Uint32(uint32(*in.PPid)) } - if in.Tid != 0 { - const prefix string = ",\"tid\":" + { + const prefix string = ",\"sid\":" if first { first = false out.RawString(prefix[1:]) } else { out.RawString(prefix) } + out.Uint32(uint32(in.SID)) + } + if in.Tid != 0 { + const prefix string = ",\"tid\":" + out.RawString(prefix) out.Uint32(uint32(in.Tid)) } { const prefix string = ",\"fork_flags\":" - if first { - first = false - out.RawString(prefix[1:]) - } else { - out.RawString(prefix) - } + out.RawString(prefix) out.Int(int(in.ForkFlags)) } { diff --git a/pkg/security/serializers/serializers_linux.go b/pkg/security/serializers/serializers_linux.go index 5ba23c534e77..7f08e0657d64 100644 --- a/pkg/security/serializers/serializers_linux.go +++ b/pkg/security/serializers/serializers_linux.go @@ -266,6 +266,8 @@ type ProcessSerializer struct { Pid uint32 `json:"pid,omitempty"` // Parent Process ID PPid *uint32 `json:"ppid,omitempty"` + // Session ID + SID uint32 `json:"sid"` // Thread ID Tid uint32 `json:"tid,omitempty"` // ForkFlags @@ -962,6 +964,7 @@ func newProcessSerializer(ps *model.Process, e *model.Event) *ProcessSerializer Pid: ps.Pid, Tid: ps.Tid, PPid: createNumPointer(ps.PPid), + SID: ps.SID, ForkFlags: int(ps.ForkFlags), Comm: ps.Comm, TTY: ps.TTYName, @@ -1032,6 +1035,7 @@ func newProcessSerializer(ps *model.Process, e *model.Event) *ProcessSerializer return &ProcessSerializer{ Pid: ps.Pid, Tid: ps.Tid, + SID: ps.SID, IsKworker: ps.IsKworker, IsExec: ps.IsExec, IsExecExec: ps.IsExecExec, diff --git a/pkg/security/serializers/serializers_linux_easyjson.go b/pkg/security/serializers/serializers_linux_easyjson.go index 6ff5da69e6a6..cd1cfceb0c34 100644 --- a/pkg/security/serializers/serializers_linux_easyjson.go +++ b/pkg/security/serializers/serializers_linux_easyjson.go @@ -2171,6 +2171,12 @@ func easyjsonDdc0fdbeDecodeGithubComDataDogDatadogAgentPkgSecuritySerializers16( *out.PPid = uint32(in.Uint32()) } } + case "sid": + if in.IsNull() { + in.Skip() + } else { + out.SID = uint32(in.Uint32()) + } case "tid": if in.IsNull() { in.Skip() @@ -2631,24 +2637,24 @@ func easyjsonDdc0fdbeEncodeGithubComDataDogDatadogAgentPkgSecuritySerializers16( } out.Uint32(uint32(*in.PPid)) } - if in.Tid != 0 { - const prefix string = ",\"tid\":" + { + const prefix string = ",\"sid\":" if first { first = false out.RawString(prefix[1:]) } else { out.RawString(prefix) } + out.Uint32(uint32(in.SID)) + } + if in.Tid != 0 { + const prefix string = ",\"tid\":" + out.RawString(prefix) out.Uint32(uint32(in.Tid)) } { const prefix string = ",\"fork_flags\":" - if first { - first = false - out.RawString(prefix[1:]) - } else { - out.RawString(prefix) - } + out.RawString(prefix) out.Int(int(in.ForkFlags)) } { diff --git a/pkg/security/tests/process_test.go b/pkg/security/tests/process_test.go index dc394fb7799e..50f4377fac0f 100644 --- a/pkg/security/tests/process_test.go +++ b/pkg/security/tests/process_test.go @@ -2588,3 +2588,70 @@ func TestProcessSubreaperReparenting(t *testing.T) { } }, "test_subreaper_open") } + +func TestProcessSID(t *testing.T) { + SkipIfNotAvailable(t) + + if ebpfLessEnabled { + t.Skip("process.sid not supported in ebpfless mode") + } + + shPath := which(t, "sh") + truePath := which(t, "true") + + const sidTestEnv = "DD_CWS_SID_TEST" + + ruleDefs := []*rules.RuleDefinition{ + { + ID: "test_sid_after_setsid", + Expression: fmt.Sprintf(`exec.file.path == "%s" && exec.envs in ["%s"] && process.sid != 0`, shPath, sidTestEnv), + }, + { + ID: "test_sid_inherited", + Expression: fmt.Sprintf(`exec.file.path == "%s" && exec.envs in ["%s"] && process.sid != 0`, truePath, sidTestEnv), + }, + } + + test, err := newTestModule(t, nil, ruleDefs) + if err != nil { + t.Fatal(err) + } + defer test.Close() + + t.Run("sid-updated-after-setsid", func(t *testing.T) { + cmd := exec.Command(shPath, "-c", "true") + test.WaitSignalFromRule(t, func() error { + cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} + cmd.Env = []string{sidTestEnv + "=1"} + return cmd.Run() + }, func(event *model.Event, rule *rules.Rule) { + assertTriggeredRule(t, rule, "test_sid_after_setsid") + fmt.Printf("ProcessContext is %+v\n", event.ProcessContext) + assert.Equal(t, event.ProcessContext.Pid, event.ProcessContext.SID, "after setsid, SID should equal PID (process is session leader)") + assert.NotZero(t, event.ProcessContext.SID, "SID should not be zero") + }, "test_sid_after_setsid") + }) + + t.Run("sid-inherited-not-leader", func(t *testing.T) { + test.WaitSignalFromRule(t, func() error { + // "; :" forces sh to fork before exec'ing truePath, otherwise + // sh would exec-optimize into true and become the session leader itself. + cmd := exec.Command(shPath, "-c", truePath+"; :") + cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} + cmd.Env = []string{sidTestEnv + "=1"} + return cmd.Run() + }, func(event *model.Event, rule *rules.Rule) { + assertTriggeredRule(t, rule, "test_sid_inherited") + assert.NotEqual(t, event.ProcessContext.Pid, event.ProcessContext.SID, "true should not be the session leader") + assert.NotZero(t, event.ProcessContext.SID, "SID should not be zero") + foundLeader := false + for a := event.ProcessContext.Ancestor; a != nil; a = a.Ancestor { + if a.Pid == event.ProcessContext.SID { + foundLeader = true + break + } + } + assert.True(t, foundLeader, "SID should match an ancestor's PID (the session leader)") + }, "test_sid_inherited") + }) +} diff --git a/pkg/security/utils/proc_linux.go b/pkg/security/utils/proc_linux.go index cd84129d3f51..ef4b3c9b2a22 100644 --- a/pkg/security/utils/proc_linux.go +++ b/pkg/security/utils/proc_linux.go @@ -273,6 +273,31 @@ func PidTTY(pid uint32) string { return "" } +// PidSID returns the session ID of the given pid from /proc/[pid]/stat +func PidSID(pid uint32) uint32 { + statPath := procPidPath(pid, "stat") + content, err := os.ReadFile(statPath) + if err != nil { + return 0 + } + // The comm field (field 2) can contain spaces and parens, so find the last ')' first + s := string(content) + idx := strings.LastIndex(s, ")") + if idx < 0 || idx+2 >= len(s) { + return 0 + } + // Fields after comm: state(3), ppid(4), pgrp(5), session(6) + fields := strings.Fields(s[idx+2:]) + if len(fields) < 4 { + return 0 + } + sid, err := strconv.ParseUint(fields[3], 10, 32) + if err != nil { + return 0 + } + return uint32(sid) +} + func zeroSplitter(data []byte, atEOF bool) (advance int, token []byte, err error) { for i := 0; i < len(data); i++ { if data[i] == '\x00' { diff --git a/pkg/security/utils/proc_sid_test.go b/pkg/security/utils/proc_sid_test.go new file mode 100644 index 000000000000..bace000e35a4 --- /dev/null +++ b/pkg/security/utils/proc_sid_test.go @@ -0,0 +1,33 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +//go:build linux + +package utils + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/sys/unix" +) + +func TestPidSID(t *testing.T) { + pid := uint32(os.Getpid()) + sid := PidSID(pid) + + // our own SID should match what getsid(0) returns + expected, err := unix.Getsid(0) + if err != nil { + t.Fatalf("getsid(0) failed: %v", err) + } + assert.Equal(t, uint32(expected), sid) +} + +func TestPidSID_InvalidPid(t *testing.T) { + sid := PidSID(0xFFFFFFFF) + assert.Equal(t, uint32(0), sid) +}