From: Yu Watanabe Date: Fri, 6 Jun 2025 12:14:20 +0000 (+0900) Subject: sd-device: replace '!' with '/' before calling sd_device_new_from_subsystem_sysname() X-Git-Tag: v258-rc1~366 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=687a92a1b6a62b705acbb9065bb60fc6e84c9c20;p=thirdparty%2Fsystemd.git sd-device: replace '!' with '/' before calling sd_device_new_from_subsystem_sysname() Device ID uses device directory name as is, hence may contain '!', but sd_device_new_from_subsystem_sysname() expects that the input is sysname. So, we need to replace '!' with '/'. Follow-up for 1393c5a2a42d6ff16afcdc3ac39f007921b9cb57. Fixes #37711. --- diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index aef02350ccd..850eff9d028 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -922,15 +922,24 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { } case '+': { - const char *subsys, *sep; - - sep = strchr(id + 1, ':'); - if (!sep || sep - id - 1 > NAME_MAX) + const char *sep = strchr(id + 1, ':'); + if (!sep || sep[1] == '\0') return -EINVAL; - subsys = memdupa_suffix0(id + 1, sep - id - 1); + _cleanup_free_ char *subsystem = strndup(id + 1, sep - id - 1); + if (!subsystem) + return -ENOMEM; + + _cleanup_free_ char *sysname = strdup(sep + 1); + if (!sysname) + return -ENOMEM; + + /* Device ID uses device directory name as is, hence may contain '!', but + * sd_device_new_from_subsystem_sysname() expects that the input is sysname, + * that is, '!' must be replaced with '/'. */ + string_replace_char(sysname, '!', '/'); - return sd_device_new_from_subsystem_sysname(ret, subsys, sep + 1); + return sd_device_new_from_subsystem_sysname(ret, subsystem, sysname); } default: diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index 4173f76dd81..ceff4ed2b21 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -10,10 +10,14 @@ #include "device-util.h" #include "errno-util.h" #include "fd-util.h" +#include "fs-util.h" #include "hashmap.h" +#include "mkdir.h" +#include "mount-util.h" #include "mountpoint-util.h" #include "nulstr-util.h" #include "path-util.h" +#include "process-util.h" #include "rm-rf.h" #include "set.h" #include "stat-util.h" @@ -22,6 +26,62 @@ #include "tmpfile-util.h" #include "udev-util.h" +TEST(mdio_bus) { + int r; + + /* For issue #37711 */ + + if (getuid() != 0) + return (void) log_tests_skipped("not running as root"); + + ASSERT_OK(r = safe_fork("(mdio_bus)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_WAIT|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL)); + if (r == 0) { + const char *syspath = "/sys/bus/mdio_bus/drivers/Qualcomm Atheros AR8031!AR8033"; + const char *id = "+drivers:mdio_bus:Qualcomm Atheros AR8031!AR8033"; + + struct { + int (*getter)(sd_device*, const char**); + const char *val; + } table[] = { + { sd_device_get_syspath, syspath }, + { sd_device_get_device_id, id }, + { sd_device_get_subsystem, "drivers" }, + { sd_device_get_driver_subsystem, "mdio_bus" }, + { sd_device_get_sysname, "Qualcomm Atheros AR8031/AR8033" }, + }; + + ASSERT_OK_ERRNO(setenv("SYSTEMD_DEVICE_VERIFY_SYSFS", "0", /* overwrite = */ false)); + ASSERT_OK(mount_nofollow_verbose(LOG_ERR, "tmpfs", "/sys/bus/", "tmpfs", 0, NULL)); + ASSERT_OK(mkdir_p(syspath, 0755)); + + _cleanup_free_ char *uevent = path_join(syspath, "uevent"); + ASSERT_NOT_NULL(uevent); + ASSERT_OK(touch(uevent)); + + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + ASSERT_OK(sd_device_new_from_syspath(&dev, syspath)); + + FOREACH_ELEMENT(t, table) { + const char *v; + + ASSERT_OK(t->getter(dev, &v)); + ASSERT_STREQ(v, t->val); + } + + dev = sd_device_unref(dev); + ASSERT_OK(sd_device_new_from_device_id(&dev, id)); + + FOREACH_ELEMENT(t, table) { + const char *v; + + ASSERT_OK(t->getter(dev, &v)); + ASSERT_STREQ(v, t->val); + } + + _exit(EXIT_SUCCESS); + } +} + static void test_sd_device_one(sd_device *d) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; const char *syspath, *sysname, *subsystem = NULL, *devname, *val;