chiark / gitweb /
systemd: bind udev control socket in systemd and split udev.service
authorKay Sievers <kay.sievers@vrfy.org>
Wed, 23 Mar 2011 15:40:23 +0000 (16:40 +0100)
committerKay Sievers <kay.sievers@vrfy.org>
Wed, 23 Mar 2011 15:40:23 +0000 (16:40 +0100)
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
configure.ac
init/udev-trigger.service.in [new file with mode: 0644]
init/udev.service.in
init/udev.socket [new file with mode: 0644]
libudev/libudev-ctrl.c
libudev/libudev-private.h
udev/udevd.c

index 40f13e7..7ad9a24 100644 (file)
@@ -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
index 4ba5e32..1775fb0 100644 (file)
@@ -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 (file)
index 0000000..0ede317
--- /dev/null
@@ -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
index 908c8e9..c02a4b4 100644 (file)
@@ -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 (file)
index 0000000..324ab47
--- /dev/null
@@ -0,0 +1,5 @@
+[Unit]
+Description=udev Kernel Device Manager Socket
+
+[Socket]
+ListenDatagram=@/org/kernel/udev/udevd
index af59c36..63bf539 100644 (file)
@@ -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;
 }
 
index bd31793..1061256 100644 (file)
@@ -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);
index ef82f72..1871474 100644 (file)
@@ -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;
        }