nspawn: Support idmapped mounts on homed managed home directories
Christian made this possible in Linux 6.15 with a new system call open_tree_attr() that combines open_tree() and mount_setattr(). Because idmapped mounts are (rightfully) not nested, we have to do some extra shenanigans to make source we're putting the right source uid in the userns for any idmapped mounts that we do in nspawn. Of course we also add the necessary boilerplate to make open_tree_attr() available in our code and wrap open_tree_attr() and the corresponding fallback in a new function which we then use everywhere else.
This commit is contained in:
+33
-14
@@ -1441,6 +1441,28 @@ int make_userns(uid_t uid_shift,
|
||||
return TAKE_FD(userns_fd);
|
||||
}
|
||||
|
||||
int open_tree_attr_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr) {
|
||||
assert(attr);
|
||||
|
||||
_cleanup_close_ int fd = open_tree_attr(dir_fd, path, flags, attr, sizeof(struct mount_attr));
|
||||
if (fd >= 0)
|
||||
return TAKE_FD(fd);
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
return log_debug_errno(errno, "Failed to open tree and set mount attributes: %m");
|
||||
|
||||
if (attr->attr_clr & MOUNT_ATTR_IDMAP)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Cannot clear idmap from mount without open_tree_attr()");
|
||||
|
||||
fd = open_tree(dir_fd, path, flags);
|
||||
if (fd < 0)
|
||||
return log_debug_errno(errno, "Failed to open tree: %m");
|
||||
|
||||
if (mount_setattr(fd, "", AT_EMPTY_PATH | (flags & AT_RECURSIVE), attr, sizeof(struct mount_attr)) < 0)
|
||||
return log_debug_errno(errno, "Failed to change mount attributes: %m");
|
||||
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
||||
int remount_idmap_fd(
|
||||
char **paths,
|
||||
int userns_fd,
|
||||
@@ -1469,22 +1491,19 @@ int remount_idmap_fd(
|
||||
CLEANUP_ARRAY(mount_fds, n_mounts_fds, close_many_and_free);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int mntfd;
|
||||
|
||||
/* Clone the mount point */
|
||||
mntfd = mount_fds[n_mounts_fds] = open_tree(-EBADF, paths[i], OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
|
||||
if (mount_fds[n_mounts_fds] < 0)
|
||||
return log_debug_errno(errno, "Failed to open tree of mounted filesystem '%s': %m", paths[i]);
|
||||
|
||||
n_mounts_fds++;
|
||||
|
||||
/* Set the user namespace mapping attribute on the cloned mount point */
|
||||
if (mount_setattr(mntfd, "", AT_EMPTY_PATH,
|
||||
&(struct mount_attr) {
|
||||
/* Clone the mount point and et the user namespace mapping attribute on the cloned mount point. */
|
||||
mount_fds[n_mounts_fds] = open_tree_attr_fallback(
|
||||
/* dir_fd= */ -EBADF,
|
||||
paths[i],
|
||||
OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC,
|
||||
&(struct mount_attr) {
|
||||
.attr_set = MOUNT_ATTR_IDMAP | extra_mount_attr_set,
|
||||
.userns_fd = userns_fd,
|
||||
}, sizeof(struct mount_attr)) < 0)
|
||||
return log_debug_errno(errno, "Failed to change bind mount attributes for clone of '%s': %m", paths[i]);
|
||||
});
|
||||
if (mount_fds[n_mounts_fds] < 0)
|
||||
return mount_fds[n_mounts_fds];
|
||||
|
||||
n_mounts_fds++;
|
||||
}
|
||||
|
||||
for (size_t i = n; i > 0; i--) { /* Unmount the paths right-to-left */
|
||||
|
||||
@@ -148,6 +148,8 @@ typedef enum RemountIdmapping {
|
||||
_REMOUNT_IDMAPPING_INVALID = -EINVAL,
|
||||
} RemountIdmapping;
|
||||
|
||||
int open_tree_attr_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr);
|
||||
|
||||
int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
|
||||
int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set);
|
||||
int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
|
||||
|
||||
Reference in New Issue
Block a user