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:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "chase.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "extract-word.h"
|
||||
#include "fd-util.h"
|
||||
@@ -814,7 +815,28 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
|
||||
if (m->rm_rf_tmpdir && chown(m->source, uid_shift, uid_shift) < 0)
|
||||
return log_error_errno(errno, "Failed to chown %s: %m", m->source);
|
||||
|
||||
if (stat(m->source, &source_st) < 0)
|
||||
/* UID/GIDs of idmapped mounts are always resolved in the caller's user namespace. In other
|
||||
* words, they're not nested. If we're doing an idmapped mount from a bind mount that's
|
||||
* already idmapped itself, the old idmap is replaced with the new one. This means that the
|
||||
* source uid which we put in the idmap userns has to be the uid of mount source in the
|
||||
* caller's userns *without* any mount idmapping in place. To get that uid, we clone the
|
||||
* mount source tree and clear any existing idmapping and temporarily mount that tree over
|
||||
* the mount source before we stat the mount source to figure out the source uid. */
|
||||
_cleanup_close_ int fd_clone = open_tree_attr_fallback(
|
||||
AT_FDCWD,
|
||||
m->source,
|
||||
OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC,
|
||||
&(struct mount_attr) {
|
||||
.attr_clr = MOUNT_ATTR_IDMAP,
|
||||
});
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(fd_clone))
|
||||
/* We can only clear idmapped mounts with open_tree_attr(), but there might not be one in
|
||||
* the first place, so we keep going if we get a not supported error. */
|
||||
fd_clone = open_tree(AT_FDCWD, m->source, OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC);
|
||||
if (fd_clone < 0)
|
||||
return log_error_errno(errno, "Failed to clone %s: %m", m->source);
|
||||
|
||||
if (fstat(fd_clone, &source_st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
|
||||
|
||||
r = chase(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
|
||||
@@ -859,9 +881,10 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
|
||||
dest_uid = uid_shift;
|
||||
}
|
||||
|
||||
r = mount_nofollow_verbose(LOG_ERR, m->source, where, NULL, mount_flags, mount_opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (move_mount(fd_clone, "", AT_FDCWD, where, MOVE_MOUNT_F_EMPTY_PATH) < 0)
|
||||
return log_error_errno(errno, "Failed to mount %s to %s: %m", m->source, where);
|
||||
|
||||
fd_clone = safe_close(fd_clone);
|
||||
|
||||
if (m->read_only) {
|
||||
r = bind_remount_recursive(where, MS_RDONLY, MS_RDONLY, NULL);
|
||||
|
||||
Reference in New Issue
Block a user