Bug Summary

File:build-scan/../src/libudev/libudev-monitor.c
Warning:line 149, column 45
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

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