summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@strace.io>2023-03-16 08:00:00 +0000
committerDmitry V. Levin <ldv@strace.io>2023-03-19 11:32:09 +0000
commitc43ff248f94266cfc93e300a2d3d163ed805e55b (patch)
tree3e16f57b582bdab32f1342f9de53bf2851c09ba4 /src
parent432f1fa8c745cae452d69530642b1e9ec557d58a (diff)
downloadsystemd-c43ff248f94266cfc93e300a2d3d163ed805e55b.tar.gz
udev-rules: fix matching of token types that support alternative patterns
For those token types that support matching of alternative patterns, their token values are interpreted as nulstr, so make sure the parser does the right thing and makes these token values terminated by two subsequent NULs so they could be safely interpreted as nulstr. Before this fix, the following rules would result to "echo foo" invocation: ENV{foo}=", RUN" ENV{foo}=="bar", RUN+="echo foo" because the value of `ENV{foo}` is treated as nulstr, and it used to match against alternative patterns, in this case `bar`, `, RUN`, and `="echo foo`. Fixes: 25de7aa7b90c ("udev: modernize udev-rules.c")
Diffstat (limited to 'src')
-rw-r--r--src/shared/udev-util.c19
-rw-r--r--src/test/test-udev-util.c5
2 files changed, 19 insertions, 5 deletions
diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c
index a4b17be097..646eaf9135 100644
--- a/src/shared/udev-util.c
+++ b/src/shared/udev-util.c
@@ -347,11 +347,10 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
str += is_escaped;
if (str[0] != '"')
return -EINVAL;
- str++;
if (!is_escaped) {
/* unescape double quotation '\"'->'"' */
- for (i = j = str; *i != '"'; i++, j++) {
+ for (j = str, i = str + 1; *i != '"'; i++, j++) {
if (*i == '\0')
return -EINVAL;
if (i[0] == '\\' && i[1] == '"')
@@ -359,12 +358,17 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
*j = *i;
}
j[0] = '\0';
+ /*
+ * The return value must be terminated by two subsequent NULs
+ * so it could be safely interpreted as nulstr.
+ */
+ j[1] = '\0';
} else {
_cleanup_free_ char *unescaped = NULL;
ssize_t l;
/* find the end position of value */
- for (i = str; *i != '"'; i++) {
+ for (i = str + 1; *i != '"'; i++) {
if (i[0] == '\\')
i++;
if (*i == '\0')
@@ -372,12 +376,17 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
}
i[0] = '\0';
- l = cunescape_length(str, i - str, 0, &unescaped);
+ l = cunescape_length(str + 1, i - (str + 1), 0, &unescaped);
if (l < 0)
return l;
- assert(l <= i - str);
+ assert(l <= i - (str + 1));
memcpy(str, unescaped, l + 1);
+ /*
+ * The return value must be terminated by two subsequent NULs
+ * so it could be safely interpreted as nulstr.
+ */
+ str[l + 1] = '\0';
}
*ret_value = str;
diff --git a/src/test/test-udev-util.c b/src/test/test-udev-util.c
index 1db2dad4ff..4be3694e9e 100644
--- a/src/test/test-udev-util.c
+++ b/src/test/test-udev-util.c
@@ -24,6 +24,11 @@ static void test_udev_rule_parse_value_one(const char *in, const char *expected_
} else {
assert_se(streq_ptr(value, expected_value));
assert_se(endpos == str + strlen(in));
+ /*
+ * The return value must be terminated by two subsequent NULs
+ * so it could be safely interpreted as nulstr.
+ */
+ assert_se(value[strlen(value) + 1] == '\0');
}
}