fstab-filter: fix preserve fstab option escaping (#43274)
Fixes #42787.
This commit is contained in:
@@ -78,7 +78,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (flags & (EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS)) {
|
||||
if (flags & (EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX)) {
|
||||
bool eight_bit = false;
|
||||
char32_t u;
|
||||
|
||||
|
||||
+3
-17
@@ -529,7 +529,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
|
||||
return (int) n;
|
||||
}
|
||||
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator) {
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix) {
|
||||
char *r, *e;
|
||||
size_t n, k, m;
|
||||
|
||||
@@ -539,17 +539,12 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
||||
k = strlen(separator);
|
||||
m = strlen_ptr(prefix);
|
||||
|
||||
if (escape_separator) /* If the separator was multi-char, we wouldn't know how to escape it. */
|
||||
assert(k == 1);
|
||||
|
||||
n = 0;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (s != l)
|
||||
n += k;
|
||||
|
||||
bool needs_escaping = escape_separator && strchr(*s, *separator);
|
||||
|
||||
n += m + strlen(*s) * (1 + needs_escaping);
|
||||
n += m + strlen(*s);
|
||||
}
|
||||
|
||||
r = new(char, n+1);
|
||||
@@ -564,16 +559,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix,
|
||||
if (prefix)
|
||||
e = stpcpy(e, prefix);
|
||||
|
||||
bool needs_escaping = escape_separator && strchr(*s, *separator);
|
||||
|
||||
if (needs_escaping)
|
||||
for (size_t i = 0; (*s)[i]; i++) {
|
||||
if ((*s)[i] == *separator)
|
||||
*(e++) = '\\';
|
||||
*(e++) = (*s)[i];
|
||||
}
|
||||
else
|
||||
e = stpcpy(e, *s);
|
||||
e = stpcpy(e, *s);
|
||||
}
|
||||
|
||||
*e = 0;
|
||||
|
||||
+2
-2
@@ -120,9 +120,9 @@ char** strv_split_newlines(const char *s);
|
||||
* string in the vector is an empty string. */
|
||||
int strv_split_colon_pairs(char ***t, const char *s);
|
||||
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator);
|
||||
char* strv_join_full(char * const *l, const char *separator, const char *prefix);
|
||||
static inline char *strv_join(char * const *l, const char *separator) {
|
||||
return strv_join_full(l, separator, NULL, false);
|
||||
return strv_join_full(l, separator, NULL);
|
||||
}
|
||||
|
||||
bool strv_overlap(char * const *a, char * const *b) _pure_;
|
||||
|
||||
@@ -1172,10 +1172,10 @@ static int context_execute(Context *c) {
|
||||
return r;
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *x = strv_join_full(c->plugins, "", "\n ", /* escape_separator= */ false);
|
||||
_cleanup_free_ char *x = strv_join_full(c->plugins, "", "\n ");
|
||||
log_debug("Using plugins: %s", strna(x));
|
||||
|
||||
_cleanup_free_ char *y = strv_join_full(c->envp, "", "\n ", /* escape_separator= */ false);
|
||||
_cleanup_free_ char *y = strv_join_full(c->envp, "", "\n ");
|
||||
log_debug("Plugin environment: %s", strna(y));
|
||||
|
||||
_cleanup_free_ char *z = strv_join(strv_skip(c->argv, 1), " ");
|
||||
|
||||
+43
-5
@@ -200,6 +200,34 @@ int fstab_is_mount_point_full(const char *where, const char *path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static char* fstab_unescape_option(const char *s) {
|
||||
/* Undo the fstab option escaping: "\," -> ",", "\\" -> "\", and keep any
|
||||
* other "\x" verbatim (matches EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX). */
|
||||
char *ret, *e;
|
||||
|
||||
assert(s);
|
||||
|
||||
ret = new(char, strlen(s) + 1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
e = ret;
|
||||
for (const char *p = s; *p; p++) {
|
||||
if (*p == '\\' && p[1] != '\0') {
|
||||
if (IN_SET(p[1], ',', '\\')) {
|
||||
*e++ = p[1];
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
/* Keep the backslash and the following character verbatim. */
|
||||
*e++ = *p++;
|
||||
}
|
||||
*e++ = *p;
|
||||
}
|
||||
*e = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fstab_filter_options(
|
||||
const char *opts,
|
||||
const char *names,
|
||||
@@ -234,8 +262,10 @@ int fstab_filter_options(
|
||||
_cleanup_free_ char **filtered_strv = NULL; /* strings are owned by 'opts_split' */
|
||||
|
||||
/* For backwards compatibility, we need to pass-through escape characters.
|
||||
* The only ones we "consume" are the ones used as "\," or "\\". */
|
||||
r = strv_split_full(&opts_split, opts, ",", EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX);
|
||||
* The only ones we "consume" are the ones used as "\," or "\\". The option
|
||||
* values are not unescaped by strv_split_full() here; matching option values are
|
||||
* unescaped manually below so that callers keep getting the unescaped form. */
|
||||
r = strv_split_full(&opts_split, opts, ",", EXTRACT_UNESCAPE_RELAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -257,10 +287,18 @@ int fstab_filter_options(
|
||||
}
|
||||
|
||||
if (found) {
|
||||
_cleanup_free_ char *unescaped = NULL;
|
||||
|
||||
if ((ret_value && *x == '=') || ret_values) {
|
||||
unescaped = fstab_unescape_option(x + 1);
|
||||
if (!unescaped)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ret_value)
|
||||
r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL);
|
||||
r = free_and_replace(value, unescaped);
|
||||
else if (ret_values)
|
||||
r = strv_extend(&values, x + 1);
|
||||
r = strv_extend(&values, unescaped);
|
||||
else
|
||||
r = 0;
|
||||
} else
|
||||
@@ -270,7 +308,7 @@ int fstab_filter_options(
|
||||
}
|
||||
|
||||
if (ret_filtered) {
|
||||
filtered = strv_join_full(filtered_strv, ",", NULL, /* escape_separator= */ true);
|
||||
filtered = strv_join(filtered_strv, ",");
|
||||
if (!filtered)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -247,13 +247,13 @@ TEST(extract_first_word) {
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
|
||||
ASSERT_STREQ(t, "fooo bar");
|
||||
ASSERT_STREQ(t, "fooo\\ bar");
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
p = original = "fooo\\ bar quux";
|
||||
assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
|
||||
ASSERT_STREQ(t, "fooo bar");
|
||||
ASSERT_STREQ(t, "fooo\\ bar");
|
||||
free(t);
|
||||
assert_se(p == original + 10);
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ TEST(fstab_filter_options) {
|
||||
|
||||
/* escaped characters */
|
||||
do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, 1, "opt1", "\\", "\\", "opt2=\\xff");
|
||||
do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\");
|
||||
do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\\\");
|
||||
}
|
||||
|
||||
TEST(fstab_find_pri) {
|
||||
|
||||
+7
-20
@@ -159,44 +159,31 @@ TEST(strv_join) {
|
||||
}
|
||||
|
||||
TEST(strv_join_full) {
|
||||
_cleanup_free_ char *p = strv_join_full((char **)input_table_multiple, ", ", "foo", false);
|
||||
_cleanup_free_ char *p = strv_join_full((char **)input_table_multiple, ", ", "foo");
|
||||
assert_se(p);
|
||||
ASSERT_STREQ(p, "fooone, footwo, foothree");
|
||||
|
||||
_cleanup_free_ char *q = strv_join_full((char **)input_table_multiple, ";", "foo", false);
|
||||
_cleanup_free_ char *q = strv_join_full((char **)input_table_multiple, ";", "foo");
|
||||
assert_se(q);
|
||||
ASSERT_STREQ(q, "fooone;footwo;foothree");
|
||||
|
||||
_cleanup_free_ char *r = strv_join_full(STRV_MAKE("a", "a;b", "a:c"), ";", NULL, true);
|
||||
assert_se(r);
|
||||
ASSERT_STREQ(r, "a;a\\;b;a:c");
|
||||
|
||||
_cleanup_free_ char *s = strv_join_full(STRV_MAKE("a", "a;b", "a;;c", ";", ";x"), ";", NULL, true);
|
||||
assert_se(s);
|
||||
ASSERT_STREQ(s, "a;a\\;b;a\\;\\;c;\\;;\\;x");
|
||||
|
||||
_cleanup_free_ char *t = strv_join_full(STRV_MAKE("a", "a;b", "a:c", ";"), ";", "=", true);
|
||||
assert_se(t);
|
||||
ASSERT_STREQ(t, "=a;=a\\;b;=a:c;=\\;");
|
||||
t = mfree(t);
|
||||
|
||||
_cleanup_free_ char *u = strv_join_full((char **)input_table_multiple, NULL, "foo", false);
|
||||
_cleanup_free_ char *u = strv_join_full((char **)input_table_multiple, NULL, "foo");
|
||||
assert_se(u);
|
||||
ASSERT_STREQ(u, "fooone footwo foothree");
|
||||
|
||||
_cleanup_free_ char *v = strv_join_full((char **)input_table_one, ", ", "foo", false);
|
||||
_cleanup_free_ char *v = strv_join_full((char **)input_table_one, ", ", "foo");
|
||||
assert_se(v);
|
||||
ASSERT_STREQ(v, "fooone");
|
||||
|
||||
_cleanup_free_ char *w = strv_join_full((char **)input_table_none, ", ", "foo", false);
|
||||
_cleanup_free_ char *w = strv_join_full((char **)input_table_none, ", ", "foo");
|
||||
assert_se(w);
|
||||
ASSERT_STREQ(w, "");
|
||||
|
||||
_cleanup_free_ char *x = strv_join_full((char **)input_table_two_empties, ", ", "foo", false);
|
||||
_cleanup_free_ char *x = strv_join_full((char **)input_table_two_empties, ", ", "foo");
|
||||
assert_se(x);
|
||||
ASSERT_STREQ(x, "foo, foo");
|
||||
|
||||
_cleanup_free_ char *y = strv_join_full((char **)input_table_one_empty, ", ", "foo", false);
|
||||
_cleanup_free_ char *y = strv_join_full((char **)input_table_one_empty, ", ", "foo");
|
||||
assert_se(y);
|
||||
ASSERT_STREQ(y, "foo");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user