mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
nsresourced: refuse RENAME_WHITEOUT where mknod is refused
renameat2() with RENAME_WHITEOUT leaves a whiteout in place of the source. That's a character device owned by the caller's fsuid and fsgid which the file system creates from its ->rename() method, so it never passes the path_mknod hook. Since Linux 5.8 this doesn't require any privileges either. So a managed user namespace that can rename an entry on a file system that outlives it, e.g., in a world-writable directory the user prepared from the outside, can leave a whiteout owned by its transient range behind. The only hook that sees this is path_rename, which gets the flags. Refuse RENAME_WHITEOUT there whenever validate_mount() would refuse a mknod in the source directory. (cherry picked from commit075c364273) (cherry picked from commitb4f5697d22)
This commit is contained in:
1 parent
134e402aa0
commit
432834f79e
1 file changed
+13
@@ -69,6 +69,9 @@ void* bpf_rdonly_cast(const void *, __u32) __ksym;
|
||||
#define OVERLAYFS_SUPER_MAGIC 0x794c7630
|
||||
#define CGROUP2_SUPER_MAGIC 0x63677270
|
||||
|
||||
/* From include/uapi/linux/fs.h, for the same reason. */
|
||||
#define RENAME_WHITEOUT (1U << 2)
|
||||
|
||||
/* From include/uapi/asm-generic/fcntl.h. Only archs without BPF trampolines (no LSM programs) deviate. */
|
||||
#define __O_TMPFILE (1U << 22) /* O_TMPFILE without O_DIRECTORY */
|
||||
|
||||
@@ -416,6 +419,16 @@ int BPF_PROG(userns_restrict_file_open, struct file *file, int ret) {
|
||||
return validate_mount(file->f_path.mnt, ret);
|
||||
}
|
||||
|
||||
/* RENAME_WHITEOUT puts a whiteout owned by the calling task in place of the source, past the mknod hook */
|
||||
SEC("lsm/path_rename")
|
||||
int BPF_PROG(userns_restrict_path_rename, const struct path *old_dir, struct dentry *old_dentry,
|
||||
const struct path *new_dir, struct dentry *new_dentry, unsigned flags, int ret) {
|
||||
if (!(flags & RENAME_WHITEOUT))
|
||||
return ret;
|
||||
|
||||
return validate_mount(old_dir->mnt, ret);
|
||||
}
|
||||
|
||||
/* overlayfs' struct ovl_fs and struct ovl_layer are private to the module and hence absent from vmlinux.h
|
||||
* whenever overlayfs is built as a module. We declare the two fields we need as CO-RE "type flavors": libbpf
|
||||
* strips the ___local suffix and relocates these against the kernel's real ovl_fs/ovl_layer. This both
|
||||
|
||||
Reference in new issue
Block a user