mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-24 21:34:08 +03:00
Merge pull request #22981 from yuwata/udev-node-cleanups
udev: cleanups for device node handling
This commit is contained in:
commit
8dc3c2f197
@ -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);
|
||||
|
||||
|
@ -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"
|
||||
@ -590,51 +591,30 @@ 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, *subsystem;
|
||||
bool apply_mode, apply_uid, apply_gid;
|
||||
_cleanup_close_ int node_fd = -1;
|
||||
struct stat stats;
|
||||
dev_t devnum;
|
||||
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");
|
||||
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) {
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
@ -708,3 +688,95 @@ 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user