]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-node.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
12 #include "alloc-util.h"
13 #include "device-private.h"
14 #include "device-util.h"
15 #include "dirent-util.h"
17 #include "format-util.h"
19 #include "hexdecoct.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"
28 #include "udev-node.h"
29 #include "user-util.h"
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)
36 static int create_symlink(const char *target
, const char *slink
) {
42 for (unsigned i
= 0; i
< CREATE_LINK_MAX_RETRIES
; i
++) {
43 r
= mkdir_parents_label(slink
, 0755);
49 mac_selinux_create_file_prepare(slink
, S_IFLNK
);
50 if (symlink(target
, slink
) < 0)
54 mac_selinux_create_file_clear();
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
;
72 r
= path_extract_directory(slink
, &slink_dirname
);
74 return log_device_debug_errno(dev
, r
, "Failed to get parent directory of '%s': %m", slink
);
76 /* use relative link */
77 r
= path_make_relative(slink_dirname
, node
, &target
);
79 return log_device_debug_errno(dev
, r
, "Failed to get relative path from '%s' to '%s': %m", slink
, node
);
81 if (lstat(slink
, &stats
) >= 0) {
82 _cleanup_free_
char *buf
= NULL
;
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
);
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
);
93 (void) label_fix(slink
, LABEL_IGNORE_ENOENT
);
94 (void) utimensat(AT_FDCWD
, slink
, NULL
, AT_SYMLINK_NOFOLLOW
);
98 } else if (errno
== ENOENT
) {
99 log_device_debug(dev
, "Creating symlink '%s' to '%s'", slink
, target
);
101 r
= create_symlink(target
, slink
);
105 log_device_debug_errno(dev
, r
, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink
, target
, slink
);
107 return log_device_debug_errno(dev
, errno
, "Failed to lstat() '%s': %m", slink
);
109 log_device_debug(dev
, "Atomically replace '%s'", slink
);
111 r
= device_get_device_id(dev
, &id
);
113 return log_device_debug_errno(dev
, r
, "Failed to get device id: %m");
114 slink_tmp
= strjoina(slink
, ".tmp-", id
);
116 (void) unlink(slink_tmp
);
118 r
= create_symlink(target
, slink_tmp
);
120 return log_device_debug_errno(dev
, r
, "Failed to create symlink '%s' to '%s': %m", slink_tmp
, target
);
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
);
128 /* Tell caller that we replaced already existing symlink. */
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
;
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. */
149 r
= device_get_devlink_priority(dev
, &priority
);
153 r
= sd_device_get_devname(dev
, &devnode
);
157 target
= strdup(devnode
);
162 dir
= opendir(stackdir
);
164 if (errno
== ENOENT
) {
165 *ret
= TAKE_PTR(target
);
172 r
= device_get_device_id(dev
, &id
);
176 FOREACH_DIRENT_ALL(dent
, dir
, break) {
177 _cleanup_(sd_device_unrefp
) sd_device
*dev_db
= NULL
;
181 if (dent
->d_name
[0] == '\0')
183 if (dent
->d_name
[0] == '.')
186 log_device_debug(dev
, "Found '%s' claiming '%s'", dent
->d_name
, stackdir
);
188 /* did we find ourself? */
189 if (streq(dent
->d_name
, id
))
192 if (sd_device_new_from_device_id(&dev_db
, dent
->d_name
) < 0)
195 if (sd_device_get_devname(dev_db
, &devnode
) < 0)
198 if (device_get_devlink_priority(dev_db
, &db_prio
) < 0)
201 if (target
&& db_prio
<= priority
)
204 log_device_debug(dev_db
, "Device claims priority %i for '%s'", db_prio
, stackdir
);
206 r
= free_and_strdup(&target
, devnode
);
212 *ret
= TAKE_PTR(target
);
216 size_t udev_node_escape_path(const char *src
, char *dest
, size_t size
) {
224 for (i
= 0, j
= 0; src
[i
] != '\0'; i
++) {
226 if (j
+4 >= size
- 12 + 1)
228 memcpy(&dest
[j
], "\\x2f", 4);
230 } else if (src
[i
] == '\\') {
231 if (j
+4 >= size
- 12 + 1)
233 memcpy(&dest
[j
], "\\x5c", 4);
236 if (j
+1 >= size
- 12 + 1)
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. */
249 h
= siphash24_string(src
, UDEV_NODE_HASH_KEY
.bytes
);
251 for (unsigned k
= 0; k
<= 10; k
++)
252 dest
[size
- k
- 2] = urlsafe_base64char((h
>> (k
* 6)) & 63);
254 dest
[size
- 1] = '\0';
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];
268 slink
= strdup(slink_in
);
270 return log_oom_debug();
272 path_simplify(slink
);
274 slink_name
= path_startswith(slink
, "/dev");
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
);
281 r
= device_get_device_id(dev
, &id
);
283 return log_device_debug_errno(dev
, r
, "Failed to get device id: %m");
285 (void) udev_node_escape_path(slink_name
, name_enc
, sizeof(name_enc
));
286 dirname
= path_join("/run/udev/links/", name_enc
);
288 return log_oom_debug();
290 filename
= path_join(dirname
, id
);
292 return log_oom_debug();
295 if (unlink(filename
) < 0 && errno
!= ENOENT
)
296 log_device_debug_errno(dev
, errno
, "Failed to remove %s, ignoring: %m", filename
);
298 (void) rmdir(dirname
);
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);
308 return log_device_debug_errno(dev
, r
, "Failed to create %s: %m", filename
);
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;
315 for (i
= 0; i
< retries
; i
++) {
316 _cleanup_free_
char *target
= NULL
;
317 struct stat st1
= {}, st2
= {};
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
);
323 r
= link_find_prioritized(dev
, add
, dirname
, &target
);
325 return log_device_debug_errno(dev
, r
, "Failed to determine highest priority for symlink '%s': %m", slink
);
327 log_device_debug(dev
, "No reference left for '%s', removing", slink
);
329 if (unlink(slink
) < 0 && errno
!= ENOENT
)
330 log_device_debug_errno(dev
, errno
, "Failed to remove '%s', ignoring: %m", slink
);
332 (void) rmdir_parents(slink
, "/dev");
336 r
= node_symlink(dev
, target
, slink
);
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. */
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
);
351 if (stat_inode_unmodified(&st1
, &st2
))
356 return i
< LINK_UPDATE_MAX_RETRIES
? 0 : -ELOOP
;
359 int udev_node_update_old_links(sd_device
*dev
, sd_device
*dev_old
) {
366 /* update possible left-over symlinks */
367 FOREACH_DEVICE_DEVLINK(dev_old
, name
) {
368 const char *name_current
;
371 /* check if old link name still belongs to this device */
372 FOREACH_DEVICE_DEVLINK(dev
, name_current
)
373 if (streq(name
, name_current
)) {
381 log_device_debug(dev
,
382 "Updating old device symlink '%s', which is no longer belonging to this device.",
385 r
= link_update(dev
, name
, false);
387 log_device_warning_errno(dev
, r
,
388 "Failed to update device symlink '%s', ignoring: %m",
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;
407 r
= sd_device_get_devname(dev
, &devnode
);
409 return log_device_debug_errno(dev
, r
, "Failed to get devname: %m");
410 r
= sd_device_get_subsystem(dev
, &subsystem
);
412 return log_device_debug_errno(dev
, r
, "Failed to get subsystem: %m");
413 r
= sd_device_get_devnum(dev
, &devnum
);
415 return log_device_debug_errno(dev
, r
, "Failed to get devnum: %m");
416 (void) device_get_device_id(dev
, &id
);
418 if (streq(subsystem
, "block"))
423 node_fd
= open(devnode
, O_PATH
|O_NOFOLLOW
|O_CLOEXEC
);
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 */
430 return log_device_debug_errno(dev
, errno
, "Cannot open node %s: %m", devnode
);
433 if (fstat(node_fd
, &stats
) < 0)
434 return log_device_debug_errno(dev
, errno
, "cannot stat() node %s: %m", devnode
);
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.",
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. */
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
;
447 if (apply_mode
|| apply_uid
|| apply_gid
|| apply_mac
) {
448 bool selinux
= false, smack
= false;
449 const char *name
, *label
;
451 if (apply_mode
|| apply_uid
|| apply_gid
) {
452 log_device_debug(dev
, "Setting permissions %s, uid=" UID_FMT
", gid=" GID_FMT
", mode=%#o",
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);
458 r
= fchmod_and_chown(node_fd
, mode
, uid
, gid
);
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",
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);
468 log_device_debug(dev
, "Preserve permissions of %s, uid=" UID_FMT
", gid=" GID_FMT
", mode=%#o",
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);
474 /* apply SECLABEL{$module}=$label */
475 ORDERED_HASHMAP_FOREACH_KEY(label
, name
, seclabel_list
) {
478 if (streq(name
, "selinux")) {
481 q
= mac_selinux_apply_fd(node_fd
, devnode
, label
);
483 log_device_full_errno(dev
, q
== -ENOENT
? LOG_DEBUG
: LOG_ERR
, q
,
484 "SECLABEL: failed to set SELinux label '%s': %m", label
);
486 log_device_debug(dev
, "SECLABEL: set SELinux label '%s'", label
);
488 } else if (streq(name
, "smack")) {
491 q
= mac_smack_apply_fd(node_fd
, SMACK_ATTR_ACCESS
, label
);
493 log_device_full_errno(dev
, q
== -ENOENT
? LOG_DEBUG
: LOG_ERR
, q
,
494 "SECLABEL: failed to set SMACK label '%s': %m", label
);
496 log_device_debug(dev
, "SECLABEL: set SMACK label '%s'", label
);
499 log_device_error(dev
, "SECLABEL: unknown subsystem, ignoring '%s'='%s'", name
, label
);
502 /* set the defaults */
504 (void) mac_selinux_fix_fd(node_fd
, devnode
, LABEL_IGNORE_ENOENT
);
506 (void) mac_smack_apply_fd(node_fd
, SMACK_ATTR_ACCESS
, NULL
);
509 /* always update timestamp when we re-use the node, like on media change events */
510 r
= futimens_opath(node_fd
, NULL
);
512 log_device_debug_errno(dev
, r
, "Failed to adjust timestamp of node %s: %m", devnode
);
517 static int xsprintf_dev_num_path_from_sd_device(sd_device
*dev
, char **ret
) {
518 const char *subsystem
;
524 r
= sd_device_get_subsystem(dev
, &subsystem
);
528 r
= sd_device_get_devnum(dev
, &devnum
);
532 return device_path_make_major_minor(streq(subsystem
, "block") ? S_IFBLK
: S_IFCHR
, devnum
, ret
);
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
;
544 r
= sd_device_get_devname(dev
, &devnode
);
546 return log_device_debug_errno(dev
, r
, "Failed to get devnode: %m");
549 const char *id
= NULL
;
551 (void) device_get_device_id(dev
, &id
);
552 log_device_debug(dev
, "Handling device node '%s', devnum=%s", devnode
, strna(id
));
555 r
= node_permissions_apply(dev
, apply
, mode
, uid
, gid
, seclabel_list
);
559 /* create/update symlinks, add symlinks to name index */
560 FOREACH_DEVICE_DEVLINK(dev
, devlink
) {
561 r
= link_update(dev
, devlink
, true);
563 log_device_warning_errno(dev
, r
,
564 "Failed to update device symlink '%s', ignoring: %m",
568 r
= xsprintf_dev_num_path_from_sd_device(dev
, &filename
);
570 return log_device_debug_errno(dev
, r
, "Failed to get device path: %m");
572 /* always add /dev/{block,char}/$major:$minor */
573 r
= node_symlink(dev
, devnode
, filename
);
575 return log_device_warning_errno(dev
, r
, "Failed to create device symlink '%s': %m", filename
);
580 int udev_node_remove(sd_device
*dev
) {
581 _cleanup_free_
char *filename
= NULL
;
587 /* remove/update symlinks, remove symlinks from name index */
588 FOREACH_DEVICE_DEVLINK(dev
, devlink
) {
589 r
= link_update(dev
, devlink
, false);
591 log_device_warning_errno(dev
, r
,
592 "Failed to update device symlink '%s', ignoring: %m",
596 r
= xsprintf_dev_num_path_from_sd_device(dev
, &filename
);
598 return log_device_debug_errno(dev
, r
, "Failed to get device path: %m");
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
);