191 lines
8.1 KiB
Diff
191 lines
8.1 KiB
Diff
From 9962f072342f8b5c5c49c09a6792d5b67ed4fdad Mon Sep 17 00:00:00 2001
|
|
From: Lennart Poettering <lennart@poettering.net>
|
|
Date: Mon, 10 May 2021 16:41:46 +0200
|
|
Subject: [PATCH] sd-device: use strjoina() more again in
|
|
sd_device_new_from_subsystem_sysname()
|
|
|
|
This reverts a major part of: e17c95af8e450caacde692875b30675cea75211f
|
|
|
|
Using format strings for concatenating strings is pretty unefficient,
|
|
and using PATH_MAX buffers unpretty as well. Let's revert to using
|
|
strjoina() as before.
|
|
|
|
However, to fix the fuzz issue at hand, let's explicitly verify the two
|
|
input strings ensuring they are valid path names. This includes a length
|
|
check (to 2K each), thus making things prettier, faster and using less
|
|
memory again.
|
|
|
|
(cherry picked from commit f5e775973a22e10e0813b56cb3e43d5d415979f7)
|
|
|
|
Conflict:function test_util_resolve_subsys_kernel_one() is not in 0test-udev-util.c, but in test-libudev.c
|
|
Reference:https://github.com/systemd/systemd-stable/commit/9962f072342f8b5c5c49c09a6792d5b67ed4fdad
|
|
---
|
|
src/libsystemd/sd-device/sd-device.c | 112 +++++++++++++++++----------
|
|
src/test/test-udev-util.c | 2 +-
|
|
2 files changed, 73 insertions(+), 41 deletions(-)
|
|
|
|
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
|
|
index d82f01a164..d92410d2d0 100644
|
|
--- a/src/libsystemd/sd-device/sd-device.c
|
|
+++ b/src/libsystemd/sd-device/sd-device.c
|
|
@@ -244,71 +244,103 @@ _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum)
|
|
return sd_device_new_from_syspath(ret, syspath);
|
|
}
|
|
|
|
-_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
|
|
- char syspath[PATH_MAX], *name;
|
|
+static int device_strjoin_new(
|
|
+ const char *a,
|
|
+ const char *b,
|
|
+ const char *c,
|
|
+ const char *d,
|
|
+ sd_device **ret) {
|
|
+
|
|
+ const char *p;
|
|
+ int r;
|
|
+
|
|
+ p = strjoina(a, b, c, d);
|
|
+ if (access(p, F_OK) < 0)
|
|
+ return IN_SET(errno, ENOENT, ENAMETOOLONG) ? 0 : -errno; /* If this sysfs is too long then it doesn't exist either */
|
|
+
|
|
+ r = sd_device_new_from_syspath(ret, p);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+_public_ int sd_device_new_from_subsystem_sysname(
|
|
+ sd_device **ret,
|
|
+ const char *subsystem,
|
|
+ const char *sysname) {
|
|
+
|
|
+ const char *s;
|
|
+ char *name;
|
|
+ int r;
|
|
|
|
assert_return(ret, -EINVAL);
|
|
- assert_return(subsystem, -EINVAL);
|
|
- assert_return(sysname, -EINVAL);
|
|
- assert_return(strlen(sysname) < PATH_MAX - strlen("/sys/bus/"), -ENAMETOOLONG);
|
|
+ assert_return(path_is_normalized(subsystem), -EINVAL);
|
|
+ assert_return(path_is_normalized(sysname), -EINVAL);
|
|
|
|
if (streq(subsystem, "subsystem")) {
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/subsystem/%s", sysname) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
-
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/bus/%s", sysname) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/class/%s", sysname) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+ FOREACH_STRING(s, "/sys/subsystem/", "/sys/bus/", "/sys/class/") {
|
|
+ r = device_strjoin_new(s, sysname, NULL, NULL, ret);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ if (r > 0)
|
|
+ return 0;
|
|
+ }
|
|
|
|
} else if (streq(subsystem, "module")) {
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/module/%s", sysname) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+
|
|
+ r = device_strjoin_new("/sys/module/", sysname, NULL, NULL, ret);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ if (r > 0)
|
|
+ return 0;
|
|
|
|
} else if (streq(subsystem, "drivers")) {
|
|
- const char *subsys, *sep;
|
|
+ const char *sep;
|
|
|
|
sep = strchr(sysname, ':');
|
|
if (sep && sep[1] != '\0') { /* Require ":" and something non-empty after that. */
|
|
- subsys = memdupa_suffix0(sysname, sep - sysname);
|
|
+ const char *subsys;
|
|
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/subsystem/%s/drivers/%s", subsys, sep + 1) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+ subsys = memdupa_suffix0(sysname, sep - sysname);
|
|
+ sep++;
|
|
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/bus/%s/drivers/%s", subsys, sep + 1) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+ FOREACH_STRING(s, "/sys/subsystem/", "/sys/bus/") {
|
|
+ r = device_strjoin_new(s, subsys, "/drivers/", sep, ret);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ if (r > 0)
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
/* translate sysname back to sysfs filename */
|
|
name = strdupa(sysname);
|
|
-
|
|
for (size_t i = 0; name[i]; i++)
|
|
if (name[i] == '/')
|
|
name[i] = '!';
|
|
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/subsystem/%s/devices/%s", subsystem, name) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
-
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/bus/%s/devices/%s", subsystem, name) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+ FOREACH_STRING(s, "/sys/subsystem/", "/sys/bus/") {
|
|
+ r = device_strjoin_new(s, subsystem, "/devices/", name, ret);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ if (r > 0)
|
|
+ return 0;
|
|
+ }
|
|
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/class/%s/%s", subsystem, name) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+ r = device_strjoin_new("/sys/class/", subsystem, "/", name, ret);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ if (r > 0)
|
|
+ return 0;
|
|
|
|
- if (snprintf_ok(syspath, sizeof syspath, "/sys/firmware/%s/%s", subsystem, sysname) &&
|
|
- access(syspath, F_OK) >= 0)
|
|
- return sd_device_new_from_syspath(ret, syspath);
|
|
+ r = device_strjoin_new("/sys/firmware/", subsystem, "/", sysname, ret);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ if (r > 0)
|
|
+ return 0;
|
|
|
|
return -ENODEV;
|
|
}
|
|
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
|
|
index dcb5bcc..c423ace 100644
|
|
--- a/src/test/test-libudev.c
|
|
+++ b/src/test/test-libudev.c
|
|
@@ -417,7 +417,7 @@ static void test_util_resolve_subsys_kernel(void) {
|
|
test_util_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL);
|
|
test_util_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL);
|
|
test_util_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL);
|
|
- test_util_resolve_subsys_kernel_one("[hoge/]", false, -ENODEV, NULL);
|
|
+ test_util_resolve_subsys_kernel_one("[hoge/]", false, -EINVAL, NULL);
|
|
|
|
test_util_resolve_subsys_kernel_one("[net/lo]", false, 0, "/sys/devices/virtual/net/lo");
|
|
test_util_resolve_subsys_kernel_one("[net/lo]/", false, 0, "/sys/devices/virtual/net/lo");
|
|
--
|
|
2.27.0
|
|
|