]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mountfsd: optionally accept an access mode for the dir created by MakeDirectory()
authorLennart Poettering <lennart@poettering.net>
Thu, 20 Nov 2025 12:12:40 +0000 (13:12 +0100)
committerLennart Poettering <lennart@poettering.net>
Sun, 21 Dec 2025 06:04:42 +0000 (07:04 +0100)
So far we expected the client to access the access mode themselves, and
set a restrictive 0700 server-side.

However, in some scenarios it's handy if the inode is created
server-side already with the right mode, in particular when the client
doesn't do anything with the dir just yet, and just needs it to be there
with the right mode. If it has to adjust the mode client-side it might
otherwise need to fork something off, join the selected userns, adjust
the mode, and kill the child off again.

src/mountfsd/mountwork.c
src/shared/varlink-io.systemd.MountFileSystem.c

index 24f6e23e231ca3c33346fb5d3379baf3e9296c99..0e0bd964eebede0b874fa944db40d62402b7c1f8 100644 (file)
@@ -1003,6 +1003,7 @@ static int vl_method_mount_directory(
 typedef struct MakeDirectoryParameters {
         unsigned parent_fd_idx;
         const char *name;
+        mode_t mode;
 } MakeDirectoryParameters;
 
 static int vl_method_make_directory(
@@ -1012,14 +1013,16 @@ static int vl_method_make_directory(
                 void *userdata) {
 
         static const sd_json_dispatch_field dispatch_table[] = {
-                { "parentFileDescriptor", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint,        offsetof(MakeDirectoryParameters, parent_fd_idx), SD_JSON_MANDATORY },
-                { "name",                 SD_JSON_VARIANT_STRING,   json_dispatch_const_filename, offsetof(MakeDirectoryParameters, name),          SD_JSON_MANDATORY },
+                { "parentFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint,        offsetof(MakeDirectoryParameters, parent_fd_idx), SD_JSON_MANDATORY },
+                { "name",                 SD_JSON_VARIANT_STRING,        json_dispatch_const_filename, offsetof(MakeDirectoryParameters, name),          SD_JSON_MANDATORY },
+                { "mode",                 _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_access_mode,    offsetof(MakeDirectoryParameters, mode),          SD_JSON_STRICT    },
                 VARLINK_DISPATCH_POLKIT_FIELD,
                 {}
         };
 
         MakeDirectoryParameters p = {
                 .parent_fd_idx = UINT_MAX,
+                .mode = MODE_INVALID,
         };
         Hashmap **polkit_registry = ASSERT_PTR(userdata);
         int r;
@@ -1028,6 +1031,11 @@ static int vl_method_make_directory(
         if (r != 0)
                 return r;
 
+        if (p.mode == MODE_INVALID)
+                p.mode = 0700;
+        else
+                p.mode &= 0775; /* refuse generating world writable dirs */
+
         if (p.parent_fd_idx == UINT_MAX)
                 return sd_varlink_error_invalid_parameter_name(link, "parentFileDescriptor");
 
@@ -1089,11 +1097,11 @@ static int vl_method_make_directory(
         if (r < 0)
                 return r;
 
-        _cleanup_close_ int fd = open_mkdir_at(parent_fd, t, O_CLOEXEC, 0700);
+        _cleanup_close_ int fd = open_mkdir_at(parent_fd, t, O_CLOEXEC, p.mode);
         if (fd < 0)
                 return fd;
 
-        r = RET_NERRNO(fchmod(fd, 0700)); /* Set mode explicitly, as paranoia regarding umask games */
+        r = RET_NERRNO(fchmod(fd, p.mode)); /* Set mode explicitly, as paranoia regarding umask games */
         if (r < 0)
                 goto fail;
 
index e9c69f07d825817d3a1e837e3d08ef7843db1cba..356f9938aaa132224972ad76f1dcee5eaa2d8ad5 100644 (file)
@@ -113,6 +113,8 @@ static SD_VARLINK_DEFINE_METHOD(
                 SD_VARLINK_DEFINE_INPUT(parentFileDescriptor, SD_VARLINK_INT, 0),
                 SD_VARLINK_FIELD_COMMENT("Name of the directory to create."),
                 SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0),
+                SD_VARLINK_FIELD_COMMENT("Access mode of the directory to create. Note that the suid, sgid, sticky, world-writable bit is unconditionally masked off."),
+                SD_VARLINK_DEFINE_INPUT(mode, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
                 VARLINK_DEFINE_POLKIT_INPUT,
                 SD_VARLINK_FIELD_COMMENT("File descriptor referencing the newly created directory."),
                 SD_VARLINK_DEFINE_OUTPUT(directoryFileDescriptor, SD_VARLINK_INT, 0));