sd-device: refuse spurious properties

Properties are set through uevent, udev rules, or program output by IMPORT.
They may contain spurious characters and udev database parsers may be confused.
Let's refuse spurious properties.
This commit is contained in:
Yu Watanabe
2026-03-10 06:32:30 +09:00
parent 460b580810
commit a62cd5a153
2 changed files with 71 additions and 0 deletions
+23
View File
@@ -30,6 +30,7 @@
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
#include "utf8.h"
int device_new_aux(sd_device **ret) {
sd_device *device;
@@ -81,12 +82,34 @@ static sd_device* device_free(sd_device *device) {
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device, sd_device, device_free);
static bool property_is_valid(const char *key, const char *value) {
/* Device properties may be saved to database file, then may be parsed from the file. When if a
* property contains spurious characters, then the parser may be confused. Let's refuse spurious
* properties, even if it is internal, which will not be saved to database file, for consistency. */
if (isempty(key) || !in_charset(key, ALPHANUMERICAL "_."))
return false;
/* an empty value means unset the property, hence that's fine. */
if (isempty(value))
return true;
/* refuse invalid UTF8 and control characters */
if (!utf8_is_valid(value) || string_has_cc(value, /* ok= */ NULL))
return false;
return true;
}
int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db) {
OrderedHashmap **properties;
assert(device);
assert(key);
if (!property_is_valid(key, value))
return -EINVAL;
if (db)
properties = &device->properties_db;
else
+48
View File
@@ -841,6 +841,54 @@ TEST(devname_from_devnum) {
}
}
TEST(device_add_property) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
const char *val;
ASSERT_OK(sd_device_new_from_syspath(&dev, "/sys/class/net/lo"));
/* add a property */
ASSERT_OK(device_add_property(dev, "hoge", "foo"));
ASSERT_OK(sd_device_get_property_value(dev, "hoge", &val));
ASSERT_STREQ(val, "foo");
/* update an existing property */
ASSERT_OK(device_add_property(dev, "hoge", "bar"));
ASSERT_OK(sd_device_get_property_value(dev, "hoge", &val));
ASSERT_STREQ(val, "bar");
/* remove an existing property */
ASSERT_OK(device_add_property(dev, "hoge", NULL));
ASSERT_ERROR(sd_device_get_property_value(dev, "hoge", &val), ENOENT);
/* add a property again */
ASSERT_OK(device_add_property(dev, "hoge", "foo"));
ASSERT_OK(sd_device_get_property_value(dev, "hoge", &val));
ASSERT_STREQ(val, "foo");
/* remove it with an empty string */
ASSERT_OK(device_add_property(dev, "hoge", ""));
ASSERT_ERROR(sd_device_get_property_value(dev, "hoge", &val), ENOENT);
/* check internal property (starting with dot) */
ASSERT_OK(device_add_property(dev, ".hoge", "baz"));
ASSERT_OK(sd_device_get_property_value(dev, ".hoge", &val));
ASSERT_STREQ(val, "baz");
/* refuse invalid property names */
ASSERT_ERROR(device_add_property(dev, "hoge-hoge", "aaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge=hoge", "aaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge hoge", "aaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge\nhoge", "aaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge\rhoge", "aaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge\thoge", "aaa"), EINVAL);
/* refuse invalid property values */
ASSERT_ERROR(device_add_property(dev, "hoge", "aaa\naaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge", "aaa\raaa"), EINVAL);
ASSERT_ERROR(device_add_property(dev, "hoge", "aaa\taaa"), EINVAL);
}
static int intro(void) {
int r;