LCOV - code coverage report
Current view: top level - libsystemd/sd-device - device-monitor.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 166 356 46.6 %
Date: 2019-08-23 13:36:53 Functions: 19 29 65.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 80 378 21.2 %

           Branch data     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                 :         48 : static int monitor_set_nl_address(sd_device_monitor *m) {
      67                 :            :         union sockaddr_union snl;
      68                 :            :         socklen_t addrlen;
      69                 :            : 
      70         [ -  + ]:         48 :         assert(m);
      71                 :            : 
      72                 :            :         /* Get the address the kernel has assigned us.
      73                 :            :          * It is usually, but not necessarily the pid. */
      74                 :         48 :         addrlen = sizeof(struct sockaddr_nl);
      75         [ -  + ]:         48 :         if (getsockname(m->sock, &snl.sa, &addrlen) < 0)
      76                 :          0 :                 return -errno;
      77                 :            : 
      78                 :         48 :         m->snl.nl.nl_pid = snl.nl.nl_pid;
      79                 :         48 :         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                 :         44 : _public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size) {
      91                 :         44 :         int r, n = (int) size;
      92                 :            : 
      93   [ -  +  -  + ]:         44 :         assert_return(m, -EINVAL);
      94   [ -  +  -  + ]:         44 :         assert_return((size_t) n == size, -EINVAL);
      95                 :            : 
      96         [ +  - ]:         44 :         if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n) < 0) {
      97                 :         44 :                 r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n);
      98         [ -  + ]:         44 :                 if (r < 0)
      99                 :          0 :                         return r;
     100                 :            :         }
     101                 :            : 
     102                 :         44 :         return 0;
     103                 :            : }
     104                 :            : 
     105                 :         48 : int device_monitor_disconnect(sd_device_monitor *m) {
     106         [ -  + ]:         48 :         assert(m);
     107                 :            : 
     108                 :         48 :         m->sock = safe_close(m->sock);
     109                 :         48 :         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                 :         48 : int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, int fd) {
     119                 :         48 :         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
     120                 :         48 :         _cleanup_close_ int sock = -1;
     121                 :            :         int r;
     122                 :            : 
     123   [ -  +  -  + ]:         48 :         assert_return(ret, -EINVAL);
     124   [ +  -  -  +  :         48 :         assert_return(group >= 0 && group < _MONITOR_NETLINK_GROUP_MAX, -EINVAL);
                   -  + ]
     125                 :            : 
     126   [ +  -  -  + ]:         96 :         if (group == MONITOR_GROUP_UDEV &&
     127         [ #  # ]:         48 :             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         [ +  - ]:         48 :         if (fd < 0) {
     148                 :         48 :                 sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
     149         [ -  + ]:         48 :                 if (sock < 0)
     150         [ #  # ]:          0 :                         return log_debug_errno(errno, "sd-device-monitor: Failed to create socket: %m");
     151                 :            :         }
     152                 :            : 
     153                 :         48 :         m = new(sd_device_monitor, 1);
     154         [ -  + ]:         48 :         if (!m)
     155                 :          0 :                 return -ENOMEM;
     156                 :            : 
     157                 :        144 :         *m = (sd_device_monitor) {
     158                 :            :                 .n_ref = 1,
     159         [ +  - ]:         48 :                 .sock = fd >= 0 ? fd : TAKE_FD(sock),
     160                 :         48 :                 .bound = fd >= 0,
     161                 :            :                 .snl.nl.nl_family = AF_NETLINK,
     162                 :            :                 .snl.nl.nl_groups = group,
     163                 :            :         };
     164                 :            : 
     165         [ -  + ]:         48 :         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                 :         48 :         *ret = TAKE_PTR(m);
     172                 :         48 :         return 0;
     173                 :            : }
     174                 :            : 
     175                 :         48 : _public_ int sd_device_monitor_new(sd_device_monitor **ret) {
     176                 :         48 :         return device_monitor_new_full(ret, MONITOR_GROUP_UDEV, -1);
     177                 :            : }
     178                 :            : 
     179                 :         48 : _public_ int sd_device_monitor_stop(sd_device_monitor *m) {
     180   [ -  +  -  + ]:         48 :         assert_return(m, -EINVAL);
     181                 :            : 
     182                 :         48 :         m->event_source = sd_event_source_unref(m->event_source);
     183                 :         48 :         (void) device_monitor_disconnect(m);
     184                 :            : 
     185                 :         48 :         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                 :         48 : _public_ int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata) {
     204                 :            :         int r;
     205                 :            : 
     206   [ -  +  -  + ]:         48 :         assert_return(m, -EINVAL);
     207                 :            : 
     208         [ -  + ]:         48 :         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                 :         48 :         r = device_monitor_enable_receiving(m);
     215         [ -  + ]:         48 :         if (r < 0)
     216                 :          0 :                 return r;
     217                 :            : 
     218                 :         48 :         m->callback = callback;
     219                 :         48 :         m->userdata = userdata;
     220                 :            : 
     221                 :         48 :         r = sd_event_add_io(m->event, &m->event_source, m->sock, EPOLLIN, device_monitor_event_handler, m);
     222         [ -  + ]:         48 :         if (r < 0)
     223                 :          0 :                 return r;
     224                 :            : 
     225                 :         48 :         (void) sd_event_source_set_description(m->event_source, "sd-device-monitor");
     226                 :            : 
     227                 :         48 :         return 0;
     228                 :            : }
     229                 :            : 
     230                 :         48 : _public_ int sd_device_monitor_detach_event(sd_device_monitor *m) {
     231   [ -  +  -  + ]:         48 :         assert_return(m, -EINVAL);
     232                 :            : 
     233                 :         48 :         (void) sd_device_monitor_stop(m);
     234                 :         48 :         m->event = sd_event_unref(m->event);
     235                 :            : 
     236                 :         48 :         return 0;
     237                 :            : }
     238                 :            : 
     239                 :         48 : _public_ int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event) {
     240                 :            :         int r;
     241                 :            : 
     242   [ -  +  -  + ]:         48 :         assert_return(m, -EINVAL);
     243   [ -  +  -  + ]:         48 :         assert_return(!m->event, -EBUSY);
     244                 :            : 
     245         [ +  - ]:         48 :         if (event)
     246                 :         48 :                 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                 :         48 :         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                 :         48 : int device_monitor_enable_receiving(sd_device_monitor *m) {
     269                 :            :         int r;
     270                 :            : 
     271   [ -  +  -  + ]:         48 :         assert_return(m, -EINVAL);
     272                 :            : 
     273                 :         48 :         r = sd_device_monitor_filter_update(m);
     274         [ -  + ]:         48 :         if (r < 0)
     275         [ #  # ]:          0 :                 return log_debug_errno(r, "sd-device-monitor: Failed to update filter: %m");
     276                 :            : 
     277         [ +  - ]:         48 :         if (!m->bound) {
     278                 :            :                 /* enable receiving of sender credentials */
     279                 :         48 :                 r = setsockopt_int(m->sock, SOL_SOCKET, SO_PASSCRED, true);
     280         [ -  + ]:         48 :                 if (r < 0)
     281         [ #  # ]:          0 :                         return log_debug_errno(r, "sd-device-monitor: Failed to set socket option SO_PASSCRED: %m");
     282                 :            : 
     283         [ -  + ]:         48 :                 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                 :         48 :                 m->bound = true;
     287                 :            : 
     288                 :         48 :                 r = monitor_set_nl_address(m);
     289         [ -  + ]:         48 :                 if (r < 0)
     290         [ #  # ]:          0 :                         return log_debug_errno(r, "sd-device-monitor: Failed to set address: %m");
     291                 :            :         }
     292                 :            : 
     293                 :         48 :         return 0;
     294                 :            : }
     295                 :            : 
     296                 :         48 : static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
     297         [ -  + ]:         48 :         assert(m);
     298                 :            : 
     299                 :         48 :         (void) sd_device_monitor_detach_event(m);
     300                 :            : 
     301                 :         48 :         hashmap_free_free_free(m->subsystem_filter);
     302                 :         48 :         set_free_free(m->tag_filter);
     303                 :            : 
     304                 :         48 :         return mfree(m);
     305                 :            : }
     306                 :            : 
     307   [ +  +  -  +  :         60 : 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                 :         48 : static uint32_t string_hash32(const char *str) {
     467                 :         48 :         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                 :         44 : static uint64_t string_bloom64(const char *str) {
     472                 :         44 :         uint64_t bits = 0;
     473                 :         44 :         uint32_t hash = string_hash32(str);
     474                 :            : 
     475                 :         44 :         bits |= 1LLU << (hash & 63);
     476                 :         44 :         bits |= 1LLU << ((hash >> 6) & 63);
     477                 :         44 :         bits |= 1LLU << ((hash >> 12) & 63);
     478                 :         44 :         bits |= 1LLU << ((hash >> 18) & 63);
     479                 :         44 :         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                 :        376 : static void bpf_stmt(struct sock_filter *ins, unsigned *i,
     567                 :            :                      unsigned short code, unsigned data) {
     568                 :        376 :         ins[(*i)++] = (struct sock_filter) {
     569                 :            :                 .code = code,
     570                 :            :                 .k = data,
     571                 :            :         };
     572                 :        376 : }
     573                 :            : 
     574                 :        140 : static void bpf_jmp(struct sock_filter *ins, unsigned *i,
     575                 :            :                     unsigned short code, unsigned data,
     576                 :            :                     unsigned short jt, unsigned short jf) {
     577                 :        140 :         ins[(*i)++] = (struct sock_filter) {
     578                 :            :                 .code = code,
     579                 :            :                 .jt = jt,
     580                 :            :                 .jf = jf,
     581                 :            :                 .k = data,
     582                 :            :         };
     583                 :        140 : }
     584                 :            : 
     585                 :         48 : _public_ int sd_device_monitor_filter_update(sd_device_monitor *m) {
     586                 :         48 :         struct sock_filter ins[512] = {};
     587                 :            :         struct sock_fprog filter;
     588                 :            :         const char *subsystem, *devtype, *tag;
     589                 :         48 :         unsigned i = 0;
     590                 :            :         Iterator it;
     591                 :            : 
     592   [ -  +  -  + ]:         48 :         assert_return(m, -EINVAL);
     593                 :            : 
     594         [ -  + ]:         48 :         if (m->filter_uptodate)
     595                 :          0 :                 return 0;
     596                 :            : 
     597   [ +  +  -  + ]:         92 :         if (hashmap_isempty(m->subsystem_filter) &&
     598                 :         44 :             set_isempty(m->tag_filter)) {
     599                 :          0 :                 m->filter_uptodate = true;
     600                 :          0 :                 return 0;
     601                 :            :         }
     602                 :            : 
     603                 :            :         /* load magic in A */
     604                 :         48 :         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, magic));
     605                 :            :         /* jump if magic matches */
     606                 :         48 :         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0);
     607                 :            :         /* wrong magic, pass packet */
     608                 :         48 :         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     609                 :            : 
     610         [ +  + ]:         48 :         if (!set_isempty(m->tag_filter)) {
     611                 :         44 :                 int tag_matches = set_size(m->tag_filter);
     612                 :            : 
     613                 :            :                 /* add all tags matches */
     614         [ +  + ]:         88 :                 SET_FOREACH(tag, m->tag_filter, it) {
     615                 :         44 :                         uint64_t tag_bloom_bits = string_bloom64(tag);
     616                 :         44 :                         uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
     617                 :         44 :                         uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
     618                 :            : 
     619                 :            :                         /* load device bloom bits in A */
     620                 :         44 :                         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                 :         44 :                         bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi);
     623                 :            :                         /* jump to next tag if it does not match */
     624                 :         44 :                         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3);
     625                 :            : 
     626                 :            :                         /* load device bloom bits in A */
     627                 :         44 :                         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                 :         44 :                         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                 :         44 :                         tag_matches--;
     632                 :         44 :                         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                 :         44 :                 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
     637                 :            :         }
     638                 :            : 
     639                 :            :         /* add all subsystem matches */
     640         [ +  + ]:         48 :         if (!hashmap_isempty(m->subsystem_filter)) {
     641         [ +  + ]:          8 :                 HASHMAP_FOREACH_KEY(devtype, subsystem, m->subsystem_filter, it) {
     642                 :          4 :                         uint32_t hash = string_hash32(subsystem);
     643                 :            : 
     644                 :            :                         /* load device subsystem value in A */
     645                 :          4 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(monitor_netlink_header, filter_subsystem_hash));
     646         [ +  - ]:          4 :                         if (!devtype) {
     647                 :            :                                 /* jump if subsystem does not match */
     648                 :          4 :                                 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                 :          4 :                         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     661                 :            : 
     662         [ -  + ]:          4 :                         if (i+1 >= ELEMENTSOF(ins))
     663                 :          0 :                                 return -E2BIG;
     664                 :            :                 }
     665                 :            : 
     666                 :            :                 /* nothing matched, drop packet */
     667                 :          4 :                 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
     668                 :            :         }
     669                 :            : 
     670                 :            :         /* matched, pass packet */
     671                 :         48 :         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     672                 :            : 
     673                 :            :         /* install filter */
     674                 :         48 :         filter = (struct sock_fprog) {
     675                 :            :                 .len = i,
     676                 :            :                 .filter = ins,
     677                 :            :         };
     678         [ -  + ]:         48 :         if (setsockopt(m->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
     679                 :          0 :                 return -errno;
     680                 :            : 
     681                 :         48 :         m->filter_uptodate = true;
     682                 :         48 :         return 0;
     683                 :            : }
     684                 :            : 
     685                 :          4 : _public_ int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype) {
     686                 :          4 :         _cleanup_free_ char *s = NULL, *d = NULL;
     687                 :            :         int r;
     688                 :            : 
     689   [ -  +  -  + ]:          4 :         assert_return(m, -EINVAL);
     690   [ -  +  -  + ]:          4 :         assert_return(subsystem, -EINVAL);
     691                 :            : 
     692                 :          4 :         s = strdup(subsystem);
     693         [ -  + ]:          4 :         if (!s)
     694                 :          0 :                 return -ENOMEM;
     695                 :            : 
     696         [ -  + ]:          4 :         if (devtype) {
     697                 :          0 :                 d = strdup(devtype);
     698         [ #  # ]:          0 :                 if (!d)
     699                 :          0 :                         return -ENOMEM;
     700                 :            :         }
     701                 :            : 
     702                 :          4 :         r = hashmap_ensure_allocated(&m->subsystem_filter, NULL);
     703         [ -  + ]:          4 :         if (r < 0)
     704                 :          0 :                 return r;
     705                 :            : 
     706                 :          4 :         r = hashmap_put(m->subsystem_filter, s, d);
     707         [ -  + ]:          4 :         if (r < 0)
     708                 :          0 :                 return r;
     709                 :            : 
     710                 :          4 :         s = d = NULL;
     711                 :          4 :         m->filter_uptodate = false;
     712                 :            : 
     713                 :          4 :         return 0;
     714                 :            : }
     715                 :            : 
     716                 :         44 : _public_ int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag) {
     717                 :         44 :         _cleanup_free_ char *t = NULL;
     718                 :            :         int r;
     719                 :            : 
     720   [ -  +  -  + ]:         44 :         assert_return(m, -EINVAL);
     721   [ -  +  -  + ]:         44 :         assert_return(tag, -EINVAL);
     722                 :            : 
     723                 :         44 :         t = strdup(tag);
     724         [ -  + ]:         44 :         if (!t)
     725                 :          0 :                 return -ENOMEM;
     726                 :            : 
     727                 :         44 :         r = set_ensure_allocated(&m->tag_filter, &string_hash_ops);
     728         [ -  + ]:         44 :         if (r < 0)
     729                 :          0 :                 return r;
     730                 :            : 
     731                 :         44 :         r = set_put(m->tag_filter, t);
     732         [ -  + ]:         44 :         if (r == -EEXIST)
     733                 :          0 :                 return 0;
     734         [ -  + ]:         44 :         if (r < 0)
     735                 :          0 :                 return r;
     736                 :            : 
     737                 :         44 :         TAKE_PTR(t);
     738                 :         44 :         m->filter_uptodate = false;
     739                 :            : 
     740                 :         44 :         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