]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-device: replace '!' with '/' before calling sd_device_new_from_subsystem_sysname()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 6 Jun 2025 12:14:20 +0000 (21:14 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 25 Jun 2025 12:36:10 +0000 (13:36 +0100)
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.

(cherry picked from commit 687a92a1b6a62b705acbb9065bb60fc6e84c9c20)

src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-sd-device.c

index 2373f1a4f2cea6abf63987b650c143c3923b8afe..f65e947415d50ffb7c606db989dc92ea9192191d 100644 (file)
@@ -914,15 +914,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:
index aa235cf8d008e4b8f66520b5cb32d249065eb4b9..f9bd37b5cff45ef33b232cb571d42766e1c69c8b 100644 (file)
 #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 "stat-util.h"
 #include "string-util.h"
 #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;