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