From: Kai Lueke Date: Tue, 2 Dec 2025 15:02:32 +0000 (+0900) Subject: sysext: Create mutable directory with the right mode X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e4c2f8df781902db47f31ebe48b1e819955edf9;p=thirdparty%2Fsystemd.git sysext: Create mutable directory with the right mode When the mutable directory didn't exist but gets created with --mutable=yes then it used to get mode 700 and later it got patched by a chmod because it is the top layer and must match the target hierarchy. This meant one could not call the function to resolve the mutable directory twice before the mount because it has a check for a proper mode when the directory exists which is the case for the second call. Also, this resulted in /var/lib/extensions.mutable getting created with mode 700 which is not really required. Don't rely on the chmod for the upper dir but directly create the directory with the right mode by first creating all missing directories with 755 as a sane default and then changing the mode as needed for the mutable directory. --- diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index ea3ebceab53..5374a89a659 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -1037,23 +1037,25 @@ static int resolve_mutable_directory( } if (IN_SET(arg_mutable, MUTABLE_YES, MUTABLE_EPHEMERAL, MUTABLE_EPHEMERAL_IMPORT)) { - _cleanup_free_ char *path_in_root = NULL; + _cleanup_close_ int path_fd = -EBADF, chmod_fd = -EBADF; - path_in_root = path_join(root, path); - if (!path_in_root) - return log_oom(); - - r = mkdir_p(path_in_root, 0700); + /* This also creates, e.g., /var/lib/extensions.mutable/usr if needed and all parent + * directories plus it also works when the last part is a symlink to the real /usr but we + * can't use chase_and_open here because it does not behave the same. */ + r = chase(path, root, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY|CHASE_PREFIX_ROOT, /* ret_path */ NULL, &path_fd); if (r < 0) - return log_error_errno(r, "Failed to create a directory '%s': %m", path_in_root); + return log_error_errno(r, "Failed to chase/create base directory '%s/%s': %m", strempty(root), skip_leading_slash(path)); + + chmod_fd = fd_reopen(path_fd, O_CLOEXEC|O_DIRECTORY); + if (chmod_fd < 0) + return log_error_errno(chmod_fd, "Failed to reopen '%s/%s': %m", strempty(root), skip_leading_slash(path)); - _cleanup_close_ int atfd = open(path_in_root, O_DIRECTORY|O_CLOEXEC); - if (atfd < 0) - return log_error_errno(errno, "Failed to open directory '%s': %m", path_in_root); + if (fchmod(chmod_fd, hierarchy_mode) < 0) + return log_error_errno(errno, "Failed to chmod directory '%s/%s': %m", strempty(root), skip_leading_slash(path)); - r = mac_selinux_fix_full(atfd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0); + r = mac_selinux_fix_full(chmod_fd, /* inode_path= */ NULL, hierarchy, /* flags= */ 0); if (r < 0) - return log_error_errno(r, "Failed to fix SELinux label for '%s': %m", path_in_root); + return log_error_errno(r, "Failed to fix SELinux label for '%s/%s': %m", strempty(root), skip_leading_slash(path)); } r = chase(path, root, CHASE_PREFIX_ROOT, &resolved_path, NULL);