From fc1de713f5b754fb38876b5b797e18f812727f0a Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 23 Mar 2011 16:40:23 +0100 Subject: [PATCH] systemd: bind udev control socket in systemd and split udev.service We should bind the udev socket from systemd, so we are sure that the abstract namespace socket is always bound by a root process and there is never a window during an update where an untrusted process can steal our socket. Also split the udev.service file, so that the daemon can be updated/restarted without triggering any coldplug events. --- Makefile.am | 8 +++++++- configure.ac | 1 + init/udev-trigger.service.in | 11 ++++++++++ init/udev.service.in | 5 +++-- init/udev.socket | 5 +++++ libudev/libudev-ctrl.c | 39 ++++++++++++++++++++++++++++-------- libudev/libudev-private.h | 1 + udev/udevd.c | 14 ++++++++----- 8 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 init/udev-trigger.service.in create mode 100644 init/udev.socket diff --git a/Makefile.am b/Makefile.am index 40f13e790..7ad9a242b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,14 +124,20 @@ sharepkgconfig_DATA = udev/udev.pc if WITH_SYSTEMD systemdsystemunit_DATA = \ + init/udev.socket \ init/udev.service \ + init/udev-trigger.service \ init/udev-settle.service +EXTRA_DIST += init/udev.socket + systemd-install-hook: + mkdir -p $(DESTDIR)$(systemdsystemunitdir)/socket.target.wants + ln -sf ../udev.socket $(DESTDIR)$(systemdsystemunitdir)/socket.target.wants/udev.socket mkdir -p $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants ln -sf ../udev.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev.service + ln -sf ../udev-trigger.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev-trigger.service ln -sf ../udev-settle.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev-settle.service - ln -sf ../udev-retry.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev-retry.service INSTALL_DATA_HOOKS += systemd-install-hook endif diff --git a/configure.ac b/configure.ac index 4ba5e32f3..1775fb072 100644 --- a/configure.ac +++ b/configure.ac @@ -137,6 +137,7 @@ AC_CONFIG_FILES([ Makefile udev/udev.pc init/udev.service + init/udev-trigger.service init/udev-settle.service libudev/libudev.pc libudev/docs/Makefile diff --git a/init/udev-trigger.service.in b/init/udev-trigger.service.in new file mode 100644 index 000000000..0ede3171e --- /dev/null +++ b/init/udev-trigger.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=udev Coldplug all Devices +Requires=udev.service +After=udev.service +Before=basic.target +DefaultDependencies=no + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=@sbindir@/udevadm trigger --type=subsystems --action=add ; @sbindir@/udevadm trigger --type=devices --action=add diff --git a/init/udev.service.in b/init/udev.service.in index 908c8e9ac..c02a4b4d8 100644 --- a/init/udev.service.in +++ b/init/udev.service.in @@ -1,9 +1,10 @@ [Unit] Description=udev Kernel Device Manager -DefaultDependencies=no +Requires=udev.socket +After=udev.socket Before=basic.target +DefaultDependencies=no [Service] Type=notify ExecStart=@sbindir@/udevd -ExecStartPost=@sbindir@/udevadm trigger --type=subsystems --action=add ; @sbindir@/udevadm trigger --type=devices --action=add diff --git a/init/udev.socket b/init/udev.socket new file mode 100644 index 000000000..324ab4709 --- /dev/null +++ b/init/udev.socket @@ -0,0 +1,5 @@ +[Unit] +Description=udev Kernel Device Manager Socket + +[Socket] +ListenDatagram=@/org/kernel/udev/udevd diff --git a/libudev/libudev-ctrl.c b/libudev/libudev-ctrl.c index af59c3682..63bf53919 100644 --- a/libudev/libudev-ctrl.c +++ b/libudev/libudev-ctrl.c @@ -61,7 +61,7 @@ struct udev_ctrl { socklen_t addrlen; }; -struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path) +static struct udev_ctrl *udev_ctrl_new(struct udev *udev) { struct udev_ctrl *uctrl; @@ -70,6 +70,16 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke return NULL; uctrl->refcount = 1; uctrl->udev = udev; + return uctrl; +} + +struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path) +{ + struct udev_ctrl *uctrl; + + uctrl = udev_ctrl_new(udev); + if (uctrl == NULL) + return NULL; uctrl->sock = socket(AF_LOCAL, SOCK_DGRAM, 0); if (uctrl->sock < 0) { @@ -84,6 +94,17 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke /* translate leading '@' to abstract namespace */ if (uctrl->saddr.sun_path[0] == '@') uctrl->saddr.sun_path[0] = '\0'; + return uctrl; +} + +struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) +{ + struct udev_ctrl *uctrl; + + uctrl = udev_ctrl_new(udev); + if (uctrl == NULL) + return NULL; + uctrl->sock = fd; return uctrl; } @@ -91,16 +112,18 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) { int err; - const int feature_on = 1; - - err= bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen); - if (err < 0) { - err(uctrl->udev, "bind failed: %m\n"); - return err; + const int on = 1; + + if (uctrl->addrlen > 0) { + err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen); + if (err < 0) { + err(uctrl->udev, "bind failed: %m\n"); + return err; + } } /* enable receiving of the sender credentials */ - setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); + setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); return 0; } diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h index bd317933b..10612560f 100644 --- a/libudev/libudev-private.h +++ b/libudev/libudev-private.h @@ -125,6 +125,7 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, /* libudev-ctrl.c - daemon runtime setup */ struct udev_ctrl; struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path); +struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd); int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl); struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl); void udev_ctrl_unref(struct udev_ctrl *uctrl); diff --git a/udev/udevd.c b/udev/udevd.c index ef82f72d0..1871474ff 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -1228,16 +1228,20 @@ int main(int argc, char *argv[]) if (write(STDERR_FILENO, 0, 0) < 0) dup2(fd, STDERR_FILENO); - udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); + /* udevadm control socket */ + if (sd_listen_fds(true) == 1 && sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_DGRAM, -1)) + udev_ctrl = udev_ctrl_new_from_fd(udev, SD_LISTEN_FDS_START); + else + udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); if (udev_ctrl == NULL) { - fprintf(stderr, "error initializing control socket"); - err(udev, "error initializing udevd socket"); + fprintf(stderr, "error initializing udev control socket"); + err(udev, "error initializing udev control socket"); rc = 1; goto exit; } if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { - fprintf(stderr, "error binding control socket, seems udevd is already running\n"); - err(udev, "error binding control socket, seems udevd is already running\n"); + fprintf(stderr, "error binding udev control socket\n"); + err(udev, "error binding udev control socket\n"); rc = 1; goto exit; } -- 2.30.2