LCOV - code coverage report
Current view: top level - libsystemd/sd-device - device-monitor.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 166 356 46.6 %
Date: 2019-08-22 15:41:25 Functions: 19 29 65.5 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <linux/filter.h>
       5             : #include <linux/netlink.h>
       6             : #include <sys/socket.h>
       7             : 
       8             : #include "sd-device.h"
       9             : #include "sd-event.h"
      10             : 
      11             : #include "MurmurHash2.h"
      12             : #include "alloc-util.h"
      13             : #include "device-monitor-private.h"
      14             : #include "device-private.h"
      15             : #include "device-util.h"
      16             : #include "fd-util.h"
      17             : #include "format-util.h"
      18             : #include "hashmap.h"
      19             : #include "io-util.h"
      20             : #include "missing.h"
      21             : #include "mountpoint-util.h"
      22             : #include "set.h"
      23             : #include "socket-util.h"
      24             : #include "string-util.h"
      25             : #include "strv.h"
      26             : 
      27             : struct sd_device_monitor {
      28             :         unsigned n_ref;
      29             : 
      30             :         int sock;
      31             :         union sockaddr_union snl;
      32             :         union sockaddr_union snl_trusted_sender;
      33             :         bool bound;
      34             : 
      35             :         Hashmap *subsystem_filter;
      36             :         Set *tag_filter;
      37             :         bool filter_uptodate;
      38             : 
      39             :         sd_event *event;
      40             :         sd_event_source *event_source;
      41             :         sd_device_monitor_handler_t callback;
      42             :         void *userdata;
      43             : };
      44             : 
      45             : #define UDEV_MONITOR_MAGIC                0xfeedcafe
      46             : 
      47             : typedef struct monitor_netlink_header {
      48             :         /* "libudev" prefix to distinguish libudev and kernel messages */
      49             :         char prefix[8];
      50             :         /* Magic to protect against daemon <-> Library message format mismatch
      51             :          * Used in the kernel from socket filter rules; needs to be stored in network order */
      52             :         unsigned magic;
      53             :         /* Total length of header structure known to the sender */
      54             :         unsigned header_size;
      55             :         /* Properties string buffer */
      56             :         unsigned properties_off;
      57             :         unsigned properties_len;
      58             :         /* Hashes of primary device properties strings, to let libudev subscribers
      59             :          * use in-kernel socket filters; values need to be stored in network order */
      60             :         unsigned filter_subsystem_hash;
      61             :         unsigned filter_devtype_hash;
      62             :         unsigned filter_tag_bloom_hi;
      63             :         unsigned filter_tag_bloom_lo;
      64             : } monitor_netlink_header;
      65             : 
      66          12 : static int monitor_set_nl_address(sd_device_monitor *m) {
      67             :         union sockaddr_union snl;
      68             :         socklen_t addrlen;
      69             : 
      70          12 :         assert(m);
      71             : 
      72             :         /* Get the address the kernel has assigned us.
      73             :          * It is usually, but not necessarily the pid. */
      74          12 :         addrlen = sizeof(struct sockaddr_nl);
      75          12 :         if (getsockname(m->sock, &snl.sa, &addrlen) < 0)
      76           0 :                 return -errno;
      77             : 
      78          12 :         m->snl.nl.nl_pid = snl.nl.nl_pid;
      79          12 :         return 0;
      80             : }
      81             : 
      82           0 : int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor *sender) {
      83           0 :         assert_return(m, -EINVAL);
      84           0 :         assert_return(sender, -EINVAL);
      85             : 
      86           0 :         m->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
      87           0 :         return 0;
      88             : }
      89             : 
      90          11 : _public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size) {
      91          11 :         int r, n = (int) size;
      92             : 
      93          11 :         assert_return(m, -EINVAL);
      94          11 :         assert_return((size_t) n == size, -EINVAL);
      95             : 
      96          11 :         if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n) < 0) {
      97          11 :                 r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n);
      98          11 :                 if (r < 0)
      99           0 :                         return r;
     100             :         }
     101             : 
     102          11 :         return 0;
     103             : }
     104             : 
     105          12 : int device_monitor_disconnect(sd_device_monitor *m) {
     106          12 :         assert(m);
     107             : 
     108          12 :         m->sock = safe_close(m->sock);
     109          12 :         return 0;
     110             : }
     111             : 
     112           0 : int device_monitor_get_fd(sd_device_monitor *m) {
     113           0 :         assert_return(m, -EINVAL);
     114             : 
     115           0 :         return m->sock;
     116             : }
     117             : 
     118          12 : int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, int fd) {
     119          12 :         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
     120          12 :         _cleanup_close_ int sock = -1;
     121             :         int r;
     122             : 
     123          12 :         assert_return(ret, -EINVAL);
     124          12 :         assert_return(group >= 0 && group < _MONITOR_NETLINK_GROUP_MAX, -EINVAL);
     125             : 
     126          24 :         if (group == MONITOR_GROUP_UDEV &&
     127          12 :             access("/run/udev/control", F_OK) < 0 &&
     128           0 :             dev_is_devtmpfs() <= 0) {
     129             : 
     130             :                 /*
     131             :                  * We do not support subscribing to uevents if no instance of
     132             :                  * udev is running. Uevents would otherwise broadcast the
     133             :                  * processing data of the host into containers, which is not
     134             :                  * desired.
     135             :                  *
     136             :                  * Containers will currently not get any udev uevents, until
     137             :                  * a supporting infrastructure is available.
     138             :                  *
     139             :                  * We do not set a netlink multicast group here, so the socket
     140             :                  * will not receive any messages.
     141             :                  */
     142             : 
     143           0 :                 log_debug("sd-device-monitor: The udev service seems not to be active, disabling the monitor");
     144           0 :                 group = MONITOR_GROUP_NONE;
     145             :         }
     146             : 
     147          12 :         if (fd < 0) {
     148          12 :                 sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
     149          12 :                 if (sock < 0)
     150           0 :                         return log_debug_errno(errno, "sd-device-monitor: Failed to create socket: %m");
     151             :         }
     152             : 
     153          12 :         m = new(sd_device_monitor, 1);
     154          12 :         if (!m)
     155           0 :                 return -ENOMEM;
     156             : 
     157          36 :         *m = (sd_device_monitor) {
     158             :                 .n_ref = 1,
     159          12 :                 .sock = fd >= 0 ? fd : TAKE_FD(sock),
     160          12 :                 .bound = fd >= 0,
     161             :                 .snl.nl.nl_family = AF_NETLINK,
     162             :                 .snl.nl.nl_groups = group,
     163             :         };
     164             : 
     165          12 :         if (fd >= 0) {
     166           0 :                 r = monitor_set_nl_address(m);
     167           0 :                 if (r < 0)
     168           0 :                         return log_debug_errno(r, "sd-device-monitor: Failed to set netlink address: %m");
     169             :         }
     170             : 
     171          12 :         *ret = TAKE_PTR(m);
     172          12 :         return 0;
     173             : }
     174             : 
     175          12 : _public_ int sd_device_monitor_new(sd_device_monitor **ret) {
     176          12 :         return device_monitor_new_full(ret, MONITOR_GROUP_UDEV, -1);
     177             : }
     178             : 
     179          12 : _public_ int sd_device_monitor_stop(sd_device_monitor *m) {
     180          12 :         assert_return(m, -EINVAL);
     181             : 
     182          12 :         m->event_source = sd_event_source_unref(m->event_source);
     183          12 :         (void) device_monitor_disconnect(m);
     184             : 
     185          12 :         return 0;
     186             : }
     187             : 
     188           0 : static int device_monitor_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     189           0 :         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
     190           0 :         sd_device_monitor *m = userdata;
     191             : 
     192           0 :         assert(m);
     193             : 
     194           0 :         if (device_monitor_receive_device(m, &device) <= 0)
     195           0 :                 return 0;
     196             : 
     197           0 :         if (m->callback)
     198           0 :                 return m->callback(m, device, m->userdata);
     199             : 
     200           0 :         return 0;
     201             : }
     202             : 
     203          12 : _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata) {
     204             :         int r;
     205             : 
     206          12 :         assert_return(m, -EINVAL);
     207             : 
     208          12 :         if (!m->event) {
     209           0 :                 r = sd_device_monitor_attach_event(m, NULL);
     210           0 :                 if (r < 0)
     211           0 :                         return r;
     212             :         }
     213             : 
     214          12 :         r = device_monitor_enable_receiving(m);
     215          12 :         if (r < 0)
     216           0 :                 return r;
     217             : 
     218          12 :         m->callback = callback;
     219          12 :         m->userdata = userdata;
     220             : 
     221          12 :         r = sd_event_add_io(m->event, &m->event_source, m->sock, EPOLLIN, device_monitor_event_handler, m);
     222          12 :         if (r < 0)
     223           0 :                 return r;
     224             : 
     225          12 :         (void) sd_event_source_set_description(m->event_source, "sd-device-monitor");
     226             : 
     227          12 :         return 0;
     228             : }
     229             : 
     230          12 : _public_ int sd_device_monitor_detach_event(sd_device_monitor *m) {
     231          12 :         assert_return(m, -EINVAL);
     232             : 
     233          12 :         (void) sd_device_monitor_stop(m);
     234          12 :         m->event = sd_event_unref(m->event);
     235             : 
     236          12 :         return 0;
     237             : }
     238             : 
     239          12 : _public_ int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event) {
     240             :         int r;
     241             : 
     242          12 :         assert_return(m, -EINVAL);
     243          12 :         assert_return(!m->event, -EBUSY);
     244             : 
     245          12 :         if (event)
     246          12 :                 m->event = sd_event_ref(event);
     247             :         else {
     248           0 :                 r = sd_event_default(&m->event);
     249           0 :                 if (r < 0)
     250           0 :                         return r;
     251             :         }
     252             : 
     253          12 :         return 0;
     254             : }
     255             : 
     256           0 : _public_ sd_event *sd_device_monitor_get_event(sd_device_monitor *m) {
     257           0 :         assert_return(m, NULL);
     258             : 
     259           0 :         return m->event;
     260             : }
     261             : 
     262           0 : _public_ sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *m) {
     263           0 :         assert_return(m, NULL);
     264             : 
     265           0 :         return m->event_source;
     266             : }
     267             : 
     268          12 : int device_monitor_enable_receiving(sd_device_monitor *m) {
     269             :         int r;
     270             : 
     271          12 :         assert_return(m, -EINVAL);
     272             : 
     273          12 :         r = sd_device_monitor_filter_update(m);
     274          12 :         if (r < 0)
     275           0 :                 return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m");
     276             : 
     277          12 :         if (!m->bound) {
     278             :                 /* enable receiving of sender credentials */
     279          12 :                 r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
     280          12 :                 if (r < 0)
     281           0 :                         return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m");
     282             : 
     283          12 :                 if (bind(m->sock, &m->snl.sa, sizeof(struct sockaddr_nl)) < 0)
     284           0 :                         return log_debug_errno(errno, "sd-device-monitor: Failed to bind monitoring socket: %m");
     285             : 
     286          12 :                 m->bound = true;
     287             : 
     288          12 :                 r = monitor_set_nl_address(m);
     289          12 :                 if (r < 0)
     290           0 :                         return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m");
     291             :         }
     292             : 
     293          12 :         return 0;
     294             : }
     295             : 
     296          12 : static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
     297          12 :         assert(m);
     298             : 
     299          12 :         (void) sd_device_monitor_detach_event(m);
     300             : 
     301          12 :         hashmap_free_free_free(m->subsystem_filter);
     302          12 :         set_free_free(m->tag_filter);
     303             : 
     304          12 :         return mfree(m);
     305             : }
     306             : 
     307          15 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_monitor, sd_device_monitor, device_monitor_free);
     308             : 
     309           0 : static int passes_filter(sd_device_monitor *m, sd_device *device) {
     310           0 :         const char *tag, *subsystem, *devtype, *s, *d = NULL;
     311             :         Iterator i;
     312             :         int r;
     313             : 
     314           0 :         assert_return(m, -EINVAL);
     315           0 :         assert_return(device, -EINVAL);
     316             : 
     317           0 :         if (hashmap_isempty(m->subsystem_filter))
     318           0 :                 goto tag;
     319             : 
     320           0 :         r = sd_device_get_subsystem(device, &s);
     321           0 :         if (r < 0)
     322           0 :                 return r;
     323             : 
     324           0 :         r = sd_device_get_devtype(device, &d);
     325           0 :         if (r < 0 && r != -ENOENT)
     326           0 :                 return r;
     327             : 
     328           0 :         HASHMAP_FOREACH_KEY(devtype, subsystem, m->subsystem_filter, i) {
     329           0 :                 if (!streq(s, subsystem))
     330           0 :                         continue;
     331             : 
     332           0 :                 if (!devtype)
     333           0 :                         goto tag;
     334             : 
     335           0 :                 if (!d)
     336           0 :                         continue;
     337             : 
     338           0 :                 if (streq(d, devtype))
     339           0 :                         goto tag;
     340             :         }
     341             : 
     342           0 :         return 0;
     343             : 
     344           0 : tag:
     345           0 :         if (set_isempty(m->tag_filter))
     346           0 :                 return 1;
     347             : 
     348           0 :         SET_FOREACH(tag, m->tag_filter, i)
     349           0 :                 if (sd_device_has_tag(device, tag) > 0)
     350           0 :                         return 1;
     351             : 
     352           0 :         return 0;
     353             : }
     354             : 
     355           0 : int device_monitor_receive_device(sd_device_monitor *m, sd_device **ret) {
     356           0 :         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
     357             :         union {
     358             :                 monitor_netlink_header nlh;
     359             :                 char raw[8192];
     360             :         } buf;
     361           0 :         struct iovec iov = {
     362             :                 .iov_base = &buf,
     363             :                 .iov_len = sizeof(buf)
     364             :         };
     365             :         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
     366             :         union sockaddr_union snl;
     367           0 :         struct msghdr smsg = {
     368             :                 .msg_iov = &iov,
     369             :                 .msg_iovlen = 1,
     370             :                 .msg_control = cred_msg,
     371             :                 .msg_controllen = sizeof(cred_msg),
     372             :                 .msg_name = &snl,
     373             :                 .msg_namelen = sizeof(snl),
     374             :         };
     375             :         struct cmsghdr *cmsg;
     376             :         struct ucred *cred;
     377             :         ssize_t buflen, bufpos;
     378           0 :         bool is_initialized = false;
     379             :         int r;
     380             : 
     381           0 :         assert(ret);
     382             : 
     383           0 :         buflen = recvmsg(m->sock, &smsg, 0);
     384           0 :         if (buflen < 0) {
     385           0 :                 if (errno != EINTR)
     386           0 :                         log_debug_errno(errno, "sd-device-monitor: Failed to receive message: %m");
     387           0 :                 return -errno;
     388             :         }
     389             : 
     390           0 :         if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC))
     391           0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     392             :                                        "sd-device-monitor: Invalid message length.");
     393             : 
     394           0 :         if (snl.nl.nl_groups == MONITOR_GROUP_NONE) {
     395             :                 /* unicast message, check if we trust the sender */
     396           0 :                 if (m->snl_trusted_sender.nl.nl_pid == 0 ||
     397           0 :                     snl.nl.nl_pid != m->snl_trusted_sender.nl.nl_pid)
     398           0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     399             :                                                "sd-device-monitor: Unicast netlink message ignored.");
     400             : 
     401           0 :         } else if (snl.nl.nl_groups == MONITOR_GROUP_KERNEL) {
     402           0 :                 if (snl.nl.nl_pid > 0)
     403           0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     404             :                                                "sd-device-monitor: Multicast kernel netlink message from PID %"PRIu32" ignored.", snl.nl.nl_pid);
     405             :         }
     406             : 
     407           0 :         cmsg = CMSG_FIRSTHDR(&smsg);
     408           0 :         if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
     409           0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     410             :                                        "sd-device-monitor: No sender credentials received, message ignored.");
     411             : 
     412           0 :         cred = (struct ucred*) CMSG_DATA(cmsg);
     413           0 :         if (cred->uid != 0)
     414           0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     415             :                                        "sd-device-monitor: Sender uid="UID_FMT", message ignored.", cred->uid);
     416             : 
     417           0 :         if (streq(buf.raw, "libudev")) {
     418             :                 /* udev message needs proper version magic */
     419           0 :                 if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC))
     420           0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     421             :                                                "sd-device-monitor: Invalid message signature (%x != %x)",
     422             :                                                buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
     423             : 
     424           0 :                 if (buf.nlh.properties_off+32 > (size_t) buflen)
     425           0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     426             :                                                "sd-device-monitor: Invalid message length (%u > %zd)",
     427             :                                                buf.nlh.properties_off+32, buflen);
     428             : 
     429           0 :                 bufpos = buf.nlh.properties_off;
     430             : 
     431             :                 /* devices received from udev are always initialized */
     432           0 :                 is_initialized = true;
     433             : 
     434             :         } else {
     435             :                 /* kernel message with header */
     436           0 :                 bufpos = strlen(buf.raw) + 1;
     437           0 :                 if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen)
     438           0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     439             :                                                "sd-device-monitor: Invalid message length");
     440             : 
     441             :                 /* check message header */
     442           0 :                 if (!strstr(buf.raw, "@/"))
     443           0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
     444             :                                                "sd-device-monitor: Invalid message header");
     445             :         }
     446             : 
     447           0 :         r = device_new_from_nulstr(&device, (uint8_t*) &buf.raw[bufpos], buflen - bufpos);
     448           0 :         if (r < 0)
     449           0 :                 return log_debug_errno(r, "sd-device-monitor: Failed to create device from received message: %m");
     450             : 
     451           0 :         if (is_initialized)
     452           0 :                 device_set_is_initialized(device);
     453             : 
     454             :         /* Skip device, if it does not pass the current filter */
     455           0 :         r = passes_filter(m, device);
     456           0 :         if (r < 0)
     457           0 :                 return log_device_debug_errno(device, r, "sd-device-monitor: Failed to check received device passing filter: %m");
     458           0 :         if (r == 0)
     459           0 :                 log_device_debug(device, "sd-device-monitor: Received device does not pass filter, ignoring");
     460             :         else
     461           0 :                 *ret = TAKE_PTR(device);
     462             : 
     463           0 :         return r;
     464             : }
     465             : 
     466          12 : static uint32_t string_hash32(const char *str) {
     467          12 :         return MurmurHash2(str, strlen(str), 0);
     468             : }
     469             : 
     470             : /* Get a bunch of bit numbers out of the hash, and set the bits in our bit field */
     471          11 : static uint64_t string_bloom64(const char *str) {
     472          11 :         uint64_t bits = 0;
     473          11 :         uint32_t hash = string_hash32(str);
     474             : 
     475          11 :         bits |= 1LLU << (hash & 63);
     476          11 :         bits |= 1LLU << ((hash >> 6) & 63);
     477          11 :         bits |= 1LLU << ((hash >> 12) & 63);
     478          11 :         bits |= 1LLU << ((hash >> 18) & 63);
     479          11 :         return bits;
     480             : }
     481             : 
     482           0 : int device_monitor_send_device(
     483             :                 sd_device_monitor *m,
     484             :                 sd_device_monitor *destination,
     485             :                 sd_device *device) {
     486             : 
     487           0 :         monitor_netlink_header nlh = {
     488             :                 .prefix = "libudev",
     489           0 :                 .magic = htobe32(UDEV_MONITOR_MAGIC),
     490             :                 .header_size = sizeof nlh,
     491             :         };
     492           0 :         struct iovec iov[2] = {
     493             :                 { .iov_base = &nlh, .iov_len = sizeof nlh },
     494             :         };
     495           0 :         struct msghdr smsg = {
     496             :                 .msg_iov = iov,
     497             :                 .msg_iovlen = 2,
     498             :         };
     499             :         /* default destination for sending */
     500           0 :         union sockaddr_union default_destination = {
     501             :                 .nl.nl_family = AF_NETLINK,
     502             :                 .nl.nl_groups = MONITOR_GROUP_UDEV,
     503             :         };
     504             :         uint64_t tag_bloom_bits;
     505             :         const char *buf, *val;
     506             :         ssize_t count;
     507             :         size_t blen;
     508             :         int r;
     509             : 
     510           0 :         assert(m);
     511           0 :         assert(device);
     512             : 
     513           0 :         r = device_get_properties_nulstr(device, (const uint8_t **) &buf, &blen);
     514           0 :         if (r < 0)
     515           0 :                 return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device properties: %m");
     516           0 :         if (blen < 32) {
     517           0 :                 log_device_debug(device, "sd-device-monitor: Length of device property nulstr is too small to contain valid device information");
     518           0 :                 return -EINVAL;
     519             :         }
     520             : 
     521             :         /* fill in versioned header */
     522           0 :         r = sd_device_get_subsystem(device, &val);
     523           0 :         if (r < 0)
     524           0 :                 return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device subsystem: %m");
     525           0 :         nlh.filter_subsystem_hash = htobe32(string_hash32(val));
     526             : 
     527           0 :         if (sd_device_get_devtype(device, &val) >= 0)
     528           0 :                 nlh.filter_devtype_hash = htobe32(string_hash32(val));
     529             : 
     530             :         /* add tag bloom filter */
     531           0 :         tag_bloom_bits = 0;
     532           0 :         FOREACH_DEVICE_TAG(device, val)
     533           0 :                 tag_bloom_bits |= string_bloom64(val);
     534             : 
     535           0 :         if (tag_bloom_bits > 0) {
     536           0 :                 nlh.filter_tag_bloom_hi = htobe32(tag_bloom_bits >> 32);
     537           0 :                 nlh.filter_tag_bloom_lo = htobe32(tag_bloom_bits & 0xffffffff);
     538             :         }
     539             : 
     540             :         /* add properties list */
     541           0 :         nlh.properties_off = iov[0].iov_len;
     542           0 :         nlh.properties_len = blen;
     543           0 :         iov[1] = IOVEC_MAKE((char*) buf, blen);
     544             : 
     545             :         /*
     546             :          * Use custom address for target, or the default one.
     547             :          *
     548             :          * If we send to a multicast group, we will get
     549             :          * ECONNREFUSED, which is expected.
     550             :          */
     551           0 :         smsg.msg_name = destination ? &destination->snl : &default_destination;
     552           0 :         smsg.msg_namelen = sizeof(struct sockaddr_nl);
     553           0 :         count = sendmsg(m->sock, &smsg, 0);
     554           0 :         if (count < 0) {
     555           0 :                 if (!destination && errno == ECONNREFUSED) {
     556           0 :                         log_device_debug(device, "sd-device-monitor: Passed to netlink monitor");
     557           0 :                         return 0;
     558             :                 } else
     559           0 :                         return log_device_debug_errno(device, errno, "sd-device-monitor: Failed to send device to netlink monitor: %m");
     560             :         }
     561             : 
     562           0 :         log_device_debug(device, "sd-device-monitor: Passed %zi byte to netlink monitor", count);
     563           0 :         return count;
     564             : }
     565             : 
     566          94 : static void bpf_stmt(struct sock_filter *ins, unsigned *i,
     567             :                      unsigned short code, unsigned data) {
     568          94 :         ins[(*i)++] = (struct sock_filter) {
     569             :                 .code = code,
     570             :                 .k = data,
     571             :         };
     572          94 : }
     573             : 
     574          35 : static void bpf_jmp(struct sock_filter *ins, unsigned *i,
     575             :                     unsigned short code, unsigned data,
     576             :                     unsigned short jt, unsigned short jf) {
     577          35 :         ins[(*i)++] = (struct sock_filter) {
     578             :                 .code = code,
     579             :                 .jt = jt,
     580             :                 .jf = jf,
     581             :                 .k = data,
     582             :         };
     583          35 : }
     584             : 
     585          12 : _public_ int sd_device_monitor_filter_update(sd_device_monitor *m) {
     586          12 :         struct sock_filter ins[512] = {};
     587             :         struct sock_fprog filter;
     588             :         const char *subsystem, *devtype, *tag;
     589          12 :         unsigned i = 0;
     590             :         Iterator it;
     591             : 
     592          12 :         assert_return(m, -EINVAL);
     593             : 
     594          12 :         if (m->filter_uptodate)
     595           0 :                 return 0;
     596             : 
     597          23 :         if (hashmap_isempty(m->subsystem_filter) &&
     598          11 :             set_isempty(m->tag_filter)) {
     599           0 :                 m->filter_uptodate = true;
     600           0 :                 return 0;
     601             :         }
     602             : 
     603             :         /* load magic in A */
     604          12 :         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, magic));
     605             :         /* jump if magic matches */
     606          12 :         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0);
     607             :         /* wrong magic, pass packet */
     608          12 :         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     609             : 
     610          12 :         if (!set_isempty(m->tag_filter)) {
     611          11 :                 int tag_matches = set_size(m->tag_filter);
     612             : 
     613             :                 /* add all tags matches */
     614          22 :                 SET_FOREACH(tag, m->tag_filter, it) {
     615          11 :                         uint64_t tag_bloom_bits = string_bloom64(tag);
     616          11 :                         uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
     617          11 :                         uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
     618             : 
     619             :                         /* load device bloom bits in A */
     620          11 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_tag_bloom_hi));
     621             :                         /* clear bits (tag bits & bloom bits) */
     622          11 :                         bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi);
     623             :                         /* jump to next tag if it does not match */
     624          11 :                         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3);
     625             : 
     626             :                         /* load device bloom bits in A */
     627          11 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_tag_bloom_lo));
     628             :                         /* clear bits (tag bits & bloom bits) */
     629          11 :                         bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo);
     630             :                         /* jump behind end of tag match block if tag matches */
     631          11 :                         tag_matches--;
     632          11 :                         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0);
     633             :                 }
     634             : 
     635             :                 /* nothing matched, drop packet */
     636          11 :                 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
     637             :         }
     638             : 
     639             :         /* add all subsystem matches */
     640          12 :         if (!hashmap_isempty(m->subsystem_filter)) {
     641           2 :                 HASHMAP_FOREACH_KEY(devtype, subsystem, m->subsystem_filter, it) {
     642           1 :                         uint32_t hash = string_hash32(subsystem);
     643             : 
     644             :                         /* load device subsystem value in A */
     645           1 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_subsystem_hash));
     646           1 :                         if (!devtype) {
     647             :                                 /* jump if subsystem does not match */
     648           1 :                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
     649             :                         } else {
     650             :                                 /* jump if subsystem does not match */
     651           0 :                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
     652             :                                 /* load device devtype value in A */
     653           0 :                                 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_devtype_hash));
     654             :                                 /* jump if value does not match */
     655           0 :                                 hash = string_hash32(devtype);
     656           0 :                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
     657             :                         }
     658             : 
     659             :                         /* matched, pass packet */
     660           1 :                         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     661             : 
     662           1 :                         if (i+1 >= ELEMENTSOF(ins))
     663           0 :                                 return -E2BIG;
     664             :                 }
     665             : 
     666             :                 /* nothing matched, drop packet */
     667           1 :                 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
     668             :         }
     669             : 
     670             :         /* matched, pass packet */
     671          12 :         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     672             : 
     673             :         /* install filter */
     674          12 :         filter = (struct sock_fprog) {
     675             :                 .len = i,
     676             :                 .filter = ins,
     677             :         };
     678          12 :         if (setsockopt(m->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
     679           0 :                 return -errno;
     680             : 
     681          12 :         m->filter_uptodate = true;
     682          12 :         return 0;
     683             : }
     684             : 
     685           1 : _public_ int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype) {
     686           1 :         _cleanup_free_ char *s = NULL, *d = NULL;
     687             :         int r;
     688             : 
     689           1 :         assert_return(m, -EINVAL);
     690           1 :         assert_return(subsystem, -EINVAL);
     691             : 
     692           1 :         s = strdup(subsystem);
     693           1 :         if (!s)
     694           0 :                 return -ENOMEM;
     695             : 
     696           1 :         if (devtype) {
     697           0 :                 d = strdup(devtype);
     698           0 :                 if (!d)
     699           0 :                         return -ENOMEM;
     700             :         }
     701             : 
     702           1 :         r = hashmap_ensure_allocated(&m->subsystem_filter, NULL);
     703           1 :         if (r < 0)
     704           0 :                 return r;
     705             : 
     706           1 :         r = hashmap_put(m->subsystem_filter, s, d);
     707           1 :         if (r < 0)
     708           0 :                 return r;
     709             : 
     710           1 :         s = d = NULL;
     711           1 :         m->filter_uptodate = false;
     712             : 
     713           1 :         return 0;
     714             : }
     715             : 
     716          11 : _public_ int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag) {
     717          11 :         _cleanup_free_ char *t = NULL;
     718             :         int r;
     719             : 
     720          11 :         assert_return(m, -EINVAL);
     721          11 :         assert_return(tag, -EINVAL);
     722             : 
     723          11 :         t = strdup(tag);
     724          11 :         if (!t)
     725           0 :                 return -ENOMEM;
     726             : 
     727          11 :         r = set_ensure_allocated(&m->tag_filter, &string_hash_ops);
     728          11 :         if (r < 0)
     729           0 :                 return r;
     730             : 
     731          11 :         r = set_put(m->tag_filter, t);
     732          11 :         if (r == -EEXIST)
     733           0 :                 return 0;
     734          11 :         if (r < 0)
     735           0 :                 return r;
     736             : 
     737          11 :         TAKE_PTR(t);
     738          11 :         m->filter_uptodate = false;
     739             : 
     740          11 :         return 0;
     741             : }
     742             : 
     743           0 : _public_ int sd_device_monitor_filter_remove(sd_device_monitor *m) {
     744             :         static const struct sock_fprog filter = { 0, NULL };
     745             : 
     746           0 :         assert_return(m, -EINVAL);
     747             : 
     748           0 :         m->subsystem_filter = hashmap_free_free_free(m->subsystem_filter);
     749           0 :         m->tag_filter = set_free_free(m->tag_filter);
     750             : 
     751           0 :         if (setsockopt(m->sock, SOL_SOCKET, SO_DETACH_FILTER, &filter, sizeof(filter)) < 0)
     752           0 :                 return -errno;
     753             : 
     754           0 :         m->filter_uptodate = true;
     755           0 :         return 0;
     756             : }

Generated by: LCOV version 1.14