From 3cabdc2345608b01e344a52fe6f8c3c378406ebc Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Tue, 26 Nov 2019 18:36:46 +0100 Subject: [PATCH 1/2] Revert "udevd: fix crash when workers time out after exit is signal caught" This reverts commit 5db454b8031c58a743cc4ee3d5d1dd01dcff17e8. See https://github.com/systemd/systemd/issues/14128 --- src/udev/udevd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 2bb322796b2..144a20ec63f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -293,8 +293,6 @@ static void manager_free(Manager *manager) { if (!manager) return; - manager->monitor = sd_device_monitor_unref(manager->monitor); - udev_builtin_exit(); if (manager->pid == getpid_cached()) @@ -791,6 +789,8 @@ static void manager_exit(Manager *manager) { manager->inotify_event = sd_event_source_unref(manager->inotify_event); manager->fd_inotify = safe_close(manager->fd_inotify); + manager->monitor = sd_device_monitor_unref(manager->monitor); + /* discard queued events and kill workers */ event_queue_cleanup(manager, EVENT_QUEUED); manager_kill_workers(manager); From 030f4571670537c76355c5d923468c9a61aa77e9 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Tue, 26 Nov 2019 18:39:09 +0100 Subject: [PATCH 2/2] udevd: don't use monitor after manager_exit() If udevd receives an exit signal, it releases its reference on the udev monitor in manager_exit(). If at this time a worker is hanging, and if the event timeout for this worker expires before udevd exits, udevd crashes in on_sigchld()->udev_monitor_send_device(), because the monitor has already been freed. Fix this by testing the validity of manager->monitor in on_sigchld(). --- src/udev/udevd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 144a20ec63f..7678331897f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1311,10 +1311,12 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi device_delete_db(worker->event->dev); device_tag_index(worker->event->dev, NULL, false); - /* forward kernel event without amending it */ - r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); - if (r < 0) - log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); + if (manager->monitor) { + /* forward kernel event without amending it */ + r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); + if (r < 0) + log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); + } } worker_free(worker);