]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-event: make pidfd copy in event_add_child_pidref()
authorLennart Poettering <lennart@poettering.net>
Wed, 19 Mar 2025 14:11:58 +0000 (15:11 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 19 Mar 2025 17:14:24 +0000 (18:14 +0100)
So far we'd directly use the pidfd passed into event_add_child_pidref(),
hoping it would not be closed by the caller before we are done. This was
violated by vmspawn however.

Let's make this safe, and simply duplicate the fd, and make us
independent of the caller.

src/libsystemd/sd-event/event-util.c
src/vmspawn/vmspawn.c

index 47cf76f9c2c9f6ae629e7c0458bf887a676f8d45..d4e986fc49105ccfe0748c2c4c5ed24da974439d 100644 (file)
@@ -165,19 +165,49 @@ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handle
 
 int event_add_child_pidref(
                 sd_event *e,
-                sd_event_source **s,
+                sd_event_source **ret,
                 const PidRef *pid,
                 int options,
                 sd_event_child_handler_t callback,
                 void *userdata) {
 
+        int r;
+
+        assert(e);
+
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
-        if (pid->fd >= 0)
-                return sd_event_add_child_pidfd(e, s, pid->fd, options, callback, userdata);
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
+        if (pid->fd < 0)
+                return sd_event_add_child(e, ret, pid->pid, options, callback, userdata);
+
+        _cleanup_close_ int copy_fd = fcntl(pid->fd, F_DUPFD_CLOEXEC, 3);
+        if (copy_fd < 0)
+                return -errno;
+
+        _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+        r = sd_event_add_child_pidfd(e, &s, copy_fd, options, callback, userdata);
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_child_pidfd_own(s, true);
+        if (r < 0)
+                return r;
+
+        TAKE_FD(copy_fd);
+
+        if (ret)
+                *ret = TAKE_PTR(s);
+        else {
+                r = sd_event_source_set_floating(s, true);
+                if (r < 0)
+                        return r;
+        }
 
-        return sd_event_add_child(e, s, pid->pid, options, callback, userdata);
+        return 0;
 }
 
 int event_source_get_child_pidref(sd_event_source *s, PidRef *ret) {
index d616f2c7ab8828c7c29d7fa7f8c6478bc19a4635..294775d03e8eced72963696e43daab1d7b45d4c1 100644 (file)
@@ -2350,7 +2350,9 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
                 log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
 
         /* Exit when the child exits */
-        (void) event_add_child_pidref(event, NULL, &child_pidref, WEXITED, on_child_exit, NULL);
+        r = event_add_child_pidref(event, /* ret_event_source= */ NULL, &child_pidref, WEXITED, on_child_exit, /* userdata= */ NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to watch qemu process: &m");
 
         _cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
         _cleanup_(pty_forward_freep) PTYForward *forward = NULL;