Skip to content
Merged
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
28 changes: 23 additions & 5 deletions pkg/security/ebpf/c/include/hooks/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,24 +340,42 @@ int hook_mnt_change_mountpoint(ctx_t *ctx)

HOOK_ENTRY("make_visible")
int hook_make_visible(ctx_t *ctx) {
struct syscall_cache_t *syscall = peek_syscall_with(unshare_or_open_tree_or_move_mount);
struct syscall_cache_t *syscall = peek_syscall_with(mountpoint_predicate);
if (!syscall) {
return 0;
}

struct mount *newmnt = (struct mount *)CTX_PARM1(ctx);
// check if this mount has already been processed by another hook
if (syscall->mount.newmnt == newmnt) {
u32 ns_inum = get_mount_mount_ns_inum(newmnt);

if (syscall->type == EVENT_MOUNT) {
// copy_tree attaches the copies of a recursive bind mount before the mount itself is made visible, so
// we skip these copies here, commit_tree will call us again with the mount the syscall was issued for,
// once it joined the namespace. (ns_inum == 0 because the copies aren't part of any namespace at this point).
if (!ns_inum) {
return 0;
}
// attach_recursive_mnt is the only other hook covering regular mount syscalls and it cannot be trusted
// since 6.18: its arguments were replaced by a pinned_mountpoint and the compiler usually
// leaves an ISRA clone of it. It records the same mount as we do here, but only a older kernel versions (< 6.18).
if (syscall->mount.newmnt && syscall->mount.newmnt != newmnt) {
return 0;
Comment on lines +361 to +362

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Capture the first visible mount despite propagation

When a mount is attached beneath a shared mount, hook_propagate_mnt runs before commit_tree and stores a propagated copy in syscall->mount.newmnt (lines 524-535). The first make_visible call is then for the syscall's original mount, so this inequality rejects exactly the mount the comment says to capture; a later call can instead select the cached propagated copy. The exit hook consequently reports/resolves the peer copy while the original mount remains unknown to CWS. Track whether make_visible itself has captured its first mount rather than treating any pre-populated newmnt as authoritative.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only two hooks currently write to the syscall->mount.newmnt field for EVENT_MOUNT: attach_recursive_mnt and propagate_mnt. Both of these retrieve the original mount created by the mount syscall (and not a copy of some propagated mountpoint), so the comment is wrong here

}
} else if (syscall->mount.newmnt && syscall->mount.newmnt == newmnt) {
// check if this mount has already been processed by another hook
return 0;
}

syscall->mount.ns_inum = get_mount_mount_ns_inum(newmnt);
syscall->mount.ns_inum = ns_inum;
syscall->mount.newmnt = newmnt;
syscall->mount.parent = get_mount_parent(newmnt);
struct mountpoint *mp = get_mount_mountpoint(newmnt);
syscall->mount.mountpoint_dentry = get_mountpoint_dentry(mp);

handle_new_mount(ctx, syscall, KPROBE_OR_FENTRY_TYPE, false);
// plain mounts are sent from the mount syscall return hook, once the syscall is known to succeed
if (syscall->type != EVENT_MOUNT) {
handle_new_mount(ctx, syscall, KPROBE_OR_FENTRY_TYPE, false);
}

return 0;
}
Expand Down
Loading