]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd/sd-device/device-monitor.c
tree-wide: make sure our control buffers are properly aligned
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-monitor.c
index da99971b0296fb61ad68409bf6ffe2cee2233a9c..20a422c77cf347add270c7d417b486ab2ee62c70 100644 (file)
@@ -3,7 +3,7 @@
 #include <errno.h>
 #include <linux/filter.h>
 #include <linux/netlink.h>
-#include <sys/socket.h>
+#include <unistd.h>
 
 #include "sd-device.h"
 #include "sd-event.h"
@@ -16,8 +16,8 @@
 #include "fd-util.h"
 #include "format-util.h"
 #include "hashmap.h"
-#include "missing.h"
-#include "mount-util.h"
+#include "io-util.h"
+#include "mountpoint-util.h"
 #include "set.h"
 #include "socket-util.h"
 #include "string-util.h"
@@ -92,8 +92,8 @@ _public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, siz
         assert_return(m, -EINVAL);
         assert_return((size_t) n == size, -EINVAL);
 
-        if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n) < 0) {
-                r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n);
+        if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n) < 0) {
+                r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n);
                 if (r < 0)
                         return r;
         }
@@ -246,7 +246,7 @@ _public_ int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *even
         else {
                 r = sd_event_default(&m->event);
                 if (r < 0)
-                        return 0;
+                        return r;
         }
 
         return 0;
@@ -269,27 +269,25 @@ int device_monitor_enable_receiving(sd_device_monitor *m) {
 
         assert_return(m, -EINVAL);
 
-        if (!m->filter_uptodate) {
-                r = sd_device_monitor_filter_update(m);
-                if (r < 0)
-                        return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m");
-        }
+        r = sd_device_monitor_filter_update(m);
+        if (r < 0)
+                return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m");
 
         if (!m->bound) {
+                /* enable receiving of sender credentials */
+                r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
+                if (r < 0)
+                        return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m");
+
                 if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0)
-                        return log_debug_errno(errno, "sd-device-monitor: Failed to bind monitoring socket to event source: %m");
+                        return log_debug_errno(errno, "sd-device-monitor: Failed to bind monitoring socket: %m");
 
                 m->bound = true;
-        }
 
-        r = monitor_set_nl_address(m);
-        if (r < 0)
-                return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m");
-
-        /* enable receiving of sender credentials */
-        r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
-        if (r < 0)
-                return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m");
+                r = monitor_set_nl_address(m);
+                if (r < 0)
+                        return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m");
+        }
 
         return 0;
 }
@@ -363,13 +361,13 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
                 .iov_base = &buf,
                 .iov_len = sizeof(buf)
         };
-        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control;
         union sockaddr_union snl;
         struct msghdr smsg = {
                 .msg_iov = &iov,
                 .msg_iovlen = 1,
-                .msg_control = cred_msg,
-                .msg_controllen = sizeof(cred_msg),
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
                 .msg_name = &snl,
                 .msg_namelen = sizeof(snl),
         };
@@ -389,35 +387,42 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
         }
 
         if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC))
-                return log_debug_errno(EINVAL, "sd-device-monitor: Invalid message length.");
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "sd-device-monitor: Invalid message length.");
 
         if (snl.nl.nl_groups == MONITOR_GROUP_NONE) {
                 /* unicast message, check if we trust the sender */
                 if (m->snl_trusted_sender.nl.nl_pid == 0 ||
                     snl.nl.nl_pid != m->snl_trusted_sender.nl.nl_pid)
-                        return log_debug_errno(EAGAIN, "sd-device-monitor: Unicast netlink message ignored.");
+                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                               "sd-device-monitor: Unicast netlink message ignored.");
 
         } else if (snl.nl.nl_groups == MONITOR_GROUP_KERNEL) {
                 if (snl.nl.nl_pid > 0)
-                        return log_debug_errno(EAGAIN, "sd-device-monitor: Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
+                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                               "sd-device-monitor: Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
         }
 
         cmsg = CMSG_FIRSTHDR(&smsg);
         if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
-                return log_debug_errno(EAGAIN, "sd-device-monitor: No sender credentials received, message ignored.");
+                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                       "sd-device-monitor: No sender credentials received, message ignored.");
 
         cred = (struct ucred*) CMSG_DATA(cmsg);
         if (cred->uid != 0)
-                return log_debug_errno(EAGAIN, "sd-device-monitor: Sender uid="UID_FMT", message ignored.", cred->uid);
+                return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                       "sd-device-monitor: Sender uid="UID_FMT", message ignored.", cred->uid);
 
         if (streq(buf.raw, "libudev")) {
                 /* udev message needs proper version magic */
                 if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC))
-                        return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message signature (%x != %x)",
+                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                               "sd-device-monitor: Invalid message signature (%x != %x)",
                                                buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
 
                 if (buf.nlh.properties_off+32 > (size_t) buflen)
-                        return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message length (%u > %zd)",
+                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                               "sd-device-monitor: Invalid message length (%u > %zd)",
                                                buf.nlh.properties_off+32, buflen);
 
                 bufpos = buf.nlh.properties_off;
@@ -429,11 +434,13 @@ int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
                 /* kernel message with header */
                 bufpos = strlen(buf.raw) + 1;
                 if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen)
-                        return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message length");
+                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                               "sd-device-monitor: Invalid message length");
 
                 /* check message header */
                 if (!strstr(buf.raw, "@/"))
-                        return log_debug_errno(EAGAIN, "sd-device-monitor: Invalid message header");
+                        return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+                                               "sd-device-monitor: Invalid message header");
         }
 
         r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos);
@@ -532,10 +539,7 @@ int device_monitor_send_device(
         /* add properties list */
         nlh.properties_off = iov[0].iov_len;
         nlh.properties_len = blen;
-        iov[1] = (struct iovec) {
-                .iov_base = (char*) buf,
-                .iov_len = blen,
-        };
+        iov[1] = IOVEC_MAKE((char*) buf, blen);
 
         /*
          * Use custom address for target, or the default one.
@@ -586,6 +590,9 @@ _public_ int sd_device_monitor_filter_update(sd_device_monitor *m) {
 
         assert_return(m, -EINVAL);
 
+        if (m->filter_uptodate)
+                return 0;
+
         if (hashmap_isempty(m->subsystem_filter) &&
             set_isempty(m->tag_filter)) {
                 m->filter_uptodate = true;
@@ -639,13 +646,12 @@ _public_ int sd_device_monitor_filter_update(sd_device_monitor *m) {
                                 /* jump if subsystem does not match */
                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
                         } else {
-                                hash = string_hash32(devtype);
-
                                 /* jump if subsystem does not match */
                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
                                 /* load device devtype value in A */
                                 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_devtype_hash));
                                 /* jump if value does not match */
+                                hash = string_hash32(devtype);
                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
                         }
 
@@ -741,7 +747,7 @@ _public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) {
         m->subsystem_filter = hashmap_free_free_free(m->subsystem_filter);
         m->tag_filter = set_free_free(m->tag_filter);
 
-        if (setsockopt(m->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
+        if (setsockopt(m->sock, SOL_SOCKET, SO_DETACH_FILTER, &filter, sizeof(filter)) < 0)
                 return -errno;
 
         m->filter_uptodate = true;