summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2023-11-17 08:03:57 +0100
committerLennart Poettering <lennart@poettering.net>2024-02-15 11:49:54 +0100
commit614d09a37dc468d126df40ae649092f927196863 (patch)
tree5a729e36da950ef815bcc0bc5983feeb666a8d59 /src
parentlog: reorder arguments of internal macro (diff)
downloadsystemd-614d09a37dc468d126df40ae649092f927196863.tar.xz
systemd-614d09a37dc468d126df40ae649092f927196863.zip
nspawn: add support for owneridmap bind option
owneridmap bind option will map the target directory owner from inside the container to the owner of the directory bound from the host filesystem. This will ensure files and directories created in the container will be owned by the directory owner of the host filesystem. All other users will remain unmapped. Files to be written as other users in the container will not be allowed. Resolves: #27037
Diffstat (limited to 'src')
-rw-r--r--src/nspawn/nspawn-mount.c9
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/shared/dissect-image.c2
-rw-r--r--src/shared/mount-util.c22
-rw-r--r--src/shared/mount-util.h9
5 files changed, 33 insertions, 11 deletions
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index 5f41c1c91f..71efeb8572 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -742,6 +742,8 @@ static int parse_mount_bind_options(const char *options, unsigned long *mount_fl
new_idmapping = REMOUNT_IDMAPPING_NONE;
else if (streq(word, "rootidmap"))
new_idmapping = REMOUNT_IDMAPPING_HOST_OWNER;
+ else if (streq(word, "owneridmap"))
+ new_idmapping = REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER;
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid bind mount option: %s", word);
@@ -759,6 +761,7 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
_cleanup_free_ char *mount_opts = NULL, *where = NULL;
unsigned long mount_flags = MS_BIND | MS_REC;
struct stat source_st, dest_st;
+ uid_t dest_uid = UID_INVALID;
int r;
RemountIdmapping idmapping = REMOUNT_IDMAPPING_NONE;
@@ -787,6 +790,8 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
if (stat(where, &dest_st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", where);
+ dest_uid = dest_st.st_uid;
+
if (S_ISDIR(source_st.st_mode) && !S_ISDIR(dest_st.st_mode))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot bind mount directory %s on file %s.",
@@ -815,6 +820,8 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
if (chown(where, uid_shift, uid_shift) < 0)
return log_error_errno(errno, "Failed to chown %s: %m", where);
+
+ dest_uid = uid_shift;
}
r = mount_nofollow_verbose(LOG_ERR, m->source, where, NULL, mount_flags, mount_opts);
@@ -828,7 +835,7 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
}
if (idmapping != REMOUNT_IDMAPPING_NONE) {
- r = remount_idmap(STRV_MAKE(where), uid_shift, uid_range, source_st.st_uid, idmapping);
+ r = remount_idmap(STRV_MAKE(where), uid_shift, uid_range, source_st.st_uid, dest_uid, idmapping);
if (r < 0)
return log_error_errno(r, "Failed to map ids for bind mount %s: %m", where);
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 664637685b..49b57c5168 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3931,7 +3931,7 @@ static int outer_child(
dirs[i] = NULL;
- r = remount_idmap(dirs, arg_uid_shift, arg_uid_range, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
+ r = remount_idmap(dirs, arg_uid_shift, arg_uid_range, UID_INVALID, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
if (r == -EINVAL || ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
/* This might fail because the kernel or file system doesn't support idmapping. We
* can't really distinguish this nicely, nor do we have any guarantees about the
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index e699aa43e9..d7c705184a 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -2144,7 +2144,7 @@ int dissected_image_mount(
if (userns_fd < 0 && need_user_mapping(uid_shift, uid_range) && FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_IDMAPPED)) {
- my_userns_fd = make_userns(uid_shift, uid_range, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
+ my_userns_fd = make_userns(uid_shift, uid_range, UID_INVALID, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
if (my_userns_fd < 0)
return my_userns_fd;
diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c
index 9bae21f88e..bff1bf9f49 100644
--- a/src/shared/mount-util.c
+++ b/src/shared/mount-util.c
@@ -1314,7 +1314,7 @@ int fd_make_mount_point(int fd) {
return 1;
}
-int make_userns(uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping) {
+int make_userns(uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest_owner, RemountIdmapping idmapping) {
_cleanup_close_ int userns_fd = -EBADF;
_cleanup_free_ char *line = NULL;
@@ -1349,8 +1349,20 @@ int make_userns(uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping
if (idmapping == REMOUNT_IDMAPPING_HOST_OWNER) {
/* Remap the owner of the bind mounted directory to the root user within the container. This
* way every file written by root within the container to the bind-mounted directory will
- * be owned by the original user. All other user will remain unmapped. */
- if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", owner, uid_shift, 1u) < 0)
+ * be owned by the original user from the host. All other users will remain unmapped. */
+ if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", source_owner, uid_shift, 1u) < 0)
+ return log_oom_debug();
+ }
+
+ if (idmapping == REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER) {
+ /* Remap the owner of the bind mounted directory to the owner of the target directory
+ * within the container. This way every file written by target directory owner within the
+ * container to the bind-mounted directory will be owned by the original host user.
+ * All other users will remain unmapped. */
+ if (asprintf(
+ &line,
+ UID_FMT " " UID_FMT " " UID_FMT "\n",
+ source_owner, dest_owner, 1u) < 0)
return log_oom_debug();
}
@@ -1424,10 +1436,10 @@ int remount_idmap_fd(
return 0;
}
-int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping) {
+int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest_owner,RemountIdmapping idmapping) {
_cleanup_close_ int userns_fd = -EBADF;
- userns_fd = make_userns(uid_shift, uid_range, owner, idmapping);
+ userns_fd = make_userns(uid_shift, uid_range, source_owner, dest_owner, idmapping);
if (userns_fd < 0)
return userns_fd;
diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h
index ef31104900..2f9f394ab0 100644
--- a/src/shared/mount-util.h
+++ b/src/shared/mount-util.h
@@ -116,16 +116,19 @@ typedef enum RemountIdmapping {
* certain security implications defaults to off, and requires explicit opt-in. */
REMOUNT_IDMAPPING_HOST_ROOT,
/* Define a mapping from root user within the container to the owner of the bind mounted directory.
- * This ensure no root-owned files will be written in a bind-mounted directory owned by a different
+ * This ensures no root-owned files will be written in a bind-mounted directory owned by a different
* user. No other users are mapped. */
REMOUNT_IDMAPPING_HOST_OWNER,
+ /* Define a mapping from bind-target owner within the container to the host owner of the bind mounted
+ * directory. No other users are mapped. */
+ REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER,
_REMOUNT_IDMAPPING_MAX,
_REMOUNT_IDMAPPING_INVALID = -EINVAL,
} RemountIdmapping;
-int make_userns(uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping);
+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);
-int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t owner, RemountIdmapping idmapping);
+int remount_idmap(char **p, uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
int bind_mount_submounts(
const char *source,