mirror of
https://github.com/systemd/systemd
synced 2026-04-25 16:34:50 +02:00
Compare commits
No commits in common. "8dc3c2f197370e2a63dce6ab03d48eba85c4ffdf" and "bab34bc12e8f3802516497cee2b419b197e728ab" have entirely different histories.
8dc3c2f197
...
bab34bc12e
@ -21,7 +21,7 @@ UBUNTU_RELEASE="$(lsb_release -cs)"
|
||||
create_container() {
|
||||
# Create autopkgtest LXC image; this sometimes fails with "Unable to fetch
|
||||
# GPG key from keyserver", so retry a few times with different keyservers.
|
||||
for keyserver in "keys.openpgp.org" "" "keyserver.ubuntu.com" "keys.gnupg.net"; do
|
||||
for keyserver in "" "keys.gnupg.net" "keys.openpgp.org" "keyserver.ubuntu.com"; do
|
||||
for retry in {1..5}; do
|
||||
sudo lxc-create -n "$CONTAINER" -t download -- -d "$DISTRO" -r "$RELEASE" -a "$ARCH" ${keyserver:+--keyserver "$keyserver"} && break 2
|
||||
sleep $((retry*retry))
|
||||
@ -36,16 +36,8 @@ create_container() {
|
||||
# enable source repositories so that apt-get build-dep works
|
||||
sudo lxc-attach -n "$CONTAINER" -- sh -ex <<EOF
|
||||
sed 's/^deb/deb-src/' /etc/apt/sources.list >> /etc/apt/sources.list.d/sources.list
|
||||
# We might attach the console too soon
|
||||
while ! systemctl --quiet --wait is-system-running; do sleep 1; done
|
||||
# Manpages database trigger takes a lot of time and is not useful in a CI
|
||||
echo 'man-db man-db/auto-update boolean false' | debconf-set-selections
|
||||
# Speed up dpkg, image is thrown away after the test
|
||||
mkdir -p /etc/dpkg/dpkg.cfg.d/
|
||||
echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/unsafe_io
|
||||
# For some reason, it is necessary to run this manually or the interface won't be configured
|
||||
# Note that we avoid networkd, as some of the tests will break it later on
|
||||
dhclient
|
||||
# wait until online
|
||||
while [ -z "\$(ip route list 0/0)" ]; do sleep 1; done
|
||||
apt-get -q --allow-releaseinfo-change update
|
||||
apt-get -y dist-upgrade
|
||||
apt-get install -y eatmydata
|
||||
@ -96,10 +88,6 @@ EOF
|
||||
rm -rf debian/patches
|
||||
# disable autopkgtests which are not for upstream
|
||||
sed -i '/# NOUPSTREAM/ q' debian/tests/control
|
||||
# TODO: rebooting via autopkgtest-reboot seems to be broken, disable these tests for now
|
||||
sed -i -n '1,/Tests: boot-and-services/p;/Tests: udev/,$p' debian/tests/control
|
||||
sed -i '/Tests: boot-and-services/d' debian/tests/control
|
||||
sed -i '/Tests: boot-smoke/,$d' debian/tests/control
|
||||
# enable more unit tests
|
||||
sed -i '/^CONFFLAGS =/ s/=/= --werror -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true -Dfuzz-tests=true -Dman=true /' debian/rules
|
||||
# no orig tarball
|
||||
|
||||
@ -7,7 +7,7 @@ name: Debian autopkgtest (LXC)
|
||||
agent:
|
||||
machine:
|
||||
type: e1-standard-2
|
||||
os_image: ubuntu2004
|
||||
os_image: ubuntu1804
|
||||
|
||||
# Cancel any running or queued job for the same ref
|
||||
auto_cancel:
|
||||
|
||||
56
README
56
README
@ -30,21 +30,14 @@ LICENSE:
|
||||
LGPL-2.1-or-later for all code, exceptions noted in LICENSES/README.md
|
||||
|
||||
REQUIREMENTS:
|
||||
Linux kernel ≥ 3.15
|
||||
≥ 4.5 for pids controller in cgroup v2
|
||||
≥ 4.6 for cgroup namespaces
|
||||
≥ 4.9 for RENAME_NOREPLACE support in vfat
|
||||
≥ 4.10 for cgroup-bpf egress and ingress hooks
|
||||
≥ 4.15 for cgroup-bpf device hook and cpu controller in cgroup v2
|
||||
≥ 4.17 for cgroup-bpf socket address hooks
|
||||
≥ 5.3 for bounded loops in BPF program
|
||||
≥ 5.4 for signed Verity images
|
||||
≥ 5.7 for BPF links and the BPF LSM hook
|
||||
|
||||
Kernel versions below 4.15 have significant gaps in functionality and
|
||||
are not recommended for use with this version of systemd. Taint flag
|
||||
'old-kernel' will be set. Systemd will most likely still function, but
|
||||
upstream support and testing are limited.
|
||||
Linux kernel >= 3.15
|
||||
Linux kernel >= 4.2 for unified cgroup hierarchy support
|
||||
Linux kernel >= 4.10 for cgroup-bpf egress and ingress hooks
|
||||
Linux kernel >= 4.15 for cgroup-bpf device hook
|
||||
Linux kernel >= 4.17 for cgroup-bpf socket address hooks
|
||||
Linux kernel >= 5.3 for bounded-loops in BPF program
|
||||
Linux kernel >= 5.4 for signed Verity images support
|
||||
Linux kernel >= 5.7 for BPF links and the BPF LSM hook
|
||||
|
||||
Kernel Config Options:
|
||||
CONFIG_DEVTMPFS
|
||||
@ -337,41 +330,24 @@ SYSV INIT.D SCRIPTS:
|
||||
Please see src/systemctl/systemd-sysv-install.SKELETON for how this
|
||||
needs to look like, and provide an implementation at the marked places.
|
||||
|
||||
WARNINGS and TAINT FLAGS:
|
||||
WARNINGS:
|
||||
systemd will warn during early boot if /usr is not already mounted at
|
||||
this point (that means: either located on the same file system as / or
|
||||
already mounted in the initrd). While in systemd itself very little
|
||||
will break if /usr is on a separate late-mounted partition, many of its
|
||||
dependencies very likely will break sooner or later in one form or
|
||||
will break if /usr is on a separate, late-mounted partition, many of
|
||||
its dependencies very likely will break sooner or later in one form or
|
||||
another. For example, udev rules tend to refer to binaries in /usr,
|
||||
binaries that link to libraries in /usr or binaries that refer to data
|
||||
files in /usr. Since these breakages are not always directly visible,
|
||||
systemd will warn about this. Such setups are not really supported by
|
||||
the basic set of Linux OS components. Taint flag 'split-usr' will be
|
||||
set when this condition is detected.
|
||||
systemd will warn about this, since this kind of file system setup is
|
||||
not really supported anymore by the basic set of Linux OS components.
|
||||
|
||||
systemd requires that the /run mount point exists. systemd also
|
||||
requires that /var/run is a symlink to /run.
|
||||
|
||||
For more information on this issue consult
|
||||
https://www.freedesktop.org/wiki/Software/systemd/separate-usr-is-broken
|
||||
|
||||
systemd requires that the /run mount point exists. systemd also
|
||||
requires that /var/run is a symlink to /run. Taint flag 'var-run-bad'
|
||||
will be set when this condition is detected.
|
||||
|
||||
Systemd will also warn when the cgroup support is unavailable in the
|
||||
kernel (taint flag 'cgroups-missing'), the system is using the old
|
||||
cgroup hierarchy (taint flag 'cgroupsv1'), the hardware clock is
|
||||
running in non-UTC mode (taint flag 'local-hwclock'), the kernel
|
||||
overflow UID or GID are not 65534 (taint flags 'overflowuid-not-65534'
|
||||
and 'overflowgid-not-65534'), the UID or GID range assigned to the
|
||||
running systemd instance covers less than 0…65534 (taint flags
|
||||
'short-uid-range' and 'short-gid-range').
|
||||
|
||||
Taint conditions are logged during boot, but may also be checked at any
|
||||
time with:
|
||||
|
||||
busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager Tainted
|
||||
|
||||
VALGRIND:
|
||||
To run systemd under valgrind, compile with meson option
|
||||
-Dvalgrind=true and have valgrind development headers installed
|
||||
(i.e. valgrind-devel or equivalent). Otherwise, false positives will be
|
||||
|
||||
@ -403,18 +403,6 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>v251</constant></term>
|
||||
|
||||
<listitem><para>Since version <constant>v247</constant> we no longer set
|
||||
<varname>ID_NET_NAME_SLOT</varname> if we detect that a PCI device associated with a slot is a PCI
|
||||
bridge as that would create naming conflict when there are more child devices on that bridge. Now,
|
||||
this is relaxed and we will use slot information to generate the name based on it but only if
|
||||
the PCI device has multiple functions. This is safe because distinct function number is a part of
|
||||
the device name for multifunction devices.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
|
||||
|
||||
@ -74,4 +74,4 @@
|
||||
/* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.system.ManagedOOM"
|
||||
|
||||
#define KERNEL_BASELINE_VERSION "4.15"
|
||||
#define KERNEL_BASELINE_VERSION "3.15"
|
||||
|
||||
@ -4384,7 +4384,7 @@ char *manager_taint_string(Manager *m) {
|
||||
|
||||
buf = new(char, sizeof("split-usr:"
|
||||
"cgroups-missing:"
|
||||
"cgroupsv1:"
|
||||
"cgrousv1:"
|
||||
"local-hwclock:"
|
||||
"var-run-bad:"
|
||||
"overflowuid-not-65534:"
|
||||
|
||||
@ -23,7 +23,6 @@ static const NamingScheme naming_schemes[] = {
|
||||
{ "v247", NAMING_V247 },
|
||||
{ "v249", NAMING_V249 },
|
||||
{ "v250", NAMING_V250 },
|
||||
{ "v251", NAMING_V251 },
|
||||
/* … add more schemes here, as the logic to name devices is updated … */
|
||||
|
||||
EXTRA_NET_NAMING_MAP
|
||||
|
||||
@ -22,21 +22,20 @@
|
||||
* OS versions, but not fully stabilize them. */
|
||||
typedef enum NamingSchemeFlags {
|
||||
/* First, the individual features */
|
||||
NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a */
|
||||
NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6ea */
|
||||
NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df */
|
||||
NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Use zero acpi_index field, see d81186ef4f6a */
|
||||
NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */
|
||||
NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
|
||||
NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
|
||||
NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
|
||||
NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */
|
||||
NAMING_BRIDGE_NO_SLOT = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */
|
||||
NAMING_SLOT_FUNCTION_ID = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */
|
||||
NAMING_16BIT_INDEX = 1 << 11, /* Allow full 16-bit for the onboard index */
|
||||
NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
|
||||
NAMING_XEN_VIF = 1 << 13, /* Generate names for Xen netfront devices */
|
||||
NAMING_BRIDGE_MULTIFUNCTION_SLOT = 1 << 14, /* Use PCI hotplug slot information associated with bridge, but only if PCI device is multifunction */
|
||||
NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a */
|
||||
NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6ea */
|
||||
NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df */
|
||||
NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Use zero acpi_index field, see d81186ef4f6a */
|
||||
NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */
|
||||
NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
|
||||
NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
|
||||
NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
|
||||
NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */
|
||||
NAMING_BRIDGE_NO_SLOT = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */
|
||||
NAMING_SLOT_FUNCTION_ID = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */
|
||||
NAMING_16BIT_INDEX = 1 << 11, /* Allow full 16-bit for the onboard index */
|
||||
NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
|
||||
NAMING_XEN_VIF = 1 << 13, /* GEnerate names for Xen netfront devices */
|
||||
|
||||
/* And now the masks that combine the features above */
|
||||
NAMING_V238 = 0,
|
||||
@ -48,7 +47,6 @@ typedef enum NamingSchemeFlags {
|
||||
NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT,
|
||||
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
|
||||
NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
|
||||
NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
|
||||
|
||||
EXTRA_NET_NAMING_SCHEMES
|
||||
|
||||
|
||||
@ -451,15 +451,8 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
|
||||
* devices that will try to claim the same index and that would create name
|
||||
* collision. */
|
||||
if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) {
|
||||
if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && !is_pci_multifunction(names->pcidev)) {
|
||||
log_device_debug(dev, "Not using slot information because the PCI device associated with the hotplug slot is a bridge and the PCI device has single function.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) {
|
||||
log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
|
||||
return 0;
|
||||
}
|
||||
log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -966,6 +966,9 @@ 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,7 +13,6 @@
|
||||
#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"
|
||||
@ -591,30 +590,51 @@ int udev_node_remove(sd_device *dev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udev_node_apply_permissions_impl(
|
||||
sd_device *dev, /* can be NULL, only used for logging. */
|
||||
int node_fd,
|
||||
const char *devnode,
|
||||
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, *subsystem;
|
||||
bool apply_mode, apply_uid, apply_gid;
|
||||
_cleanup_close_ int node_fd = -1;
|
||||
struct stat stats;
|
||||
dev_t devnum;
|
||||
int r;
|
||||
|
||||
assert(node_fd >= 0);
|
||||
assert(devnode);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
@ -688,95 +708,3 @@ static int udev_node_apply_permissions_impl(
|
||||
|
||||
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,13 +15,6 @@ 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,6 +9,7 @@
|
||||
#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"
|
||||
@ -29,7 +30,6 @@
|
||||
#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,6 +2536,72 @@ 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;
|
||||
@ -2560,7 +2626,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 = static_node_apply_permissions(token->value, mode, uid, gid, tags);
|
||||
r = apply_static_dev_perms(token->value, uid, gid, mode, tags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -144,7 +144,6 @@ static int find_devno(
|
||||
const char *device,
|
||||
bool backing) {
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
dev_t devt, whole_devt;
|
||||
struct stat st;
|
||||
int r;
|
||||
@ -154,11 +153,7 @@ static int find_devno(
|
||||
assert(*devnos || *n_devnos == 0);
|
||||
assert(device);
|
||||
|
||||
fd = open(device, O_CLOEXEC|O_PATH);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open '%s': %m", device);
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
if (stat(device, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat '%s': %m", device);
|
||||
|
||||
if (S_ISBLK(st.st_mode))
|
||||
@ -171,13 +166,20 @@ static int find_devno(
|
||||
devt = st.st_dev;
|
||||
else {
|
||||
_cleanup_close_ int regfd = -1;
|
||||
struct stat st2;
|
||||
|
||||
/* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
|
||||
* handing, to get the backing device node. */
|
||||
|
||||
regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
||||
regfd = open(device, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
|
||||
if (regfd < 0)
|
||||
return log_error_errno(regfd, "Failed to open '%s': %m", device);
|
||||
return log_error_errno(errno, "Failed to open '%s': %m", device);
|
||||
|
||||
/* Extra safety: let's check we are still looking at the same file */
|
||||
if (fstat(regfd, &st2) < 0)
|
||||
return log_error_errno(errno, "Failed to stat '%s': %m", device);
|
||||
if (!stat_inode_same(&st, &st2))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "File '%s' was replaced while we were looking at it.", device);
|
||||
|
||||
r = btrfs_get_block_device_fd(regfd, &devt);
|
||||
if (r == -ENOTTY)
|
||||
|
||||
@ -1711,7 +1711,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
||||
'25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
|
||||
'25-veth.netdev', '25-ip6tnl-slaac.network', '25-ipv6-prefix.network',
|
||||
'25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network',
|
||||
'25-ip6tnl-tunnel-external.netdev', '26-netdev-link-local-addressing-yes.network')
|
||||
'25-ip6tnl-external.netdev', '26-netdev-link-local-addressing-yes.network')
|
||||
start_networkd()
|
||||
self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable',
|
||||
'ip6tnl-slaac:degraded', 'ip6tnl-external:degraded',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user