]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fstab,crypttab: allow escaping of commas
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 24 Sep 2020 12:55:57 +0000 (14:55 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 25 Sep 2020 11:36:34 +0000 (13:36 +0200)
Fixes #17035. We use "," as the separator between arguments in fstab and crypttab
options field, but the kernel started using "," within arguments. Users will need
to escape those nested commas.

src/cryptsetup/cryptsetup.c
src/shared/fstab-util.c
src/test/test-fstab-util.c

index 78efe19f238446f096969ea97d9c3369d30e35cf..10472bde26642c54804859602fe8491f38325eac 100644 (file)
@@ -294,7 +294,7 @@ static int parse_options(const char *options) {
                 _cleanup_free_ char *word = NULL;
                 int r;
 
-                r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
+                r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
                 if (r < 0)
                         return log_error_errno(r, "Failed to parse options: %m");
                 if (r == 0)
@@ -874,6 +874,9 @@ static int run(int argc, char *argv[]) {
                                 return r;
                 }
 
+                log_debug("%s %s ← %s type=%s cipher=%s", __func__,
+                          argv[2], argv[3], strempty(arg_type), strempty(arg_cipher));
+
                 /* A delicious drop of snake oil */
                 (void) mlockall(MCL_FUTURE);
 
index d883eca5c785d692f06ced398a06b6a743ff9c44..ca88813602304e316e8d1c37fb1eb74ff094154b 100644 (file)
@@ -95,7 +95,19 @@ int fstab_filter_options(const char *opts, const char *names,
 
         if (!ret_filtered) {
                 for (const char *word = opts;;) {
-                        const char *end = word + strcspn(word, ",");
+                        const char *end = word;
+
+                        /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
+                         * the only valid escape sequence, so we can do a very simple test here. */
+                        for (;;) {
+                                size_t n = strcspn(end, ",");
+
+                                end += n;
+                                if (n > 0 && end[-1] == '\\')
+                                        end++;
+                                else
+                                        break;
+                        }
 
                         NULSTR_FOREACH(name, names) {
                                 if (end < word + strlen(name))
@@ -128,9 +140,10 @@ int fstab_filter_options(const char *opts, const char *names,
                                 break;
                 }
         } else {
-                stor = strv_split(opts, ",");
-                if (!stor)
-                        return -ENOMEM;
+                r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
+                if (r < 0)
+                        return r;
+
                 strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
                 if (!strv)
                         return -ENOMEM;
@@ -165,7 +178,7 @@ answer:
         if (ret_filtered) {
                 char *f;
 
-                f = strv_join(strv, ",");
+                f = strv_join_full(strv, ",", NULL, true);
                 if (!f)
                         return -ENOMEM;
 
index 187be69d15e2cccfdaa003903161fff7af03a51e..f3506045a1f2634deb6e23179e363e43bbd464d4 100644 (file)
@@ -13,12 +13,11 @@ int fstab_filter_options(const char *opts, const char *names,
 */
 
 static void do_fstab_filter_options(const char *opts,
-                                      const char *remove,
-                                      int r_expected,
-                                      const char *name_expected,
-                                      const char *value_expected,
-                                      const char *filtered_expected) {
-
+                                    const char *remove,
+                                    int r_expected,
+                                    const char *name_expected,
+                                    const char *value_expected,
+                                    const char *filtered_expected) {
         int r;
         const char *name;
         _cleanup_free_ char *value = NULL, *filtered = NULL;
@@ -34,7 +33,7 @@ static void do_fstab_filter_options(const char *opts,
 
         /* also test the malloc-less mode */
         r = fstab_filter_options(opts, remove, &name, NULL, NULL);
-        log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"",
+        log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
                  opts, r, name,
                  r_expected, name_expected);
         assert_se(r == r_expected);
@@ -54,6 +53,12 @@ static void test_fstab_filter_options(void) {
         do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other");
         do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other");
 
+        do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, "opt", "0,1", "other");
+        do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, "opt", "0", "other,x-opt\\,foobar");
+        do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, "opt", NULL, "other,x-opt\\,part");
+        do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, "opt", NULL, "other,part\\,x-opt");
+        do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part");
+
         do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
         do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
         do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);