1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-23 17:34:00 +03:00

Merge pull request #19312 from yuwata/udev-escape-slash-nvme

udev: make OPTIONS="string_escape=replace" take effect on ENV{key}= assiginment
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-06-25 10:11:04 +02:00 committed by GitHub
commit 157306439e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 74 additions and 27 deletions

View File

@ -117,7 +117,7 @@
<varlistentry>
<term><literal>:=</literal></term>
<listitem>
<para>Assign a value to a key finally; disallow any later changes.</para>
<para>Assign a value to a key finally; disallow any later changes.</para>
</listitem>
</varlistentry>
</variablelist>
@ -607,9 +607,12 @@
<varlistentry>
<term><option>string_escape=<replaceable>none|replace</replaceable></option></term>
<listitem>
<para>Usually, control and other possibly unsafe characters are replaced
in strings used for device naming. The mode of replacement can be specified
with this option.</para>
<para>When <literal>replace</literal>, possibly unsafe characters in strings
assigned to <varname>NAME</varname>, <varname>SYMLINK</varname>, and
<varname>ENV{<replaceable>key</replaceable>}</varname> are replaced. When
<literal>none</literal>, no replacement is performed. When unset, the replacement
is performed for <varname>NAME</varname>, <varname>SYMLINK</varname>, but not for
<varname>ENV{<replaceable>key</replaceable>}</varname>. Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -38,13 +38,13 @@ KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{wwid}=="?*", ENV{ID_WWN
KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_MODEL}="$attr{model}"
KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{firmware_rev}=="?*", ENV{ID_REVISION}="$attr{firmware_rev}"
KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", \
ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}"
OPTIONS="string_escape=replace", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}"
KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}"
KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_MODEL}="$attr{model}"
KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{firmware_rev}=="?*", ENV{ID_REVISION}="$attr{firmware_rev}"
KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", \
ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n"
OPTIONS="string_escape=replace", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n"
# virtio-blk
KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"

View File

@ -748,6 +748,22 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
bool ifname_valid_char(char a) {
if ((unsigned char) a >= 127U)
return false;
if ((unsigned char) a <= 32U)
return false;
if (IN_SET(a,
':', /* colons are used by the legacy "alias" interface logic */
'/', /* slashes cannot work, since we need to use network interfaces in sysfs paths, and in paths slashes are separators */
'%')) /* %d is used in the kernel's weird foo%d format string naming feature which we really really don't want to ever run into by accident */
return false;
return true;
}
bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
bool numeric = true;
@ -781,16 +797,7 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
return false;
for (const char *t = p; *t; t++) {
if ((unsigned char) *t >= 127U)
return false;
if ((unsigned char) *t <= 32U)
return false;
if (IN_SET(*t,
':', /* colons are used by the legacy "alias" interface logic */
'/', /* slashes cannot work, since we need to use network interfaces in sysfs paths, and in paths slashes are separators */
'%')) /* %d is used in the kernel's weird foo%d format string naming feature which we really really don't want to ever run into by accident */
if (!ifname_valid_char(*t))
return false;
numeric = numeric && (*t >= '0' && *t <= '9');

View File

@ -139,6 +139,7 @@ typedef enum {
IFNAME_VALID_NUMERIC = 1 << 1,
_IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
} IfnameValidFlags;
bool ifname_valid_char(char a);
bool ifname_valid_full(const char *p, IfnameValidFlags flags);
static inline bool ifname_valid(const char *p) {
return ifname_valid_full(p, 0);

View File

@ -34,6 +34,7 @@ typedef enum NamingSchemeFlags {
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 */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
@ -43,7 +44,7 @@ typedef enum NamingSchemeFlags {
NAMING_V243 = NAMING_V241 | NAMING_NETDEVSIM | NAMING_LABEL_NOPREFIX,
NAMING_V245 = NAMING_V243 | NAMING_NSPAWN_LONG_HASH,
NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT,
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX,
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
_NAMING_SCHEME_FLAGS_INVALID = -EINVAL,
} NamingSchemeFlags;

View File

@ -18,6 +18,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "signal-util.h"
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strxcpyx.h"
@ -436,6 +437,22 @@ size_t udev_replace_whitespace(const char *str, char *to, size_t len) {
return j;
}
size_t udev_replace_ifname(char *str) {
size_t replaced = 0;
assert(str);
/* See ifname_valid_full(). */
for (char *p = str; *p != '\0'; p++)
if (!ifname_valid_char(*p)) {
*p = '_';
replaced++;
}
return replaced;
}
size_t udev_replace_chars(char *str, const char *allow) {
size_t i = 0, replaced = 0;

View File

@ -46,6 +46,7 @@ void log_device_uevent(sd_device *device, const char *str);
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos);
size_t udev_replace_whitespace(const char *str, char *to, size_t len);
size_t udev_replace_ifname(char *str);
size_t udev_replace_chars(char *str, const char *allow);
int udev_resolve_subsys_kernel(const char *string, char *result, size_t maxsize, bool read_value);

View File

@ -17,6 +17,7 @@
#include "fd-util.h"
#include "fs-util.h"
#include "format-util.h"
#include "netif-naming-scheme.h"
#include "netlink-util.h"
#include "parse-util.h"
#include "path-util.h"
@ -848,6 +849,12 @@ static int rename_netif(UdevEvent *event) {
if (r < 0)
return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
if (naming_scheme_has(NAMING_REPLACE_STRICTLY) &&
!ifname_valid(event->name)) {
log_device_warning(dev, "Invalid network interface name, ignoring: %s", event->name);
return 0;
}
/* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */
r = device_add_property(dev, "ID_RENAMING", "1");
if (r < 0)

View File

@ -17,6 +17,7 @@
#include "glob-util.h"
#include "list.h"
#include "mkdir.h"
#include "netif-naming-scheme.h"
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
@ -2023,6 +2024,12 @@ static int udev_rule_apply_token_to_event(
l = strpcpyl(&p, l, val, " ", NULL);
(void) udev_event_apply_format(event, token->value, p, l, false);
if (event->esc == ESCAPE_REPLACE) {
count = udev_replace_chars(buf, NULL);
if (count > 0)
log_rule_debug(dev, rules, "Replaced %zu slash(es) from result of ENV{%s}%s=\"%s\"",
count, name, token->op == OP_ADD ? "+" : "", token->value);
}
r = device_add_property(dev, name, value_new);
if (r < 0)
@ -2053,21 +2060,23 @@ static int udev_rule_apply_token_to_event(
if (token->op == OP_ASSIGN_FINAL)
event->name_final = true;
if (sd_device_get_ifindex(dev, NULL) < 0) {
log_rule_error(dev, rules,
"Only network interface can be renamed, ignoring NAME=\"%s\"; please fix it.",
token->value);
break;
}
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
if (IN_SET(event->esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
count = udev_replace_chars(buf, "/");
if (naming_scheme_has(NAMING_REPLACE_STRICTLY))
count = udev_replace_ifname(buf);
else
count = udev_replace_chars(buf, "/");
if (count > 0)
log_rule_debug(dev, rules, "Replaced %zu character(s) from result of NAME=\"%s\"",
count, token->value);
}
if (sd_device_get_devnum(dev, NULL) >= 0 &&
(sd_device_get_devname(dev, &val) < 0 ||
!streq_ptr(buf, path_startswith(val, "/dev/")))) {
log_rule_error(dev, rules,
"Kernel device nodes cannot be renamed, ignoring NAME=\"%s\"; please fix it.",
token->value);
break;
}
r = free_and_strdup_warn(&event->name, buf);
if (r < 0)
return r;
@ -2096,7 +2105,8 @@ static int udev_rule_apply_token_to_event(
else
count = 0;
if (count > 0)
log_rule_debug(dev, rules, "Replaced %zu character(s) from result of LINK", count);
log_rule_debug(dev, rules, "Replaced %zu character(s) from result of SYMLINK=\"%s\"",
count, token->value);
p = skip_leading_chars(buf, NULL);
while (!isempty(p)) {