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'); } }