]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect-image: add support for optionally mounting images with idmapping on
authorLennart Poettering <lennart@poettering.net>
Wed, 28 Apr 2021 15:23:29 +0000 (17:23 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 May 2021 20:44:05 +0000 (22:44 +0200)
src/core/namespace.c
src/dissect/dissect.c
src/nspawn/nspawn.c
src/portable/portable.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/sysext/sysext.c
src/test/test-loop-block.c

index acf8d14b67f295ede18dd43cd91153e0ab93b0f4..6d77ce9967424c57e1fd313bcdce26a6d748f737 100644 (file)
@@ -2170,7 +2170,7 @@ int setup_namespace(
 
         if (root_image) {
                 /* A root image is specified, mount it to the right place */
-                r = dissected_image_mount(dissected_image, root, UID_INVALID, dissect_image_flags);
+                r = dissected_image_mount(dissected_image, root, UID_INVALID, UID_INVALID, dissect_image_flags);
                 if (r < 0) {
                         log_debug_errno(r, "Failed to mount root image: %m");
                         goto finish;
index ef11faaf425a9525a41cd31ae0a7135f1c8a1b93..47feba3d627119dd9bbf3b89412f19ae9b9a8f2a 100644 (file)
@@ -582,7 +582,7 @@ static int action_mount(DissectedImage *m, LoopDevice *d) {
         if (r < 0)
                 return r;
 
-        r = dissected_image_mount_and_warn(m, arg_path, UID_INVALID, arg_flags);
+        r = dissected_image_mount_and_warn(m, arg_path, UID_INVALID, UID_INVALID, arg_flags);
         if (r < 0)
                 return r;
 
@@ -628,7 +628,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
 
         created_dir = TAKE_PTR(temp);
 
-        r = dissected_image_mount_and_warn(m, created_dir, UID_INVALID, arg_flags);
+        r = dissected_image_mount_and_warn(m, created_dir, UID_INVALID, UID_INVALID, arg_flags);
         if (r < 0)
                 return r;
 
index b5e5474231e15da111ba75702bf26968b709f834..d69b95598eec0fc17cc0b10eaf7e6d00ec24fd36 100644 (file)
@@ -3605,6 +3605,7 @@ static int outer_child(
                                 dissected_image,
                                 directory,
                                 arg_uid_shift,
+                                arg_uid_range,
                                 DISSECT_IMAGE_MOUNT_ROOT_ONLY|
                                 DISSECT_IMAGE_DISCARD_ON_LOOP|
                                 DISSECT_IMAGE_USR_NO_ROOT|
@@ -3696,6 +3697,7 @@ static int outer_child(
                                 dissected_image,
                                 directory,
                                 arg_uid_shift,
+                                arg_uid_range,
                                 DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|
                                 DISSECT_IMAGE_DISCARD_ON_LOOP|
                                 DISSECT_IMAGE_USR_NO_ROOT|
index 53c4d8e25b02fcf9873ce66a250dd0dbf8735ce1..2eebdc08aeca9493f2223fa4a203fd4c3c15426c 100644 (file)
@@ -426,7 +426,7 @@ static int portable_extract_by_path(
                 if (r == 0) {
                         seq[0] = safe_close(seq[0]);
 
-                        r = dissected_image_mount(m, tmpdir, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
+                        r = dissected_image_mount(m, tmpdir, UID_INVALID, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
                         if (r < 0) {
                                 log_debug_errno(r, "Failed to mount dissected image: %m");
                                 goto child_finish;
index 1f7ea3ec5b32d76f842ed879fc40d947437b476b..3cf00adb6f0350766ceef83b8fdb2385955b8e3e 100644 (file)
@@ -1472,11 +1472,12 @@ static int mount_partition(
                 const char *where,
                 const char *directory,
                 uid_t uid_shift,
+                uid_t uid_range,
                 DissectImageFlags flags) {
 
         _cleanup_free_ char *chased = NULL, *options = NULL;
         const char *p, *node, *fstype;
-        bool rw;
+        bool rw, remap_uid_gid = false;
         int r;
 
         assert(m);
@@ -1536,14 +1537,18 @@ static int mount_partition(
                         return -ENOMEM;
         }
 
-        if (uid_is_valid(uid_shift) && uid_shift != 0 && fstype_can_uid_gid(fstype)) {
-                _cleanup_free_ char *uid_option = NULL;
+        if (uid_is_valid(uid_shift) && uid_shift != 0) {
 
-                if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
-                        return -ENOMEM;
+                if (fstype_can_uid_gid(fstype)) {
+                        _cleanup_free_ char *uid_option = NULL;
 
-                if (!strextend_with_separator(&options, ",", uid_option))
-                        return -ENOMEM;
+                        if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
+                                return -ENOMEM;
+
+                        if (!strextend_with_separator(&options, ",", uid_option))
+                                return -ENOMEM;
+                } else if (FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_IDMAPPED))
+                        remap_uid_gid = true;
         }
 
         if (!isempty(m->mount_options))
@@ -1578,6 +1583,12 @@ static int mount_partition(
         if (rw && m->growfs && FLAGS_SET(flags, DISSECT_IMAGE_GROWFS))
                 (void) fs_grow(node, p);
 
+        if (remap_uid_gid) {
+                r = remount_idmap(p, uid_shift, uid_range);
+                if (r < 0)
+                        return r;
+        }
+
         return 1;
 }
 
@@ -1607,7 +1618,13 @@ static int mount_root_tmpfs(const char *where, uid_t uid_shift, DissectImageFlag
         return 1;
 }
 
-int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
+int dissected_image_mount(
+                DissectedImage *m,
+                const char *where,
+                uid_t uid_shift,
+                uid_t uid_range,
+                DissectImageFlags flags) {
+
         int r, xbootldr_mounted;
 
         assert(m);
@@ -1631,14 +1648,14 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
 
                 /* First mount the root fs. If there's none we use a tmpfs. */
                 if (m->partitions[PARTITION_ROOT].found)
-                        r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
+                        r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, uid_range, flags);
                 else
                         r = mount_root_tmpfs(where, uid_shift, flags);
                 if (r < 0)
                         return r;
 
                 /* For us mounting root always means mounting /usr as well */
-                r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, flags);
+                r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, uid_range, flags);
                 if (r < 0)
                         return r;
 
@@ -1659,23 +1676,23 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
         if (flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY)
                 return 0;
 
-        r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
+        r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, uid_range, flags);
         if (r < 0)
                 return r;
 
-        r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, flags);
+        r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, uid_range, flags);
         if (r < 0)
                 return r;
 
-        r = mount_partition(m->partitions + PARTITION_VAR, where, "/var", uid_shift, flags);
+        r = mount_partition(m->partitions + PARTITION_VAR, where, "/var", uid_shift, uid_range, flags);
         if (r < 0)
                 return r;
 
-        r = mount_partition(m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, flags);
+        r = mount_partition(m->partitions + PARTITION_TMP, where, "/var/tmp", uid_shift, uid_range, flags);
         if (r < 0)
                 return r;
 
-        xbootldr_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
+        xbootldr_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, uid_range, flags);
         if (xbootldr_mounted < 0)
                 return xbootldr_mounted;
 
@@ -1701,7 +1718,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
                                                 return r;
                                 } else if (dir_is_empty(p) > 0) {
                                         /* It exists and is an empty directory. Let's mount the ESP there. */
-                                        r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
+                                        r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, uid_range, flags);
                                         if (r < 0)
                                                 return r;
 
@@ -1713,7 +1730,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
                 if (!esp_done) {
                         /* OK, let's mount the ESP now to /efi (possibly creating the dir if missing) */
 
-                        r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
+                        r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, uid_range, flags);
                         if (r < 0)
                                 return r;
                 }
@@ -1722,13 +1739,19 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
         return 0;
 }
 
-int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
+int dissected_image_mount_and_warn(
+                DissectedImage *m,
+                const char *where,
+                uid_t uid_shift,
+                uid_t uid_range,
+                DissectImageFlags flags) {
+
         int r;
 
         assert(m);
         assert(where);
 
-        r = dissected_image_mount(m, where, uid_shift, flags);
+        r = dissected_image_mount(m, where, uid_shift, uid_range, flags);
         if (r == -ENXIO)
                 return log_error_errno(r, "Not root file system found in image.");
         if (r == -EMEDIUMTYPE)
@@ -2523,6 +2546,7 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
                                 m,
                                 t,
                                 UID_INVALID,
+                                UID_INVALID,
                                 DISSECT_IMAGE_READ_ONLY|
                                 DISSECT_IMAGE_MOUNT_ROOT_ONLY|
                                 DISSECT_IMAGE_VALIDATE_OS|
@@ -2811,7 +2835,7 @@ int mount_image_privately_interactively(
 
         created_dir = TAKE_PTR(temp);
 
-        r = dissected_image_mount_and_warn(dissected_image, created_dir, UID_INVALID, flags);
+        r = dissected_image_mount_and_warn(dissected_image, created_dir, UID_INVALID, UID_INVALID, flags);
         if (r < 0)
                 return r;
 
@@ -2917,7 +2941,7 @@ int verity_dissect_and_mount(
         if (r < 0)
                 return log_debug_errno(r, "Failed to umount under destination directory %s: %m", dest);
 
-        r = dissected_image_mount(dissected_image, dest, UID_INVALID, dissect_image_flags);
+        r = dissected_image_mount(dissected_image, dest, UID_INVALID, UID_INVALID, dissect_image_flags);
         if (r < 0)
                 return log_debug_errno(r, "Failed to mount image: %m");
 
index b2f5c5dc96b16f29aa04a6d0f9976694d0ddd92e..c961ee3e71ab7875c81e5919b09ab42e010b476f 100644 (file)
@@ -112,6 +112,7 @@ typedef enum DissectImageFlags {
         DISSECT_IMAGE_READ_ONLY           = DISSECT_IMAGE_DEVICE_READ_ONLY |
                                             DISSECT_IMAGE_MOUNT_READ_ONLY,
         DISSECT_IMAGE_GROWFS              = 1 << 18, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
+        DISSECT_IMAGE_MOUNT_IDMAPPED      = 1 << 19, /* Mount mounts with kernel 5.12-style userns ID mapping, if file sytem type doesn't support uid=/gid= */
 } DissectImageFlags;
 
 struct DissectedImage {
@@ -169,8 +170,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
 
 int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
 int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
-int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
-int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags);
+int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags);
+int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags);
 
 int dissected_image_acquire_metadata(DissectedImage *m);
 
index 76a21afea619451d7d1f434d3ba1410b4cf3aacb..572e4007fe27ff0072157520c70c823fbf337790 100644 (file)
@@ -551,6 +551,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
                                         m,
                                         p,
                                         UID_INVALID,
+                                        UID_INVALID,
                                         flags);
                         if (r < 0)
                                 return r;
index ba44b5f3f91829506accff80c11374b2a4fc8053..57f3279b676b692ebf12ab703c03d6d7dad8174d 100644 (file)
@@ -77,7 +77,7 @@ static void* thread_func(void *ptr) {
                 assert_se(dissected->partitions[PARTITION_HOME].found);
                 assert_se(dissected->partitions[PARTITION_HOME].node);
 
-                r = dissected_image_mount(dissected, mounted, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
+                r = dissected_image_mount(dissected, mounted, UID_INVALID, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
                 log_notice_errno(r, "Mounted %s → %s: %m", loop->node, mounted);
                 assert_se(r >= 0);
 
@@ -217,7 +217,7 @@ int main(int argc, char *argv[]) {
         assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);
 
         /* This first (writable) mount will initialize the mount point dirs, so that the subsequent read-only ones can work */
-        assert_se(dissected_image_mount(dissected, mounted, UID_INVALID, 0) >= 0);
+        assert_se(dissected_image_mount(dissected, mounted, UID_INVALID, UID_INVALID, 0) >= 0);
 
         assert_se(umount_recursive(mounted, 0) >= 0);
         loop = loop_device_unref(loop);