]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/varlink: pass file descriptor of state directory with SetPersistentStorage...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 15 Mar 2024 15:55:10 +0000 (00:55 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 19 Mar 2024 06:15:32 +0000 (15:15 +0900)
The state directory is owned by systemd-networkd-persistent-storage.service,
at least technically. Let's not directly access the storage through the path,
but through the fd.

Addresses https://github.com/systemd/systemd/pull/31746#issuecomment-1993556966.

Suggested-by: Mike Yuan <me@yhndnzj.com>
src/network/networkctl.c
src/network/networkd-manager-varlink.c

index 7ee0961fa6a00dae1694aa6ccfc2763c27d2751e..91285e8116045f50b83e5a49224101272bc3863c 100644 (file)
@@ -102,6 +102,10 @@ static int varlink_connect_networkd(Varlink **ret_varlink) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to network service /run/systemd/netif/io.systemd.Network: %m");
 
+        r = varlink_set_allow_fd_passing_output(vl, true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allow passing file descriptor through varlink: %m");
+
         r = varlink_call_and_log(vl, "io.systemd.Network.GetNamespaceId", /* parameters= */ NULL, &reply);
         if (r < 0)
                 return r;
@@ -2943,6 +2947,20 @@ static int verb_persistent_storage(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
+        if (ready) {
+                _cleanup_close_ int fd = -EBADF;
+
+                fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+
+                r = varlink_push_fd(vl, fd);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to push file descriptor of /var/lib/systemd/network/ into varlink: %m");
+
+                TAKE_FD(fd);
+        }
+
         return varlink_callb_and_log(vl, "io.systemd.Network.SetPersistentStorage", /* reply = */ NULL,
                                      JSON_BUILD_OBJECT(JSON_BUILD_PAIR_BOOLEAN("Ready", ready)));
 }
index b1b60ac48fb77f695469d48b1e1f8b23d9630647..2ccd1df1ef3469783f921bdab77f91345eb60e85 100644 (file)
@@ -185,12 +185,18 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
                 return r;
 
         if (ready) {
-                _cleanup_close_ int fd = -EBADF;
                 struct stat st, st_prev;
+                int fd;
 
-                fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+                fd = varlink_peek_fd(vlink, 0);
                 if (fd < 0)
-                        return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+                        return log_warning_errno(fd, "Failed to peek file descriptor of the persistent storage: %m");
+
+                r = fd_verify_safe_flags_full(fd, O_DIRECTORY);
+                if (r == -EREMOTEIO)
+                        return log_warning_errno(r, "Passed persistent storage fd has unexpected flags, refusing.");
+                if (r < 0)
+                        return log_warning_errno(r, "Failed to verify flags of passed persistent storage fd: %m");
 
                 r = fd_is_read_only_fs(fd);
                 if (r < 0)
@@ -201,7 +207,11 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
                 }
 
                 if (fstat(fd, &st) < 0)
-                        return log_warning_errno(r, "Failed to stat the persistent storage: %m");
+                        return log_warning_errno(r, "Failed to stat the passed persistent storage fd: %m");
+
+                r = stat_verify_directory(&st);
+                if (r < 0)
+                        return log_warning_errno(r, "The passed persistent storage fd is not a directory, refusing: %m");
 
                 if (manager->persistent_storage_fd >= 0 &&
                     fstat(manager->persistent_storage_fd, &st_prev) >= 0 &&
@@ -225,9 +235,9 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
         if (ready) {
                 _cleanup_close_ int fd = -EBADF;
 
-                fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+                fd = varlink_take_fd(vlink, 0);
                 if (fd < 0)
-                        return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+                        return log_warning_errno(fd, "Failed to take file descriptor of the persistent storage: %m");
 
                 close_and_replace(manager->persistent_storage_fd, fd);
         } else
@@ -238,6 +248,18 @@ static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *paramet
         return varlink_reply(vlink, NULL);
 }
 
+static int on_connect(VarlinkServer *s, Varlink *vlink, void *userdata) {
+        int r;
+
+        assert(vlink);
+
+        r = varlink_set_allow_fd_passing_input(vlink, true);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to allow receiving file descriptor through varlink: %m");
+
+        return 0;
+}
+
 int manager_connect_varlink(Manager *m) {
         _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
         int r;
@@ -274,6 +296,10 @@ int manager_connect_varlink(Manager *m) {
         if (r < 0)
                 return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
 
+        r = varlink_server_bind_connect(s, on_connect);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set on-connect callback for varlink: %m");
+
         m->varlink_server = TAKE_PTR(s);
         return 0;
 }