Skip to content

Commit

Permalink
[CWS] fix open with perm denied not reported
Browse files Browse the repository at this point in the history
  • Loading branch information
safchain committed Jan 31, 2025
1 parent 65e6e9f commit b6e51cd
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 135 deletions.
2 changes: 1 addition & 1 deletion pkg/security/ebpf/c/include/constants/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" \
: "=r"(var))
#define IS_UNHANDLED_ERROR(retval) retval < 0 && retval != -EACCES &&retval != -EPERM
#define IS_UNHANDLED_ERROR(retval) retval < 0 && retval != -EACCES && retval != -EPERM
#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
#define IS_KTHREAD(ppid, pid) ppid == 2 || pid == 2
#define NS_TO_SEC(x) (x) / 1000000000
Expand Down
198 changes: 85 additions & 113 deletions pkg/security/ebpf/c/include/hooks/open.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,25 +77,7 @@ HOOK_SYSCALL_ENTRY4(openat2, int, dirfd, const char *, filename, struct openat2_
return trace__sys_openat(filename, SYNC_SYSCALL, how.flags, how.mode);
}

int __attribute__((always_inline)) handle_open_event(struct syscall_cache_t *syscall, struct file *file, struct path *path, struct inode *inode) {
if (syscall->open.dentry) {
return 0;
}

struct dentry *dentry = get_path_dentry(path);

syscall->open.dentry = dentry;
syscall->open.file.path_key = get_inode_key_path(inode, path);

set_file_inode(dentry, &syscall->open.file, 0);

// do not pop, we want to keep track of the mount ref counter later in the stack
approve_syscall(syscall, open_approvers);

return 0;
}

int __attribute__((always_inline)) handle_truncate_path_dentry(struct path *path, struct dentry *dentry) {
int __attribute__((always_inline)) handle_truncate_path_dentry(ctx_t *ctx, struct path *path, struct dentry *dentry) {
struct syscall_cache_t *syscall = peek_syscall(EVENT_OPEN);
if (!syscall) {
return 0;
Expand All @@ -118,16 +100,25 @@ int __attribute__((always_inline)) handle_truncate_path_dentry(struct path *path
// do not pop, we want to keep track of the mount ref counter later in the stack
approve_syscall(syscall, open_approvers);

syscall->resolver.key = syscall->open.file.path_key;
syscall->resolver.dentry = syscall->open.dentry;
syscall->resolver.discarder_event_type = dentry_resolver_discarder_event_type(syscall);
syscall->resolver.iteration = 0;
syscall->resolver.ret = 0;

// tail call
resolve_dentry(ctx, DR_KPROBE_OR_FENTRY);

return 0;
}

int __attribute__((always_inline)) handle_truncate_path(struct path *path) {
int __attribute__((always_inline)) handle_truncate_path(ctx_t *ctx, struct path *path) {
if (path == NULL) {
return 0;
}

struct dentry *dentry = get_path_dentry(path);
return handle_truncate_path_dentry(path, dentry);
return handle_truncate_path_dentry(ctx, path, dentry);
}

HOOK_ENTRY("do_truncate")
Expand All @@ -138,13 +129,13 @@ int hook_do_truncate(ctx_t *ctx) {
return 0;
}
struct path *path = get_file_f_path_addr(f);
return handle_truncate_path_dentry(path, dentry);
return handle_truncate_path_dentry(ctx, path, dentry);
}

HOOK_ENTRY("vfs_truncate")
int hook_vfs_truncate(ctx_t *ctx) {
struct path *path = (struct path *)CTX_PARM1(ctx);
return handle_truncate_path(path);
return handle_truncate_path(ctx, path);
}

HOOK_ENTRY("security_file_truncate")
Expand All @@ -153,33 +144,54 @@ int hook_security_file_truncate(ctx_t *ctx) {
if (f == NULL) {
return 0;
}
return handle_truncate_path(get_file_f_path_addr(f));
return handle_truncate_path(ctx, get_file_f_path_addr(f));
}

HOOK_ENTRY("security_path_truncate")
int hook_security_path_truncate(ctx_t *ctx) {
struct path *path = (struct path *)CTX_PARM1(ctx);
return handle_truncate_path(path);
return handle_truncate_path(ctx, path);
}

HOOK_ENTRY("vfs_open")
int hook_vfs_open(ctx_t *ctx) {
int __attribute__((always_inline)) handle_open(ctx_t *ctx) {
struct syscall_cache_t *syscall = peek_syscall(EVENT_OPEN);
if (!syscall) {
return 0;
}

// embedded in struct nameidata
struct path *path = (struct path *)CTX_PARM1(ctx);
struct file *file = (struct file *)CTX_PARM2(ctx);

struct dentry *dentry = get_path_dentry(path);
struct inode *inode = get_dentry_inode(dentry);

if (is_non_mountable_dentry(dentry)) {
pop_syscall(EVENT_OPEN);
return 0;
}

return handle_open_event(syscall, file, path, inode);
syscall->open.dentry = dentry;
syscall->open.file.path_key = get_dentry_key_path(dentry, path);

set_file_inode(dentry, &syscall->open.file, 0);

// do not pop, we want to keep track of the mount ref counter later in the stack
approve_syscall(syscall, open_approvers);

syscall->resolver.key = syscall->open.file.path_key;
syscall->resolver.dentry = syscall->open.dentry;
syscall->resolver.discarder_event_type = dentry_resolver_discarder_event_type(syscall);
syscall->resolver.iteration = 0;
syscall->resolver.ret = 0;

// tail call
resolve_dentry(ctx, DR_KPROBE_OR_FENTRY);

return 0;
}

HOOK_ENTRY("terminate_walk")
int hook_terminate_walk(ctx_t *ctx) {
return handle_open(ctx);
}

HOOK_ENTRY("do_dentry_open")
Expand Down Expand Up @@ -233,84 +245,101 @@ int hook_io_openat2(ctx_t *ctx) {
return trace_io_openat(ctx);
}

int __attribute__((always_inline)) sys_open_ret(void *ctx, int retval, int dr_type) {
if (IS_UNHANDLED_ERROR(retval)) {
pop_syscall(EVENT_OPEN);
int __attribute__((always_inline)) sys_open_ret(void *ctx, int retval) {
struct syscall_cache_t *syscall = pop_syscall(EVENT_OPEN);
if (!syscall) {
return 0;
}

struct syscall_cache_t *syscall = peek_syscall(EVENT_OPEN);
if (!syscall) {
if (IS_UNHANDLED_ERROR(retval)) {
return 0;
}

// increase mount ref
inc_mount_ref(syscall->open.file.path_key.mount_id);
if (syscall->state == DISCARDED) {
pop_syscall(EVENT_OPEN);
return 0;
}

syscall->resolver.key = syscall->open.file.path_key;
syscall->resolver.dentry = syscall->open.dentry;
syscall->resolver.discarder_event_type = dentry_resolver_discarder_event_type(syscall);
syscall->resolver.callback = select_dr_key(dr_type, DR_OPEN_CALLBACK_KPROBE_KEY, DR_OPEN_CALLBACK_TRACEPOINT_KEY);
syscall->resolver.iteration = 0;
syscall->resolver.ret = 0;
syscall->resolver.sysretval = retval;
if (syscall->resolver.ret == DENTRY_DISCARDED) {
monitor_discarded(EVENT_OPEN);
return 0;
}

// tail call
resolve_dentry(ctx, dr_type);
if (syscall->resolver.ret == DENTRY_INVALID) {
return 0;
}

struct open_event_t event = {
.syscall.retval = retval,
.syscall_ctx.id = syscall->ctx_id,
.event.flags = (syscall->async ? EVENT_FLAGS_ASYNC : 0) |
(syscall->resolver.flags & SAVED_BY_ACTIVITY_DUMP ? EVENT_FLAGS_SAVED_BY_AD : 0) |
(syscall->resolver.flags & ACTIVITY_DUMP_RUNNING ? EVENT_FLAGS_ACTIVITY_DUMP_SAMPLE : 0),
.file = syscall->open.file,
.flags = syscall->open.flags,
.mode = syscall->open.mode,
};

fill_file(syscall->open.dentry, &event.file);

struct proc_cache_t *entry;
if (syscall->open.pid_tgid != 0) {
entry = fill_process_context_with_pid_tgid(&event.process, syscall->open.pid_tgid);
} else {
entry = fill_process_context(&event.process);
}
fill_container_context(entry, &event.container);
fill_span_context(&event.span);

// if the tail call fails, we need to pop the syscall cache entry
pop_syscall(EVENT_OPEN);
send_event(ctx, EVENT_OPEN, event);
return 0;
}

HOOK_SYSCALL_EXIT(creat) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_SYSCALL_COMPAT_EXIT(open_by_handle_at) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_SYSCALL_COMPAT_EXIT(truncate) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_SYSCALL_COMPAT_EXIT(ftruncate) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_SYSCALL_COMPAT_EXIT(open) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_SYSCALL_COMPAT_EXIT(openat) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_SYSCALL_EXIT(openat2) {
int retval = SYSCALL_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

SEC("tracepoint/handle_sys_open_exit")
int tracepoint_handle_sys_open_exit(struct tracepoint_raw_syscalls_sys_exit_t *args) {
return sys_open_ret(args, args->ret, DR_TRACEPOINT);
return sys_open_ret(args, args->ret);
}

HOOK_EXIT("io_openat2")
int rethook_io_openat2(ctx_t *ctx) {
int retval = CTX_PARMRET(ctx);
return sys_open_ret(ctx, retval, DR_KPROBE_OR_FENTRY);
return sys_open_ret(ctx, retval);
}

HOOK_ENTRY("filp_close")
Expand All @@ -324,61 +353,4 @@ int hook_filp_close(ctx_t *ctx) {
return 0;
}

int __attribute__((always_inline)) dr_open_callback(void *ctx) {
struct syscall_cache_t *syscall = pop_syscall(EVENT_OPEN);
if (!syscall) {
return 0;
}

s64 retval = syscall->resolver.sysretval;

if (IS_UNHANDLED_ERROR(retval)) {
return 0;
}

if (syscall->resolver.ret == DENTRY_DISCARDED) {
monitor_discarded(EVENT_OPEN);
return 0;
}

if (syscall->resolver.ret == DENTRY_INVALID) {
return 0;
}

struct open_event_t event = {
.syscall.retval = retval,
.syscall_ctx.id = syscall->ctx_id,
.event.flags = (syscall->async ? EVENT_FLAGS_ASYNC : 0) |
(syscall->resolver.flags & SAVED_BY_ACTIVITY_DUMP ? EVENT_FLAGS_SAVED_BY_AD : 0) |
(syscall->resolver.flags & ACTIVITY_DUMP_RUNNING ? EVENT_FLAGS_ACTIVITY_DUMP_SAMPLE : 0),
.file = syscall->open.file,
.flags = syscall->open.flags,
.mode = syscall->open.mode,
};

fill_file(syscall->open.dentry, &event.file);

struct proc_cache_t *entry;
if (syscall->open.pid_tgid != 0) {
entry = fill_process_context_with_pid_tgid(&event.process, syscall->open.pid_tgid);
} else {
entry = fill_process_context(&event.process);
}
fill_container_context(entry, &event.container);
fill_span_context(&event.span);

send_event(ctx, EVENT_OPEN, event);
return 0;
}

TAIL_CALL_TARGET("dr_open_callback")
int tail_call_target_dr_open_callback(ctx_t *ctx) {
return dr_open_callback(ctx);
}

SEC("tracepoint/dr_open_callback")
int tracepoint_dr_open_callback(struct tracepoint_syscalls_sys_exit_t *args) {
return dr_open_callback(args);
}

#endif
14 changes: 0 additions & 14 deletions pkg/security/ebpf/probes/dentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,6 @@ func getDentryResolverTailCallRoutes(ERPCDentryResolutionEnabled, supportMmapabl
},

// dentry resolver kprobe callbacks
{
ProgArrayName: dentryCallbackProgs,
Key: DentryResolverOpenCallbackKprobeKey,
ProbeIdentificationPair: manager.ProbeIdentificationPair{
EBPFFuncName: "tail_call_target_dr_open_callback",
},
},
{
ProgArrayName: dentryCallbackProgs,
Key: DentryResolverSetAttrCallbackKprobeKey,
Expand Down Expand Up @@ -158,13 +151,6 @@ func getDentryResolverTailCallRoutes(ERPCDentryResolutionEnabled, supportMmapabl
EBPFFuncName: "tail_call_target_dr_chdir_callback",
},
},
{
ProgArrayName: "dentry_resolver_tracepoint_callbacks",
Key: DentryResolverOpenCallbackTracepointKey,
ProbeIdentificationPair: manager.ProbeIdentificationPair{
EBPFFuncName: "tracepoint_dr_open_callback",
},
},
{
ProgArrayName: "dentry_resolver_tracepoint_callbacks",
Key: DentryResolverMkdirCallbackTracepointKey,
Expand Down
4 changes: 3 additions & 1 deletion pkg/security/ebpf/probes/event_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ func GetSelectorsPerEventType(fentry bool) map[eval.EventType][]manager.ProbesSe
kprobeOrFentry("setup_arg_pages"),
kprobeOrFentry("mprotect_fixup"),
kprobeOrFentry("exit_itimers"),
kprobeOrFentry("vfs_open"),
kprobeOrFentry("do_dentry_open"),
kprobeOrFentry("commit_creds"),
kprobeOrFentry("switch_task_namespaces"),
Expand Down Expand Up @@ -185,6 +184,9 @@ func GetSelectorsPerEventType(fentry bool) map[eval.EventType][]manager.ProbesSe
&manager.AllOf{Selectors: []manager.ProbesSelector{
kprobeOrFentry("filp_close"),
}},
&manager.OneOf{Selectors: []manager.ProbesSelector{
kprobeOrFentry("terminate_walk"),
}},

// iouring
&manager.BestEffort{Selectors: []manager.ProbesSelector{
Expand Down
Loading

0 comments on commit b6e51cd

Please sign in to comment.