]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysext: Make sure that merged hierarchy does not change its permissions
authorKrzesimir Nowak <knowak@microsoft.com>
Thu, 28 Mar 2024 14:15:45 +0000 (15:15 +0100)
committerKrzesimir Nowak <knowak@microsoft.com>
Fri, 19 Apr 2024 05:15:01 +0000 (07:15 +0200)
The merged overlayfs filesystem mountpoint has a mode of its top layer. We have
been creating all the directories to be used as layers with mode 0700, so the
result was a merged hierarchy with such mode - it rendered the merged hierarchy
to be accesible only by root.

Change the mode of a directory serving as the top layer to match the hierarchy
to avoid such situations.

src/sysext/sysext.c

index 44ee20f709eecee0026b33767cc9e35077eebdd3..07a9619bd12a4f6fb6882b7fc1a223f59a004560 100644 (file)
@@ -725,6 +725,7 @@ static int work_dir_for_hierarchy(
 
 typedef struct OverlayFSPaths {
         char *hierarchy;
+        mode_t hierarchy_mode;
         char *resolved_hierarchy;
         char *resolved_mutable_directory;
 
@@ -822,6 +823,8 @@ static int resolve_mutable_directory(
 
 static int overlayfs_paths_new(const char *hierarchy, const char *workspace_path, OverlayFSPaths **ret_op) {
         _cleanup_free_ char *hierarchy_copy = NULL, *resolved_hierarchy = NULL, *resolved_mutable_directory = NULL;
+        mode_t hierarchy_mode;
+
         int r;
 
         assert (hierarchy);
@@ -834,6 +837,16 @@ static int overlayfs_paths_new(const char *hierarchy, const char *workspace_path
         r = resolve_hierarchy(hierarchy, &resolved_hierarchy);
         if (r < 0)
                 return r;
+
+        if (resolved_hierarchy) {
+                struct stat st;
+
+                if (stat(resolved_hierarchy, &st) < 0)
+                        return log_error_errno(errno, "Failed to stat '%s': %m", resolved_hierarchy);
+                hierarchy_mode = st.st_mode & 0777;
+        } else
+                hierarchy_mode = 0755;
+
         r = resolve_mutable_directory(hierarchy, workspace_path, &resolved_mutable_directory);
         if (r < 0)
                 return r;
@@ -845,6 +858,7 @@ static int overlayfs_paths_new(const char *hierarchy, const char *workspace_path
 
         *op = (OverlayFSPaths) {
                 .hierarchy = TAKE_PTR(hierarchy_copy),
+                .hierarchy_mode = hierarchy_mode,
                 .resolved_hierarchy = TAKE_PTR(resolved_hierarchy),
                 .resolved_mutable_directory = TAKE_PTR(resolved_mutable_directory),
         };
@@ -1137,6 +1151,7 @@ static int mount_overlayfs_with_op(
                 const char *meta_path) {
 
         int r;
+        const char* top_layer = NULL;
 
         assert(op);
         assert(overlay_path);
@@ -1153,8 +1168,19 @@ static int mount_overlayfs_with_op(
                 r = mkdir_p(op->work_dir, 0700);
                 if (r < 0)
                         return log_error_errno(r, "Failed to make directory '%s': %m", op->work_dir);
+                top_layer = op->upper_dir;
+        } else {
+                assert(!strv_isempty(op->lower_dirs));
+                top_layer = op->lower_dirs[0];
         }
 
+        /* Overlayfs merged directory has the same mode as the top layer (either first lowerdir in options in
+         * read-only case, or upperdir for mutable case. Set up top overlayfs layer to the same mode as the
+         * unmerged hierarchy, otherwise we might end up with merged hierarchy owned by root and with mode
+         * being 0700. */
+        if (chmod(top_layer, op->hierarchy_mode) < 0)
+                return log_error_errno(errno, "Failed to set permissions of '%s' to %04o: %m", top_layer, op->hierarchy_mode);
+
         r = mount_overlayfs(image_class, noexec, overlay_path, op->lower_dirs, op->upper_dir, op->work_dir);
         if (r < 0)
                 return r;