LCOV - code coverage report
Current view: top level - libudev - libudev-monitor.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 126 331 38.1 %
Date: 2015-07-29 18:47:03 Functions: 13 22 59.1 %

          Line data    Source code
       1             : /***
       2             :   This file is part of systemd.
       3             : 
       4             :   Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
       5             : 
       6             :   systemd is free software; you can redistribute it and/or modify it
       7             :   under the terms of the GNU Lesser General Public License as published by
       8             :   the Free Software Foundation; either version 2.1 of the License, or
       9             :   (at your option) any later version.
      10             : 
      11             :   systemd is distributed in the hope that it will be useful, but
      12             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      14             :   Lesser General Public License for more details.
      15             : 
      16             :   You should have received a copy of the GNU Lesser General Public License
      17             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      18             : ***/
      19             : 
      20             : #include <stdio.h>
      21             : #include <stdlib.h>
      22             : #include <stddef.h>
      23             : #include <unistd.h>
      24             : #include <errno.h>
      25             : #include <string.h>
      26             : #include <poll.h>
      27             : #include <sys/socket.h>
      28             : #include <linux/netlink.h>
      29             : #include <linux/filter.h>
      30             : 
      31             : #include "libudev.h"
      32             : #include "libudev-private.h"
      33             : #include "socket-util.h"
      34             : #include "missing.h"
      35             : #include "formats-util.h"
      36             : 
      37             : /**
      38             :  * SECTION:libudev-monitor
      39             :  * @short_description: device event source
      40             :  *
      41             :  * Connects to a device event source.
      42             :  */
      43             : 
      44             : /**
      45             :  * udev_monitor:
      46             :  *
      47             :  * Opaque object handling an event source.
      48             :  */
      49             : struct udev_monitor {
      50             :         struct udev *udev;
      51             :         int refcount;
      52             :         int sock;
      53             :         union sockaddr_union snl;
      54             :         union sockaddr_union snl_trusted_sender;
      55             :         union sockaddr_union snl_destination;
      56             :         socklen_t addrlen;
      57             :         struct udev_list filter_subsystem_list;
      58             :         struct udev_list filter_tag_list;
      59             :         bool bound;
      60             : };
      61             : 
      62             : enum udev_monitor_netlink_group {
      63             :         UDEV_MONITOR_NONE,
      64             :         UDEV_MONITOR_KERNEL,
      65             :         UDEV_MONITOR_UDEV,
      66             : };
      67             : 
      68             : #define UDEV_MONITOR_MAGIC                0xfeedcafe
      69             : struct udev_monitor_netlink_header {
      70             :         /* "libudev" prefix to distinguish libudev and kernel messages */
      71             :         char prefix[8];
      72             :         /*
      73             :          * magic to protect against daemon <-> library message format mismatch
      74             :          * used in the kernel from socket filter rules; needs to be stored in network order
      75             :          */
      76             :         unsigned int magic;
      77             :         /* total length of header structure known to the sender */
      78             :         unsigned int header_size;
      79             :         /* properties string buffer */
      80             :         unsigned int properties_off;
      81             :         unsigned int properties_len;
      82             :         /*
      83             :          * hashes of primary device properties strings, to let libudev subscribers
      84             :          * use in-kernel socket filters; values need to be stored in network order
      85             :          */
      86             :         unsigned int filter_subsystem_hash;
      87             :         unsigned int filter_devtype_hash;
      88             :         unsigned int filter_tag_bloom_hi;
      89             :         unsigned int filter_tag_bloom_lo;
      90             : };
      91             : 
      92          11 : static struct udev_monitor *udev_monitor_new(struct udev *udev)
      93             : {
      94             :         struct udev_monitor *udev_monitor;
      95             : 
      96          11 :         udev_monitor = new0(struct udev_monitor, 1);
      97          11 :         if (udev_monitor == NULL)
      98           0 :                 return NULL;
      99          11 :         udev_monitor->refcount = 1;
     100          11 :         udev_monitor->udev = udev;
     101          11 :         udev_list_init(udev, &udev_monitor->filter_subsystem_list, false);
     102          11 :         udev_list_init(udev, &udev_monitor->filter_tag_list, true);
     103          11 :         return udev_monitor;
     104             : }
     105             : 
     106             : /* we consider udev running when /dev is on devtmpfs */
     107           0 : static bool udev_has_devtmpfs(struct udev *udev) {
     108             : 
     109           0 :         union file_handle_union h = FILE_HANDLE_INIT;
     110           0 :         _cleanup_fclose_ FILE *f = NULL;
     111             :         char line[LINE_MAX], *e;
     112             :         int mount_id;
     113             :         int r;
     114             : 
     115           0 :         r = name_to_handle_at(AT_FDCWD, "/dev", &h.handle, &mount_id, 0);
     116           0 :         if (r < 0) {
     117           0 :                 if (errno != EOPNOTSUPP)
     118           0 :                         log_debug_errno(errno, "name_to_handle_at on /dev: %m");
     119           0 :                 return false;
     120             :         }
     121             : 
     122           0 :         f = fopen("/proc/self/mountinfo", "re");
     123           0 :         if (!f)
     124           0 :                 return false;
     125             : 
     126           0 :         FOREACH_LINE(line, f, return false) {
     127             :                 int mid;
     128             : 
     129           0 :                 if (sscanf(line, "%i", &mid) != 1)
     130           0 :                         continue;
     131             : 
     132           0 :                 if (mid != mount_id)
     133           0 :                         continue;
     134             : 
     135           0 :                 e = strstr(line, " - ");
     136           0 :                 if (!e)
     137           0 :                         continue;
     138             : 
     139             :                 /* accept any name that starts with the currently expected type */
     140           0 :                 if (startswith(e + 3, "devtmpfs"))
     141           0 :                         return true;
     142           0 :         }
     143             : 
     144           0 :         return false;
     145             : }
     146             : 
     147          11 : static void monitor_set_nl_address(struct udev_monitor *udev_monitor) {
     148             :         union sockaddr_union snl;
     149             :         socklen_t addrlen;
     150             :         int r;
     151             : 
     152          11 :         assert(udev_monitor);
     153             : 
     154             :         /* get the address the kernel has assigned us
     155             :          * it is usually, but not necessarily the pid
     156             :          */
     157          11 :         addrlen = sizeof(struct sockaddr_nl);
     158          11 :         r = getsockname(udev_monitor->sock, &snl.sa, &addrlen);
     159          11 :         if (r >= 0)
     160          11 :                 udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
     161          11 : }
     162             : 
     163          11 : struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
     164             : {
     165             :         struct udev_monitor *udev_monitor;
     166             :         unsigned int group;
     167             : 
     168          11 :         if (udev == NULL)
     169           0 :                 return NULL;
     170             : 
     171          11 :         if (name == NULL)
     172           0 :                 group = UDEV_MONITOR_NONE;
     173          11 :         else if (streq(name, "udev")) {
     174             :                 /*
     175             :                  * We do not support subscribing to uevents if no instance of
     176             :                  * udev is running. Uevents would otherwise broadcast the
     177             :                  * processing data of the host into containers, which is not
     178             :                  * desired.
     179             :                  *
     180             :                  * Containers will currently not get any udev uevents, until
     181             :                  * a supporting infrastructure is available.
     182             :                  *
     183             :                  * We do not set a netlink multicast group here, so the socket
     184             :                  * will not receive any messages.
     185             :                  */
     186          11 :                 if (access("/run/udev/control", F_OK) < 0 && !udev_has_devtmpfs(udev)) {
     187           0 :                         log_debug("the udev service seems not to be active, disable the monitor");
     188           0 :                         group = UDEV_MONITOR_NONE;
     189             :                 } else
     190          11 :                         group = UDEV_MONITOR_UDEV;
     191           0 :         } else if (streq(name, "kernel"))
     192           0 :                 group = UDEV_MONITOR_KERNEL;
     193             :         else
     194           0 :                 return NULL;
     195             : 
     196          11 :         udev_monitor = udev_monitor_new(udev);
     197          11 :         if (udev_monitor == NULL)
     198           0 :                 return NULL;
     199             : 
     200          11 :         if (fd < 0) {
     201          11 :                 udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
     202          11 :                 if (udev_monitor->sock < 0) {
     203           0 :                         log_debug_errno(errno, "error getting socket: %m");
     204           0 :                         free(udev_monitor);
     205           0 :                         return NULL;
     206             :                 }
     207             :         } else {
     208           0 :                 udev_monitor->bound = true;
     209           0 :                 udev_monitor->sock = fd;
     210           0 :                 monitor_set_nl_address(udev_monitor);
     211             :         }
     212             : 
     213          11 :         udev_monitor->snl.nl.nl_family = AF_NETLINK;
     214          11 :         udev_monitor->snl.nl.nl_groups = group;
     215             : 
     216             :         /* default destination for sending */
     217          11 :         udev_monitor->snl_destination.nl.nl_family = AF_NETLINK;
     218          11 :         udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV;
     219             : 
     220          11 :         return udev_monitor;
     221             : }
     222             : 
     223             : /**
     224             :  * udev_monitor_new_from_netlink:
     225             :  * @udev: udev library context
     226             :  * @name: name of event source
     227             :  *
     228             :  * Create new udev monitor and connect to a specified event
     229             :  * source. Valid sources identifiers are "udev" and "kernel".
     230             :  *
     231             :  * Applications should usually not connect directly to the
     232             :  * "kernel" events, because the devices might not be useable
     233             :  * at that time, before udev has configured them, and created
     234             :  * device nodes. Accessing devices at the same time as udev,
     235             :  * might result in unpredictable behavior. The "udev" events
     236             :  * are sent out after udev has finished its event processing,
     237             :  * all rules have been processed, and needed device nodes are
     238             :  * created.
     239             :  *
     240             :  * The initial refcount is 1, and needs to be decremented to
     241             :  * release the resources of the udev monitor.
     242             :  *
     243             :  * Returns: a new udev monitor, or #NULL, in case of an error
     244             :  **/
     245          11 : _public_ struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
     246             : {
     247          11 :         return udev_monitor_new_from_netlink_fd(udev, name, -1);
     248             : }
     249             : 
     250          86 : static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
     251             :                             unsigned short code, unsigned int data)
     252             : {
     253          86 :         struct sock_filter *ins = &inss[*i];
     254             : 
     255          86 :         ins->code = code;
     256          86 :         ins->k = data;
     257          86 :         (*i)++;
     258          86 : }
     259             : 
     260          32 : static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
     261             :                            unsigned short code, unsigned int data,
     262             :                            unsigned short jt, unsigned short jf)
     263             : {
     264          32 :         struct sock_filter *ins = &inss[*i];
     265             : 
     266          32 :         ins->code = code;
     267          32 :         ins->jt = jt;
     268          32 :         ins->jf = jf;
     269          32 :         ins->k = data;
     270          32 :         (*i)++;
     271          32 : }
     272             : 
     273             : /**
     274             :  * udev_monitor_filter_update:
     275             :  * @udev_monitor: monitor
     276             :  *
     277             :  * Update the installed socket filter. This is only needed,
     278             :  * if the filter was removed or changed.
     279             :  *
     280             :  * Returns: 0 on success, otherwise a negative error value.
     281             :  */
     282          11 : _public_ int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
     283             : {
     284             :         struct sock_filter ins[512];
     285             :         struct sock_fprog filter;
     286             :         unsigned int i;
     287             :         struct udev_list_entry *list_entry;
     288             :         int err;
     289             : 
     290          21 :         if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL &&
     291          10 :             udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
     292           0 :                 return 0;
     293             : 
     294          11 :         memzero(ins, sizeof(ins));
     295          11 :         i = 0;
     296             : 
     297             :         /* load magic in A */
     298          11 :         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
     299             :         /* jump if magic matches */
     300          11 :         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0);
     301             :         /* wrong magic, pass packet */
     302          11 :         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     303             : 
     304          11 :         if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) {
     305             :                 int tag_matches;
     306             : 
     307             :                 /* count tag matches, to calculate end of tag match block */
     308          10 :                 tag_matches = 0;
     309          20 :                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))
     310          10 :                         tag_matches++;
     311             : 
     312             :                 /* add all tags matches */
     313          20 :                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
     314          10 :                         uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry));
     315          10 :                         uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
     316          10 :                         uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
     317             : 
     318             :                         /* load device bloom bits in A */
     319          10 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi));
     320             :                         /* clear bits (tag bits & bloom bits) */
     321          10 :                         bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi);
     322             :                         /* jump to next tag if it does not match */
     323          10 :                         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3);
     324             : 
     325             :                         /* load device bloom bits in A */
     326          10 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo));
     327             :                         /* clear bits (tag bits & bloom bits) */
     328          10 :                         bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo);
     329             :                         /* jump behind end of tag match block if tag matches */
     330          10 :                         tag_matches--;
     331          10 :                         bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0);
     332             :                 }
     333             : 
     334             :                 /* nothing matched, drop packet */
     335          10 :                 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
     336             :         }
     337             : 
     338             :         /* add all subsystem matches */
     339          11 :         if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) {
     340           2 :                 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
     341           1 :                         unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry));
     342             : 
     343             :                         /* load device subsystem value in A */
     344           1 :                         bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash));
     345           1 :                         if (udev_list_entry_get_value(list_entry) == NULL) {
     346             :                                 /* jump if subsystem does not match */
     347           1 :                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
     348             :                         } else {
     349             :                                 /* jump if subsystem does not match */
     350           0 :                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
     351             : 
     352             :                                 /* load device devtype value in A */
     353           0 :                                 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash));
     354             :                                 /* jump if value does not match */
     355           0 :                                 hash = util_string_hash32(udev_list_entry_get_value(list_entry));
     356           0 :                                 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
     357             :                         }
     358             : 
     359             :                         /* matched, pass packet */
     360           1 :                         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     361             : 
     362           1 :                         if (i+1 >= ELEMENTSOF(ins))
     363           0 :                                 return -E2BIG;
     364             :                 }
     365             : 
     366             :                 /* nothing matched, drop packet */
     367           1 :                 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
     368             :         }
     369             : 
     370             :         /* matched, pass packet */
     371          11 :         bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
     372             : 
     373             :         /* install filter */
     374          11 :         memzero(&filter, sizeof(filter));
     375          11 :         filter.len = i;
     376          11 :         filter.filter = ins;
     377          11 :         err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
     378          11 :         return err < 0 ? -errno : 0;
     379             : }
     380             : 
     381           0 : int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
     382             : {
     383           0 :         udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
     384           0 :         return 0;
     385             : }
     386             : 
     387             : /**
     388             :  * udev_monitor_enable_receiving:
     389             :  * @udev_monitor: the monitor which should receive events
     390             :  *
     391             :  * Binds the @udev_monitor socket to the event source.
     392             :  *
     393             :  * Returns: 0 on success, otherwise a negative error value.
     394             :  */
     395          11 : _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
     396             : {
     397          11 :         int err = 0;
     398          11 :         const int on = 1;
     399             : 
     400          11 :         udev_monitor_filter_update(udev_monitor);
     401             : 
     402          11 :         if (!udev_monitor->bound) {
     403          11 :                 err = bind(udev_monitor->sock,
     404          11 :                            &udev_monitor->snl.sa, sizeof(struct sockaddr_nl));
     405          11 :                 if (err == 0)
     406          11 :                         udev_monitor->bound = true;
     407             :         }
     408             : 
     409          11 :         if (err >= 0)
     410          11 :                 monitor_set_nl_address(udev_monitor);
     411             :         else {
     412           0 :                 log_debug_errno(errno, "bind failed: %m");
     413           0 :                 return -errno;
     414             :         }
     415             : 
     416             :         /* enable receiving of sender credentials */
     417          11 :         err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
     418          11 :         if (err < 0)
     419           0 :                 log_debug_errno(errno, "setting SO_PASSCRED failed: %m");
     420             : 
     421          11 :         return 0;
     422             : }
     423             : 
     424             : /**
     425             :  * udev_monitor_set_receive_buffer_size:
     426             :  * @udev_monitor: the monitor which should receive events
     427             :  * @size: the size in bytes
     428             :  *
     429             :  * Set the size of the kernel socket buffer. This call needs the
     430             :  * appropriate privileges to succeed.
     431             :  *
     432             :  * Returns: 0 on success, otherwise -1 on error.
     433             :  */
     434          10 : _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
     435             : {
     436          10 :         if (udev_monitor == NULL)
     437           0 :                 return -EINVAL;
     438          10 :         return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
     439             : }
     440             : 
     441           0 : int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
     442             : {
     443             :         int err;
     444             : 
     445           0 :         err = close(udev_monitor->sock);
     446           0 :         udev_monitor->sock = -1;
     447           0 :         return err < 0 ? -errno : 0;
     448             : }
     449             : 
     450             : /**
     451             :  * udev_monitor_ref:
     452             :  * @udev_monitor: udev monitor
     453             :  *
     454             :  * Take a reference of a udev monitor.
     455             :  *
     456             :  * Returns: the passed udev monitor
     457             :  **/
     458           0 : _public_ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
     459             : {
     460           0 :         if (udev_monitor == NULL)
     461           0 :                 return NULL;
     462           0 :         udev_monitor->refcount++;
     463           0 :         return udev_monitor;
     464             : }
     465             : 
     466             : /**
     467             :  * udev_monitor_unref:
     468             :  * @udev_monitor: udev monitor
     469             :  *
     470             :  * Drop a reference of a udev monitor. If the refcount reaches zero,
     471             :  * the bound socket will be closed, and the resources of the monitor
     472             :  * will be released.
     473             :  *
     474             :  * Returns: #NULL
     475             :  **/
     476          11 : _public_ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor)
     477             : {
     478          11 :         if (udev_monitor == NULL)
     479           0 :                 return NULL;
     480          11 :         udev_monitor->refcount--;
     481          11 :         if (udev_monitor->refcount > 0)
     482           0 :                 return NULL;
     483          11 :         if (udev_monitor->sock >= 0)
     484          11 :                 close(udev_monitor->sock);
     485          11 :         udev_list_cleanup(&udev_monitor->filter_subsystem_list);
     486          11 :         udev_list_cleanup(&udev_monitor->filter_tag_list);
     487          11 :         free(udev_monitor);
     488          11 :         return NULL;
     489             : }
     490             : 
     491             : /**
     492             :  * udev_monitor_get_udev:
     493             :  * @udev_monitor: udev monitor
     494             :  *
     495             :  * Retrieve the udev library context the monitor was created with.
     496             :  *
     497             :  * Returns: the udev library context
     498             :  **/
     499           0 : _public_ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
     500             : {
     501           0 :         if (udev_monitor == NULL)
     502           0 :                 return NULL;
     503           0 :         return udev_monitor->udev;
     504             : }
     505             : 
     506             : /**
     507             :  * udev_monitor_get_fd:
     508             :  * @udev_monitor: udev monitor
     509             :  *
     510             :  * Retrieve the socket file descriptor associated with the monitor.
     511             :  *
     512             :  * Returns: the socket file descriptor
     513             :  **/
     514          11 : _public_ int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
     515             : {
     516          11 :         if (udev_monitor == NULL)
     517           0 :                 return -EINVAL;
     518          11 :         return udev_monitor->sock;
     519             : }
     520             : 
     521           0 : static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
     522             : {
     523             :         struct udev_list_entry *list_entry;
     524             : 
     525           0 :         if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
     526           0 :                 goto tag;
     527           0 :         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
     528           0 :                 const char *subsys = udev_list_entry_get_name(list_entry);
     529           0 :                 const char *dsubsys = udev_device_get_subsystem(udev_device);
     530             :                 const char *devtype;
     531             :                 const char *ddevtype;
     532             : 
     533           0 :                 if (!streq(dsubsys, subsys))
     534           0 :                         continue;
     535             : 
     536           0 :                 devtype = udev_list_entry_get_value(list_entry);
     537           0 :                 if (devtype == NULL)
     538           0 :                         goto tag;
     539           0 :                 ddevtype = udev_device_get_devtype(udev_device);
     540           0 :                 if (ddevtype == NULL)
     541           0 :                         continue;
     542           0 :                 if (streq(ddevtype, devtype))
     543           0 :                         goto tag;
     544             :         }
     545           0 :         return 0;
     546             : 
     547             : tag:
     548           0 :         if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
     549           0 :                 return 1;
     550           0 :         udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
     551           0 :                 const char *tag = udev_list_entry_get_name(list_entry);
     552             : 
     553           0 :                 if (udev_device_has_tag(udev_device, tag))
     554           0 :                         return 1;
     555             :         }
     556           0 :         return 0;
     557             : }
     558             : 
     559             : /**
     560             :  * udev_monitor_receive_device:
     561             :  * @udev_monitor: udev monitor
     562             :  *
     563             :  * Receive data from the udev monitor socket, allocate a new udev
     564             :  * device, fill in the received data, and return the device.
     565             :  *
     566             :  * Only socket connections with uid=0 are accepted.
     567             :  *
     568             :  * The monitor socket is by default set to NONBLOCK. A variant of poll() on
     569             :  * the file descriptor returned by udev_monitor_get_fd() should to be used to
     570             :  * wake up when new devices arrive, or alternatively the file descriptor
     571             :  * switched into blocking mode.
     572             :  *
     573             :  * The initial refcount is 1, and needs to be decremented to
     574             :  * release the resources of the udev device.
     575             :  *
     576             :  * Returns: a new udev device, or #NULL, in case of an error
     577             :  **/
     578           0 : _public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
     579             : {
     580             :         struct udev_device *udev_device;
     581             :         struct msghdr smsg;
     582             :         struct iovec iov;
     583             :         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
     584             :         struct cmsghdr *cmsg;
     585             :         union sockaddr_union snl;
     586             :         struct ucred *cred;
     587             :         union {
     588             :                 struct udev_monitor_netlink_header nlh;
     589             :                 char raw[8192];
     590             :         } buf;
     591             :         ssize_t buflen;
     592             :         ssize_t bufpos;
     593           0 :         bool is_initialized = false;
     594             : 
     595             : retry:
     596           0 :         if (udev_monitor == NULL)
     597           0 :                 return NULL;
     598           0 :         iov.iov_base = &buf;
     599           0 :         iov.iov_len = sizeof(buf);
     600           0 :         memzero(&smsg, sizeof(struct msghdr));
     601           0 :         smsg.msg_iov = &iov;
     602           0 :         smsg.msg_iovlen = 1;
     603           0 :         smsg.msg_control = cred_msg;
     604           0 :         smsg.msg_controllen = sizeof(cred_msg);
     605           0 :         smsg.msg_name = &snl;
     606           0 :         smsg.msg_namelen = sizeof(snl);
     607             : 
     608           0 :         buflen = recvmsg(udev_monitor->sock, &smsg, 0);
     609           0 :         if (buflen < 0) {
     610           0 :                 if (errno != EINTR)
     611           0 :                         log_debug("unable to receive message");
     612           0 :                 return NULL;
     613             :         }
     614             : 
     615           0 :         if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) {
     616           0 :                 log_debug("invalid message length");
     617           0 :                 return NULL;
     618             :         }
     619             : 
     620           0 :         if (snl.nl.nl_groups == 0) {
     621             :                 /* unicast message, check if we trust the sender */
     622           0 :                 if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 ||
     623           0 :                     snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) {
     624           0 :                         log_debug("unicast netlink message ignored");
     625           0 :                         return NULL;
     626             :                 }
     627           0 :         } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
     628           0 :                 if (snl.nl.nl_pid > 0) {
     629           0 :                         log_debug("multicast kernel netlink message from PID %"PRIu32" ignored",
     630             :                                   snl.nl.nl_pid);
     631           0 :                         return NULL;
     632             :                 }
     633             :         }
     634             : 
     635           0 :         cmsg = CMSG_FIRSTHDR(&smsg);
     636           0 :         if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
     637           0 :                 log_debug("no sender credentials received, message ignored");
     638           0 :                 return NULL;
     639             :         }
     640             : 
     641           0 :         cred = (struct ucred *)CMSG_DATA(cmsg);
     642           0 :         if (cred->uid != 0) {
     643           0 :                 log_debug("sender uid="UID_FMT", message ignored", cred->uid);
     644           0 :                 return NULL;
     645             :         }
     646             : 
     647           0 :         if (memcmp(buf.raw, "libudev", 8) == 0) {
     648             :                 /* udev message needs proper version magic */
     649           0 :                 if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) {
     650           0 :                         log_debug("unrecognized message signature (%x != %x)",
     651             :                                  buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC));
     652           0 :                         return NULL;
     653             :                 }
     654           0 :                 if (buf.nlh.properties_off+32 > (size_t)buflen) {
     655           0 :                         log_debug("message smaller than expected (%u > %zd)",
     656             :                                   buf.nlh.properties_off+32, buflen);
     657           0 :                         return NULL;
     658             :                 }
     659             : 
     660           0 :                 bufpos = buf.nlh.properties_off;
     661             : 
     662             :                 /* devices received from udev are always initialized */
     663           0 :                 is_initialized = true;
     664             :         } else {
     665             :                 /* kernel message with header */
     666           0 :                 bufpos = strlen(buf.raw) + 1;
     667           0 :                 if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
     668           0 :                         log_debug("invalid message length");
     669           0 :                         return NULL;
     670             :                 }
     671             : 
     672             :                 /* check message header */
     673           0 :                 if (strstr(buf.raw, "@/") == NULL) {
     674           0 :                         log_debug("unrecognized message header");
     675           0 :                         return NULL;
     676             :                 }
     677             :         }
     678             : 
     679           0 :         udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
     680           0 :         if (!udev_device) {
     681           0 :                 log_debug("could not create device: %m");
     682           0 :                 return NULL;
     683             :         }
     684             : 
     685           0 :         if (is_initialized)
     686           0 :                 udev_device_set_is_initialized(udev_device);
     687             : 
     688             :         /* skip device, if it does not pass the current filter */
     689           0 :         if (!passes_filter(udev_monitor, udev_device)) {
     690             :                 struct pollfd pfd[1];
     691             :                 int rc;
     692             : 
     693           0 :                 udev_device_unref(udev_device);
     694             : 
     695             :                 /* if something is queued, get next device */
     696           0 :                 pfd[0].fd = udev_monitor->sock;
     697           0 :                 pfd[0].events = POLLIN;
     698           0 :                 rc = poll(pfd, 1, 0);
     699           0 :                 if (rc > 0)
     700           0 :                         goto retry;
     701           0 :                 return NULL;
     702             :         }
     703             : 
     704           0 :         return udev_device;
     705             : }
     706             : 
     707           0 : int udev_monitor_send_device(struct udev_monitor *udev_monitor,
     708             :                              struct udev_monitor *destination, struct udev_device *udev_device)
     709             : {
     710             :         const char *buf, *val;
     711             :         ssize_t blen, count;
     712           0 :         struct udev_monitor_netlink_header nlh = {
     713             :                 .prefix = "libudev",
     714           0 :                 .magic = htonl(UDEV_MONITOR_MAGIC),
     715             :                 .header_size = sizeof nlh,
     716             :         };
     717           0 :         struct iovec iov[2] = {
     718             :                 { .iov_base = &nlh, .iov_len = sizeof nlh },
     719             :         };
     720           0 :         struct msghdr smsg = {
     721             :                 .msg_iov = iov,
     722             :                 .msg_iovlen = 2,
     723             :         };
     724             :         struct udev_list_entry *list_entry;
     725             :         uint64_t tag_bloom_bits;
     726             : 
     727           0 :         blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
     728           0 :         if (blen < 32) {
     729           0 :                 log_debug("device buffer is too small to contain a valid device");
     730           0 :                 return -EINVAL;
     731             :         }
     732             : 
     733             :         /* fill in versioned header */
     734           0 :         val = udev_device_get_subsystem(udev_device);
     735           0 :         nlh.filter_subsystem_hash = htonl(util_string_hash32(val));
     736             : 
     737           0 :         val = udev_device_get_devtype(udev_device);
     738           0 :         if (val != NULL)
     739           0 :                 nlh.filter_devtype_hash = htonl(util_string_hash32(val));
     740             : 
     741             :         /* add tag bloom filter */
     742           0 :         tag_bloom_bits = 0;
     743           0 :         udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
     744           0 :                 tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry));
     745           0 :         if (tag_bloom_bits > 0) {
     746           0 :                 nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32);
     747           0 :                 nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff);
     748             :         }
     749             : 
     750             :         /* add properties list */
     751           0 :         nlh.properties_off = iov[0].iov_len;
     752           0 :         nlh.properties_len = blen;
     753           0 :         iov[1].iov_base = (char *)buf;
     754           0 :         iov[1].iov_len = blen;
     755             : 
     756             :         /*
     757             :          * Use custom address for target, or the default one.
     758             :          *
     759             :          * If we send to a multicast group, we will get
     760             :          * ECONNREFUSED, which is expected.
     761             :          */
     762           0 :         if (destination)
     763           0 :                 smsg.msg_name = &destination->snl;
     764             :         else
     765           0 :                 smsg.msg_name = &udev_monitor->snl_destination;
     766           0 :         smsg.msg_namelen = sizeof(struct sockaddr_nl);
     767           0 :         count = sendmsg(udev_monitor->sock, &smsg, 0);
     768           0 :         if (count < 0) {
     769           0 :                 if (!destination && errno == ECONNREFUSED) {
     770           0 :                         log_debug("passed device to netlink monitor %p", udev_monitor);
     771           0 :                         return 0;
     772             :                 } else
     773           0 :                         return -errno;
     774             :         }
     775             : 
     776           0 :         log_debug("passed %zi byte device to netlink monitor %p", count, udev_monitor);
     777           0 :         return count;
     778             : }
     779             : 
     780             : /**
     781             :  * udev_monitor_filter_add_match_subsystem_devtype:
     782             :  * @udev_monitor: the monitor
     783             :  * @subsystem: the subsystem value to match the incoming devices against
     784             :  * @devtype: the devtype value to match the incoming devices against
     785             :  *
     786             :  * This filter is efficiently executed inside the kernel, and libudev subscribers
     787             :  * will usually not be woken up for devices which do not match.
     788             :  *
     789             :  * The filter must be installed before the monitor is switched to listening mode.
     790             :  *
     791             :  * Returns: 0 on success, otherwise a negative error value.
     792             :  */
     793           1 : _public_ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
     794             : {
     795           1 :         if (udev_monitor == NULL)
     796           0 :                 return -EINVAL;
     797           1 :         if (subsystem == NULL)
     798           0 :                 return -EINVAL;
     799           1 :         if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL)
     800           0 :                 return -ENOMEM;
     801           1 :         return 0;
     802             : }
     803             : 
     804             : /**
     805             :  * udev_monitor_filter_add_match_tag:
     806             :  * @udev_monitor: the monitor
     807             :  * @tag: the name of a tag
     808             :  *
     809             :  * This filter is efficiently executed inside the kernel, and libudev subscribers
     810             :  * will usually not be woken up for devices which do not match.
     811             :  *
     812             :  * The filter must be installed before the monitor is switched to listening mode.
     813             :  *
     814             :  * Returns: 0 on success, otherwise a negative error value.
     815             :  */
     816          10 : _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
     817             : {
     818          10 :         if (udev_monitor == NULL)
     819           0 :                 return -EINVAL;
     820          10 :         if (tag == NULL)
     821           0 :                 return -EINVAL;
     822          10 :         if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL)
     823           0 :                 return -ENOMEM;
     824          10 :         return 0;
     825             : }
     826             : 
     827             : /**
     828             :  * udev_monitor_filter_remove:
     829             :  * @udev_monitor: monitor
     830             :  *
     831             :  * Remove all filters from monitor.
     832             :  *
     833             :  * Returns: 0 on success, otherwise a negative error value.
     834             :  */
     835           0 : _public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
     836             : {
     837             :         static struct sock_fprog filter = { 0, NULL };
     838             : 
     839           0 :         udev_list_cleanup(&udev_monitor->filter_subsystem_list);
     840           0 :         return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
     841             : }

Generated by: LCOV version 1.11