]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-server: make sd_dhcp_server_set_lease_file() optionally take directory fd
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 13 Mar 2024 17:05:30 +0000 (02:05 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 14 Mar 2024 19:15:10 +0000 (04:15 +0900)
Currently, though, no valid directory fd is passed to the function call.
Preparation for later commits.

src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/fuzz-dhcp-server.c
src/libsystemd-network/sd-dhcp-server-lease.c
src/libsystemd-network/sd-dhcp-server.c
src/network/networkd-dhcp-server.c
src/systemd/sd-dhcp-server.h

index 8f5707c8e2895053e5b738a18aa161261d2a5d0f..0b2fa9652414e354caaf9f9e7acd1f255c3cc1d6 100644 (file)
@@ -76,6 +76,7 @@ struct sd_dhcp_server {
         char *agent_circuit_id;
         char *agent_remote_id;
 
+        int lease_dir_fd;
         char *lease_file;
 };
 
index f30ea6353ea911e4817503f534802326c643336e..c8b03781d04921d8939b4bd1d5b81dc125abf602 100644 (file)
@@ -69,7 +69,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
         struct in_addr address = { .s_addr = htobe32(UINT32_C(10) << 24 | UINT32_C(1))};
         _cleanup_free_ uint8_t *duped = NULL;
-        _cleanup_free_ char *lease_file = NULL;
+        _cleanup_close_ int dir_fd = -EBADF;
 
         if (size < sizeof(DHCPMessage))
                 return 0;
@@ -78,12 +78,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
         assert_se(duped = memdup(data, size));
 
-        assert_se(mkdtemp_malloc(NULL, &tmpdir) >= 0);
-        assert_se(lease_file = path_join(tmpdir, "leases"));
+        dir_fd = mkdtemp_open(NULL, 0, &tmpdir);
+        assert_se(dir_fd >= 0);
 
         assert_se(sd_dhcp_server_new(&server, 1) >= 0);
         assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
-        assert_se(sd_dhcp_server_set_lease_file(server, lease_file) >= 0);
+        assert_se(sd_dhcp_server_set_lease_file(server, dir_fd, "leases") >= 0);
         server->fd = open("/dev/null", O_RDWR|O_CLOEXEC|O_NOCTTY);
         assert_se(server->fd >= 0);
         assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0);
index f4c7e8d0a47d4d33df88a8005e9c62bc48500c78..52abb87c1fadb60b84455e6e6239dd0804139cda 100644 (file)
@@ -286,7 +286,7 @@ int dhcp_server_static_leases_append_json(sd_dhcp_server *server, JsonVariant **
 
 int dhcp_server_save_leases(sd_dhcp_server *server) {
         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
-        _cleanup_(unlink_and_freep) char *temp_path = NULL;
+        _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         sd_id128_t boot_id;
         int r;
@@ -315,11 +315,11 @@ int dhcp_server_save_leases(sd_dhcp_server *server) {
         if (r < 0)
                 return r;
 
-        r = mkdir_parents(server->lease_file, 0755);
+        r = mkdirat_parents(server->lease_dir_fd, server->lease_file, 0755);
         if (r < 0)
                 return r;
 
-        r = fopen_temporary(server->lease_file, &f, &temp_path);
+        r = fopen_temporary_at(server->lease_dir_fd, server->lease_file, &f, &temp_path);
         if (r < 0)
                 return r;
 
@@ -327,14 +327,17 @@ int dhcp_server_save_leases(sd_dhcp_server *server) {
 
         r = json_variant_dump(v, JSON_FORMAT_NEWLINE | JSON_FORMAT_FLUSH, f, /* prefix = */ NULL);
         if (r < 0)
-                return r;
+                goto failure;
 
-        r = conservative_rename(temp_path, server->lease_file);
+        r = conservative_renameat(server->lease_dir_fd, temp_path, server->lease_dir_fd, server->lease_file);
         if (r < 0)
-                return r;
+                goto failure;
 
-        temp_path = mfree(temp_path);
         return 0;
+
+failure:
+        (void) unlinkat(server->lease_dir_fd, temp_path, /* flags = */ 0);
+        return r;
 }
 
 static int json_dispatch_dhcp_lease(sd_dhcp_server *server, JsonVariant *v, bool use_boottime) {
@@ -445,8 +448,9 @@ int dhcp_server_load_leases(sd_dhcp_server *server) {
         if (!server->lease_file)
                 return 0;
 
-        r = json_parse_file(
+        r = json_parse_file_at(
                         /* f = */ NULL,
+                        server->lease_dir_fd,
                         server->lease_file,
                         /* flags = */ 0,
                         &v,
index bbe96be83463b87e9bcc71c77064e3b0087669b1..6ec84405d9a279a0b8ad89ee2c0c9f23342cc6f6 100644 (file)
@@ -144,6 +144,7 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
         free(server->agent_circuit_id);
         free(server->agent_remote_id);
 
+        safe_close(server->lease_dir_fd);
         free(server->lease_file);
 
         free(server->ifname);
@@ -174,6 +175,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
                 .default_lease_time = DHCP_DEFAULT_LEASE_TIME_USEC,
                 .max_lease_time = DHCP_MAX_LEASE_TIME_USEC,
                 .rapid_commit = true,
+                .lease_dir_fd = -EBADF,
         };
 
         *ret = TAKE_PTR(server);
@@ -1586,12 +1588,34 @@ int sd_dhcp_server_set_relay_agent_information(
         return 0;
 }
 
-int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, const char *path) {
+int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char *path) {
+        int r;
+
         assert_return(server, -EINVAL);
         assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
 
-        if (path && !path_is_safe(path))
+        if (!path) {
+                /* When NULL, clear the previous assignment. */
+                server->lease_file = mfree(server->lease_file);
+                server->lease_dir_fd = safe_close(server->lease_dir_fd);
+                return 0;
+        }
+
+        if (!path_is_safe(path))
                 return -EINVAL;
 
-        return free_and_strdup(&server->lease_file, path);
+        if (dir_fd < 0 && dir_fd != AT_FDCWD)
+                return -EBADF;
+
+        _cleanup_close_ int fd = -EBADF;
+        fd = fd_reopen(dir_fd, O_CLOEXEC | O_DIRECTORY | O_PATH);
+        if (fd < 0)
+                return fd;
+
+        r = free_and_strdup(&server->lease_file, path);
+        if (r < 0)
+                return r;
+
+        server->lease_dir_fd = TAKE_FD(fd);
+        return 0;
 }
index eddbaad917ce5e92ff440e1a2628b3305168a3d9..b7bae37a4dd9da01de8d75dfacb1b5de805ccda0 100644 (file)
@@ -577,7 +577,7 @@ static int dhcp4_server_configure(Link *link) {
                 if (!lease_file)
                         return log_oom();
 
-                r = sd_dhcp_server_set_lease_file(link->dhcp_server, lease_file);
+                r = sd_dhcp_server_set_lease_file(link->dhcp_server, AT_FDCWD, lease_file);
                 if (r < 0)
                         log_link_warning_errno(link, r, "Failed to load DHCPv4 server leases, ignoring: %m");
         }
index 486af48b25175a97512307d2afdffb03b5d1b99c..1bba7a6077089d81d9a909721c4f6b8d9645413a 100644 (file)
@@ -81,7 +81,7 @@ int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[],
 int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v);
 int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v);
 int sd_dhcp_server_set_static_lease(sd_dhcp_server *server, const struct in_addr *address, uint8_t *client_id, size_t client_id_size);
-int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, const char *path);
+int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char *path);
 
 int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint64_t t);
 int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint64_t t);