]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-node.c
Merge pull request #20030 from keszybz/exec_fd-event-source
[thirdparty/systemd.git] / src / udev / udev-node.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9
10 #include "sd-id128.h"
11
12 #include "alloc-util.h"
13 #include "device-private.h"
14 #include "device-util.h"
15 #include "dirent-util.h"
16 #include "fd-util.h"
17 #include "format-util.h"
18 #include "fs-util.h"
19 #include "hexdecoct.h"
20 #include "mkdir.h"
21 #include "path-util.h"
22 #include "selinux-util.h"
23 #include "smack-util.h"
24 #include "stat-util.h"
25 #include "stdio-util.h"
26 #include "string-util.h"
27 #include "strxcpyx.h"
28 #include "udev-node.h"
29 #include "user-util.h"
30
31 #define CREATE_LINK_MAX_RETRIES 128
32 #define LINK_UPDATE_MAX_RETRIES 128
33 #define TOUCH_FILE_MAX_RETRIES 128
34 #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
35
36 static int create_symlink(const char *target, const char *slink) {
37 int r;
38
39 assert(target);
40 assert(slink);
41
42 for (unsigned i = 0; i < CREATE_LINK_MAX_RETRIES; i++) {
43 r = mkdir_parents_label(slink, 0755);
44 if (r == -ENOENT)
45 continue;
46 if (r < 0)
47 return r;
48
49 mac_selinux_create_file_prepare(slink, S_IFLNK);
50 if (symlink(target, slink) < 0)
51 r = -errno;
52 else
53 r = 0;
54 mac_selinux_create_file_clear();
55 if (r != -ENOENT)
56 return r;
57 }
58
59 return r;
60 }
61
62 static int node_symlink(sd_device *dev, const char *node, const char *slink) {
63 _cleanup_free_ char *slink_dirname = NULL, *target = NULL;
64 const char *id, *slink_tmp;
65 struct stat stats;
66 int r;
67
68 assert(dev);
69 assert(node);
70 assert(slink);
71
72 r = path_extract_directory(slink, &slink_dirname);
73 if (r < 0)
74 return log_device_debug_errno(dev, r, "Failed to get parent directory of '%s': %m", slink);
75
76 /* use relative link */
77 r = path_make_relative(slink_dirname, node, &target);
78 if (r < 0)
79 return log_device_debug_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);
80
81 if (lstat(slink, &stats) >= 0) {
82 _cleanup_free_ char *buf = NULL;
83
84 if (!S_ISLNK(stats.st_mode))
85 return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
86 "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node);
87
88 if (readlink_malloc(slink, &buf) >= 0 &&
89 path_equal(target, buf)) {
90 /* preserve link with correct target, do not replace node of other device */
91 log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
92
93 (void) label_fix(slink, LABEL_IGNORE_ENOENT);
94 (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
95
96 return 0;
97 }
98 } else if (errno == ENOENT) {
99 log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
100
101 r = create_symlink(target, slink);
102 if (r >= 0)
103 return 0;
104
105 log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
106 } else
107 return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
108
109 log_device_debug(dev, "Atomically replace '%s'", slink);
110
111 r = device_get_device_id(dev, &id);
112 if (r < 0)
113 return log_device_debug_errno(dev, r, "Failed to get device id: %m");
114 slink_tmp = strjoina(slink, ".tmp-", id);
115
116 (void) unlink(slink_tmp);
117
118 r = create_symlink(target, slink_tmp);
119 if (r < 0)
120 return log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink_tmp, target);
121
122 if (rename(slink_tmp, slink) < 0) {
123 r = log_device_debug_errno(dev, errno, "Failed to rename '%s' to '%s': %m", slink_tmp, slink);
124 (void) unlink(slink_tmp);
125 return r;
126 }
127
128 /* Tell caller that we replaced already existing symlink. */
129 return 1;
130 }
131
132 static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) {
133 _cleanup_closedir_ DIR *dir = NULL;
134 _cleanup_free_ char *target = NULL;
135 struct dirent *dent;
136 int r, priority = 0;
137 const char *id;
138
139 assert(dev);
140 assert(stackdir);
141 assert(ret);
142
143 /* Find device node of device with highest priority. This returns 1 if a device found, 0 if no
144 * device found, or a negative errno. */
145
146 if (add) {
147 const char *devnode;
148
149 r = device_get_devlink_priority(dev, &priority);
150 if (r < 0)
151 return r;
152
153 r = sd_device_get_devname(dev, &devnode);
154 if (r < 0)
155 return r;
156
157 target = strdup(devnode);
158 if (!target)
159 return -ENOMEM;
160 }
161
162 dir = opendir(stackdir);
163 if (!dir) {
164 if (errno == ENOENT) {
165 *ret = TAKE_PTR(target);
166 return !!*ret;
167 }
168
169 return -errno;
170 }
171
172 r = device_get_device_id(dev, &id);
173 if (r < 0)
174 return r;
175
176 FOREACH_DIRENT_ALL(dent, dir, break) {
177 _cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
178 const char *devnode;
179 int db_prio = 0;
180
181 if (dent->d_name[0] == '\0')
182 break;
183 if (dent->d_name[0] == '.')
184 continue;
185
186 log_device_debug(dev, "Found '%s' claiming '%s'", dent->d_name, stackdir);
187
188 /* did we find ourself? */
189 if (streq(dent->d_name, id))
190 continue;
191
192 if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0)
193 continue;
194
195 if (sd_device_get_devname(dev_db, &devnode) < 0)
196 continue;
197
198 if (device_get_devlink_priority(dev_db, &db_prio) < 0)
199 continue;
200
201 if (target && db_prio <= priority)
202 continue;
203
204 log_device_debug(dev_db, "Device claims priority %i for '%s'", db_prio, stackdir);
205
206 r = free_and_strdup(&target, devnode);
207 if (r < 0)
208 return r;
209 priority = db_prio;
210 }
211
212 *ret = TAKE_PTR(target);
213 return !!*ret;
214 }
215
216 size_t udev_node_escape_path(const char *src, char *dest, size_t size) {
217 size_t i, j;
218 uint64_t h;
219
220 assert(src);
221 assert(dest);
222 assert(size >= 12);
223
224 for (i = 0, j = 0; src[i] != '\0'; i++) {
225 if (src[i] == '/') {
226 if (j+4 >= size - 12 + 1)
227 goto toolong;
228 memcpy(&dest[j], "\\x2f", 4);
229 j += 4;
230 } else if (src[i] == '\\') {
231 if (j+4 >= size - 12 + 1)
232 goto toolong;
233 memcpy(&dest[j], "\\x5c", 4);
234 j += 4;
235 } else {
236 if (j+1 >= size - 12 + 1)
237 goto toolong;
238 dest[j] = src[i];
239 j++;
240 }
241 }
242 dest[j] = '\0';
243 return j;
244
245 toolong:
246 /* If the input path is too long to encode as a filename, then let's suffix with a string
247 * generated from the hash of the path. */
248
249 h = siphash24_string(src, UDEV_NODE_HASH_KEY.bytes);
250
251 for (unsigned k = 0; k <= 10; k++)
252 dest[size - k - 2] = urlsafe_base64char((h >> (k * 6)) & 63);
253
254 dest[size - 1] = '\0';
255 return size - 1;
256 }
257
258 /* manage "stack of names" with possibly specified device priorities */
259 static int link_update(sd_device *dev, const char *slink_in, bool add) {
260 _cleanup_free_ char *slink = NULL, *filename = NULL, *dirname = NULL;
261 const char *slink_name, *id;
262 char name_enc[NAME_MAX+1];
263 int i, r, retries;
264
265 assert(dev);
266 assert(slink_in);
267
268 slink = strdup(slink_in);
269 if (!slink)
270 return log_oom_debug();
271
272 path_simplify(slink);
273
274 slink_name = path_startswith(slink, "/dev");
275 if (!slink_name ||
276 empty_or_root(slink_name) ||
277 !path_is_normalized(slink_name))
278 return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
279 "Invalid symbolic link of device node: %s", slink);
280
281 r = device_get_device_id(dev, &id);
282 if (r < 0)
283 return log_device_debug_errno(dev, r, "Failed to get device id: %m");
284
285 (void) udev_node_escape_path(slink_name, name_enc, sizeof(name_enc));
286 dirname = path_join("/run/udev/links/", name_enc);
287 if (!dirname)
288 return log_oom_debug();
289
290 filename = path_join(dirname, id);
291 if (!filename)
292 return log_oom_debug();
293
294 if (!add) {
295 if (unlink(filename) < 0 && errno != ENOENT)
296 log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
297
298 (void) rmdir(dirname);
299 } else {
300 for (unsigned j = 0; j < TOUCH_FILE_MAX_RETRIES; j++) {
301 /* This may fail with -ENOENT when the parent directory is removed during
302 * creating the file by another udevd worker. */
303 r = touch_file(filename, /* parents= */ true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
304 if (r != -ENOENT)
305 break;
306 }
307 if (r < 0)
308 return log_device_debug_errno(dev, r, "Failed to create %s: %m", filename);
309 }
310
311 /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
312 * will be fixed in the second invocation. */
313 retries = sd_device_get_is_initialized(dev) > 0 ? LINK_UPDATE_MAX_RETRIES : 1;
314
315 for (i = 0; i < retries; i++) {
316 _cleanup_free_ char *target = NULL;
317 struct stat st1 = {}, st2 = {};
318
319 r = stat(dirname, &st1);
320 if (r < 0 && errno != ENOENT)
321 return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
322
323 r = link_find_prioritized(dev, add, dirname, &target);
324 if (r < 0)
325 return log_device_debug_errno(dev, r, "Failed to determine highest priority for symlink '%s': %m", slink);
326 if (r == 0) {
327 log_device_debug(dev, "No reference left for '%s', removing", slink);
328
329 if (unlink(slink) < 0 && errno != ENOENT)
330 log_device_debug_errno(dev, errno, "Failed to remove '%s', ignoring: %m", slink);
331
332 (void) rmdir_parents(slink, "/dev");
333 break;
334 }
335
336 r = node_symlink(dev, target, slink);
337 if (r < 0)
338 return r;
339 if (r == 1)
340 /* We have replaced already existing symlink, possibly there is some other device trying
341 * to claim the same symlink. Let's do one more iteration to give us a chance to fix
342 * the error if other device actually claims the symlink with higher priority. */
343 continue;
344
345 /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */
346 if ((st1.st_mode & S_IFMT) != 0) {
347 r = stat(dirname, &st2);
348 if (r < 0 && errno != ENOENT)
349 return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
350
351 if (stat_inode_unmodified(&st1, &st2))
352 break;
353 }
354 }
355
356 return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
357 }
358
359 int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
360 const char *name;
361 int r;
362
363 assert(dev);
364 assert(dev_old);
365
366 /* update possible left-over symlinks */
367 FOREACH_DEVICE_DEVLINK(dev_old, name) {
368 const char *name_current;
369 bool found = false;
370
371 /* check if old link name still belongs to this device */
372 FOREACH_DEVICE_DEVLINK(dev, name_current)
373 if (streq(name, name_current)) {
374 found = true;
375 break;
376 }
377
378 if (found)
379 continue;
380
381 log_device_debug(dev,
382 "Updating old device symlink '%s', which is no longer belonging to this device.",
383 name);
384
385 r = link_update(dev, name, false);
386 if (r < 0)
387 log_device_warning_errno(dev, r,
388 "Failed to update device symlink '%s', ignoring: %m",
389 name);
390 }
391
392 return 0;
393 }
394
395 static int node_permissions_apply(sd_device *dev, bool apply_mac,
396 mode_t mode, uid_t uid, gid_t gid,
397 OrderedHashmap *seclabel_list) {
398 const char *devnode, *subsystem, *id = NULL;
399 bool apply_mode, apply_uid, apply_gid;
400 _cleanup_close_ int node_fd = -1;
401 struct stat stats;
402 dev_t devnum;
403 int r;
404
405 assert(dev);
406
407 r = sd_device_get_devname(dev, &devnode);
408 if (r < 0)
409 return log_device_debug_errno(dev, r, "Failed to get devname: %m");
410 r = sd_device_get_subsystem(dev, &subsystem);
411 if (r < 0)
412 return log_device_debug_errno(dev, r, "Failed to get subsystem: %m");
413 r = sd_device_get_devnum(dev, &devnum);
414 if (r < 0)
415 return log_device_debug_errno(dev, r, "Failed to get devnum: %m");
416 (void) device_get_device_id(dev, &id);
417
418 if (streq(subsystem, "block"))
419 mode |= S_IFBLK;
420 else
421 mode |= S_IFCHR;
422
423 node_fd = open(devnode, O_PATH|O_NOFOLLOW|O_CLOEXEC);
424 if (node_fd < 0) {
425 if (errno == ENOENT) {
426 log_device_debug_errno(dev, errno, "Device node %s is missing, skipping handling.", devnode);
427 return 0; /* This is necessarily racey, so ignore missing the device */
428 }
429
430 return log_device_debug_errno(dev, errno, "Cannot open node %s: %m", devnode);
431 }
432
433 if (fstat(node_fd, &stats) < 0)
434 return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode);
435
436 if ((mode != MODE_INVALID && (stats.st_mode & S_IFMT) != (mode & S_IFMT)) || stats.st_rdev != devnum) {
437 log_device_debug(dev, "Found node '%s' with non-matching devnum %s, skipping handling.",
438 devnode, strna(id));
439 return 0; /* We might process a device that already got replaced by the time we have a look
440 * at it, handle this gracefully and step away. */
441 }
442
443 apply_mode = mode != MODE_INVALID && (stats.st_mode & 0777) != (mode & 0777);
444 apply_uid = uid_is_valid(uid) && stats.st_uid != uid;
445 apply_gid = gid_is_valid(gid) && stats.st_gid != gid;
446
447 if (apply_mode || apply_uid || apply_gid || apply_mac) {
448 bool selinux = false, smack = false;
449 const char *name, *label;
450
451 if (apply_mode || apply_uid || apply_gid) {
452 log_device_debug(dev, "Setting permissions %s, uid=" UID_FMT ", gid=" GID_FMT ", mode=%#o",
453 devnode,
454 uid_is_valid(uid) ? uid : stats.st_uid,
455 gid_is_valid(gid) ? gid : stats.st_gid,
456 mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
457
458 r = fchmod_and_chown(node_fd, mode, uid, gid);
459 if (r < 0)
460 log_device_full_errno(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
461 "Failed to set owner/mode of %s to uid=" UID_FMT
462 ", gid=" GID_FMT ", mode=%#o: %m",
463 devnode,
464 uid_is_valid(uid) ? uid : stats.st_uid,
465 gid_is_valid(gid) ? gid : stats.st_gid,
466 mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
467 } else
468 log_device_debug(dev, "Preserve permissions of %s, uid=" UID_FMT ", gid=" GID_FMT ", mode=%#o",
469 devnode,
470 uid_is_valid(uid) ? uid : stats.st_uid,
471 gid_is_valid(gid) ? gid : stats.st_gid,
472 mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
473
474 /* apply SECLABEL{$module}=$label */
475 ORDERED_HASHMAP_FOREACH_KEY(label, name, seclabel_list) {
476 int q;
477
478 if (streq(name, "selinux")) {
479 selinux = true;
480
481 q = mac_selinux_apply_fd(node_fd, devnode, label);
482 if (q < 0)
483 log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
484 "SECLABEL: failed to set SELinux label '%s': %m", label);
485 else
486 log_device_debug(dev, "SECLABEL: set SELinux label '%s'", label);
487
488 } else if (streq(name, "smack")) {
489 smack = true;
490
491 q = mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, label);
492 if (q < 0)
493 log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
494 "SECLABEL: failed to set SMACK label '%s': %m", label);
495 else
496 log_device_debug(dev, "SECLABEL: set SMACK label '%s'", label);
497
498 } else
499 log_device_error(dev, "SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label);
500 }
501
502 /* set the defaults */
503 if (!selinux)
504 (void) mac_selinux_fix_fd(node_fd, devnode, LABEL_IGNORE_ENOENT);
505 if (!smack)
506 (void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL);
507 }
508
509 /* always update timestamp when we re-use the node, like on media change events */
510 r = futimens_opath(node_fd, NULL);
511 if (r < 0)
512 log_device_debug_errno(dev, r, "Failed to adjust timestamp of node %s: %m", devnode);
513
514 return r;
515 }
516
517 static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) {
518 const char *subsystem;
519 dev_t devnum;
520 int r;
521
522 assert(ret);
523
524 r = sd_device_get_subsystem(dev, &subsystem);
525 if (r < 0)
526 return r;
527
528 r = sd_device_get_devnum(dev, &devnum);
529 if (r < 0)
530 return r;
531
532 return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
533 }
534
535 int udev_node_add(sd_device *dev, bool apply,
536 mode_t mode, uid_t uid, gid_t gid,
537 OrderedHashmap *seclabel_list) {
538 const char *devnode, *devlink;
539 _cleanup_free_ char *filename = NULL;
540 int r;
541
542 assert(dev);
543
544 r = sd_device_get_devname(dev, &devnode);
545 if (r < 0)
546 return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
547
548 if (DEBUG_LOGGING) {
549 const char *id = NULL;
550
551 (void) device_get_device_id(dev, &id);
552 log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
553 }
554
555 r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);
556 if (r < 0)
557 return r;
558
559 /* create/update symlinks, add symlinks to name index */
560 FOREACH_DEVICE_DEVLINK(dev, devlink) {
561 r = link_update(dev, devlink, true);
562 if (r < 0)
563 log_device_warning_errno(dev, r,
564 "Failed to update device symlink '%s', ignoring: %m",
565 devlink);
566 }
567
568 r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
569 if (r < 0)
570 return log_device_debug_errno(dev, r, "Failed to get device path: %m");
571
572 /* always add /dev/{block,char}/$major:$minor */
573 r = node_symlink(dev, devnode, filename);
574 if (r < 0)
575 return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
576
577 return 0;
578 }
579
580 int udev_node_remove(sd_device *dev) {
581 _cleanup_free_ char *filename = NULL;
582 const char *devlink;
583 int r;
584
585 assert(dev);
586
587 /* remove/update symlinks, remove symlinks from name index */
588 FOREACH_DEVICE_DEVLINK(dev, devlink) {
589 r = link_update(dev, devlink, false);
590 if (r < 0)
591 log_device_warning_errno(dev, r,
592 "Failed to update device symlink '%s', ignoring: %m",
593 devlink);
594 }
595
596 r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
597 if (r < 0)
598 return log_device_debug_errno(dev, r, "Failed to get device path: %m");
599
600 /* remove /dev/{block,char}/$major:$minor */
601 if (unlink(filename) < 0 && errno != ENOENT)
602 return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
603
604 return 0;
605 }