nsresourced: harden the transient UID/GID write restriction (#43196)
nsresourced hands out transient, recyclable UID/GID ranges to unprivileged user namespaces, and a BPF-LSM policy is what keeps a client from leaving inodes owned by its transient range on a file system that outlives the namespace, so that a later client which gets the same range can't inherit them. The old policy decided based on the mount a write went through, which is forgeable: unshare(CLONE_NEWNS) gives you clones of every mount with fresh mount IDs but the same superblock, and the mount namespace's owner is yours to pick. overlayfs sidesteps it entirely. So this reworks the check to look at where the write actually lands on disk. The first commit (Christian Brauner's) replaces the per-mount allowlist with two questions answered from fields the client can't forge and that survive mount cloning: does the file system die together with the user namespace (sb->s_user_ns at or below the managed one), and does the transient ID actually reach the disk, or does an idmapped mount translate it into something else first. It walks the userns chain upwards so a nested namespace can't escape it. The map layout changed, so the pins move to userns-restrict.v2 and the old ones are removed on install. The second commit handles overlayfs. A write through an overlay creates the file on the upper layer via vfs_create(), which only trips the inode LSM hooks, not the path hooks we attach to, and the one path hook that does fire sees the overlay mount, which belongs to the managed namespace and so looks like it dies with it even though the upper may be persistent. So we judge the upper at mount time in sb_kern_mount and refuse a writable overlay unless its upper dies with the namespace too. Reading overlayfs' private ovl_fs/ovl_layer uses CO-RE type flavors guarded by bpf_core_type_exists(), and the service now orders after modprobe@overlay.service. The third commit deals with restarts. The managed set only lives in the pinned maps, so an upgrade that changes the map layout comes up with empty maps and every already-running namespace silently loses its restriction. manager_startup() now re-adds the live registry entries to the maps in the same pass that reaps the dead ones. The setgroups() denial is restored from a flag we now store in the registry. One consequence: a managed namespace can only mount a writable overlay whose upper dies with it, e.g. a tmpfs it set up itself. If you need a writable persistent upperdir (mkosi does), use a plain unprivileged user namespace for that, not a transient nsresourced range.
This commit is contained in:
@@ -1563,7 +1563,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD
|
||||
output_fd = STDOUT_FILENO;
|
||||
}
|
||||
|
||||
r = tar_c(dfd, output_fd, arg_target, /* flags= */ 0);
|
||||
r = tar_c(dfd, output_fd, arg_target, /* hardlink_db_fd= */ -EBADF, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user