From f14aa5ad42e05f3e9124ac5d53b847b5de1eb9c3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 6 Apr 2022 01:35:04 +0900 Subject: [PATCH 1/4] udev: drop unnecessary code Follow-up for 78e278ad48e0d2854f950f261804fde70121820e. --- src/udev/udev-node.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index c313181041..4afd604860 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -598,11 +598,10 @@ int udev_node_apply_permissions( gid_t gid, OrderedHashmap *seclabel_list) { - const char *devnode, *subsystem; + const char *devnode; bool apply_mode, apply_uid, apply_gid; _cleanup_close_ int node_fd = -1; struct stat stats; - dev_t devnum; int r; assert(dev); @@ -610,17 +609,6 @@ int udev_node_apply_permissions( r = sd_device_get_devname(dev, &devnode); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get devname: %m"); - r = sd_device_get_subsystem(dev, &subsystem); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get subsystem: %m"); - r = sd_device_get_devnum(dev, &devnum); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get devnum: %m"); - - if (streq(subsystem, "block")) - mode |= S_IFBLK; - else - mode |= S_IFCHR; node_fd = sd_device_open(dev, O_PATH|O_CLOEXEC); if (node_fd < 0) { From a782f2a3fc4889ad7cca0a8fc77a5b0e4d5ed378 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 6 Apr 2022 01:51:47 +0900 Subject: [PATCH 2/4] udev: split udev_node_apply_permissions() into two --- src/udev/udev-node.c | 56 +++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 4afd604860..83d3242a25 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -590,35 +590,22 @@ int udev_node_remove(sd_device *dev) { return 0; } -int udev_node_apply_permissions( - sd_device *dev, +static int udev_node_apply_permissions_impl( + sd_device *dev, /* can be NULL, only used for logging. */ + int node_fd, + const char *devnode, bool apply_mac, mode_t mode, uid_t uid, gid_t gid, OrderedHashmap *seclabel_list) { - const char *devnode; bool apply_mode, apply_uid, apply_gid; - _cleanup_close_ int node_fd = -1; struct stat stats; int r; - assert(dev); - - r = sd_device_get_devname(dev, &devnode); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get devname: %m"); - - node_fd = sd_device_open(dev, O_PATH|O_CLOEXEC); - if (node_fd < 0) { - if (ERRNO_IS_DEVICE_ABSENT(node_fd)) { - log_device_debug_errno(dev, node_fd, "Device node %s is missing, skipping handling.", devnode); - return 0; /* This is necessarily racey, so ignore missing the device */ - } - - return log_device_debug_errno(dev, node_fd, "Cannot open node %s: %m", devnode); - } + assert(node_fd >= 0); + assert(devnode); if (fstat(node_fd, &stats) < 0) return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode); @@ -696,3 +683,34 @@ int udev_node_apply_permissions( return 0; } + +int udev_node_apply_permissions( + sd_device *dev, + bool apply_mac, + mode_t mode, + uid_t uid, + gid_t gid, + OrderedHashmap *seclabel_list) { + + const char *devnode; + _cleanup_close_ int node_fd = -1; + int r; + + assert(dev); + + r = sd_device_get_devname(dev, &devnode); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get devname: %m"); + + node_fd = sd_device_open(dev, O_PATH|O_CLOEXEC); + if (node_fd < 0) { + if (ERRNO_IS_DEVICE_ABSENT(node_fd)) { + log_device_debug_errno(dev, node_fd, "Device node %s is missing, skipping handling.", devnode); + return 0; /* This is necessarily racey, so ignore missing the device */ + } + + return log_device_debug_errno(dev, node_fd, "Cannot open node %s: %m", devnode); + } + + return udev_node_apply_permissions_impl(dev, node_fd, devnode, apply_mac, mode, uid, gid, seclabel_list); +} From e5ddfe3ec586c9ab174d39f4b6202155d92d24e4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 6 Apr 2022 02:20:11 +0900 Subject: [PATCH 3/4] udev: upgrade mode in udev_node_apply_permissions_impl() --- src/udev/udev-event.c | 3 --- src/udev/udev-node.c | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index d9af8bfd20..78e8f3018c 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -966,9 +966,6 @@ static int update_devnode(UdevEvent *event) { if (r < 0 && r != -ENOENT) return log_device_error_errno(dev, r, "Failed to get devnode mode: %m"); } - if (event->mode == MODE_INVALID && gid_is_valid(event->gid) && event->gid > 0) - /* If group is set, but mode is not set, "upgrade" mode for the group. */ - event->mode = 0660; bool apply_mac = device_for_action(dev, SD_DEVICE_ADD); diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 83d3242a25..493feffe00 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -610,6 +610,10 @@ static int udev_node_apply_permissions_impl( if (fstat(node_fd, &stats) < 0) return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode); + /* If group is set, but mode is not set, "upgrade" mode for the group. */ + if (mode == MODE_INVALID && gid_is_valid(gid) && gid > 0) + mode = 0660; + apply_mode = mode != MODE_INVALID && (stats.st_mode & 0777) != (mode & 0777); apply_uid = uid_is_valid(uid) && stats.st_uid != uid; apply_gid = gid_is_valid(gid) && stats.st_gid != gid; From 26dd37f6d565dd28d15b3401491589b5a7c86ecb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 6 Apr 2022 02:31:19 +0900 Subject: [PATCH 4/4] udev: move apply_static_dev_perms() to udev-node.c and make it internally use udev_node_apply_permissions_impl(). --- src/udev/udev-node.c | 62 ++++++++++++++++++++++++++++++++++++++ src/udev/udev-node.h | 7 +++++ src/udev/udev-rules.c | 70 ++----------------------------------------- 3 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 493feffe00..deacbc31c5 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -13,6 +13,7 @@ #include "device-private.h" #include "device-util.h" #include "dirent-util.h" +#include "escape.h" #include "fd-util.h" #include "format-util.h" #include "fs-util.h" @@ -718,3 +719,64 @@ int udev_node_apply_permissions( return udev_node_apply_permissions_impl(dev, node_fd, devnode, apply_mac, mode, uid, gid, seclabel_list); } + +int static_node_apply_permissions( + const char *name, + mode_t mode, + uid_t uid, + gid_t gid, + char **tags) { + + _cleanup_free_ char *unescaped_filename = NULL; + _cleanup_close_ int node_fd = -1; + const char *devnode; + struct stat stats; + int r; + + assert(name); + + if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID && !tags) + return 0; + + devnode = strjoina("/dev/", name); + + node_fd = open(devnode, O_PATH|O_CLOEXEC); + if (node_fd < 0) { + if (errno != ENOENT) + return log_error_errno(errno, "Failed to open %s: %m", devnode); + return 0; + } + + if (fstat(node_fd, &stats) < 0) + return log_error_errno(errno, "Failed to stat %s: %m", devnode); + + if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) { + log_warning("%s is neither block nor character device, ignoring.", devnode); + return 0; + } + + if (!strv_isempty(tags)) { + unescaped_filename = xescape(name, "/."); + if (!unescaped_filename) + return log_oom(); + } + + /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */ + STRV_FOREACH(t, tags) { + _cleanup_free_ char *p = NULL; + + p = path_join("/run/udev/static_node-tags/", *t, unescaped_filename); + if (!p) + return log_oom(); + + r = mkdir_parents(p, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create parent directory for %s: %m", p); + + r = symlink(devnode, p); + if (r < 0 && errno != EEXIST) + return log_error_errno(errno, "Failed to create symlink %s -> %s: %m", p, devnode); + } + + return udev_node_apply_permissions_impl(NULL, node_fd, devnode, false, mode, uid, gid, NULL); +} diff --git a/src/udev/udev-node.h b/src/udev/udev-node.h index a34af77146..86a829545a 100644 --- a/src/udev/udev-node.h +++ b/src/udev/udev-node.h @@ -15,6 +15,13 @@ int udev_node_apply_permissions( uid_t uid, gid_t gid, OrderedHashmap *seclabel_list); +int static_node_apply_permissions( + const char *name, + mode_t mode, + uid_t uid, + gid_t gid, + char **tags); + int udev_node_remove(sd_device *dev); int udev_node_update(sd_device *dev, sd_device *dev_old); diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index b46cb0f906..1c20775f08 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -9,7 +9,6 @@ #include "device-private.h" #include "device-util.h" #include "dirent-util.h" -#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "format-util.h" @@ -30,6 +29,7 @@ #include "udev-builtin.h" #include "udev-event.h" #include "udev-netlink.h" +#include "udev-node.h" #include "udev-rules.h" #include "udev-util.h" #include "user-util.h" @@ -2536,72 +2536,6 @@ int udev_rules_apply_to_event( return 0; } -static int apply_static_dev_perms(const char *devnode, uid_t uid, gid_t gid, mode_t mode, char **tags) { - char device_node[UDEV_PATH_SIZE], tags_dir[UDEV_PATH_SIZE], tag_symlink[UDEV_PATH_SIZE]; - _cleanup_free_ char *unescaped_filename = NULL; - struct stat stats; - int r; - - assert(devnode); - - if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID && !tags) - return 0; - - strscpyl(device_node, sizeof(device_node), "/dev/", devnode, NULL); - if (stat(device_node, &stats) < 0) { - if (errno != ENOENT) - return log_error_errno(errno, "Failed to stat %s: %m", device_node); - return 0; - } - - if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) { - log_warning("%s is neither block nor character device, ignoring.", device_node); - return 0; - } - - if (!strv_isempty(tags)) { - unescaped_filename = xescape(devnode, "/."); - if (!unescaped_filename) - return log_oom(); - } - - /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */ - STRV_FOREACH(t, tags) { - strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL); - r = mkdir_p(tags_dir, 0755); - if (r < 0) - return log_error_errno(r, "Failed to create %s: %m", tags_dir); - - strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL); - r = symlink(device_node, tag_symlink); - if (r < 0 && errno != EEXIST) - return log_error_errno(errno, "Failed to create symlink %s -> %s: %m", - tag_symlink, device_node); - } - - /* don't touch the permissions if only the tags were set */ - if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID) - return 0; - - if (mode == MODE_INVALID) - mode = gid_is_valid(gid) ? 0660 : 0600; - if (!uid_is_valid(uid)) - uid = 0; - if (!gid_is_valid(gid)) - gid = 0; - - r = chmod_and_chown(device_node, mode, uid, gid); - if (r == -ENOENT) - return 0; - if (r < 0) - return log_error_errno(r, "Failed to chown '%s' %u %u: %m", device_node, uid, gid); - else - log_debug("chown '%s' %u:%u with mode %#o", device_node, uid, gid, mode); - - (void) utimensat(AT_FDCWD, device_node, NULL, 0); - return 0; -} - static int udev_rule_line_apply_static_dev_perms(UdevRuleLine *rule_line) { _cleanup_strv_free_ char **tags = NULL; uid_t uid = UID_INVALID; @@ -2626,7 +2560,7 @@ static int udev_rule_line_apply_static_dev_perms(UdevRuleLine *rule_line) { if (r < 0) return log_oom(); } else if (token->type == TK_A_OPTIONS_STATIC_NODE) { - r = apply_static_dev_perms(token->value, uid, gid, mode, tags); + r = static_node_apply_permissions(token->value, mode, uid, gid, tags); if (r < 0) return r; }