Blob Blame History Raw
From c0f53628926e9fe8956ea276e30d98817d8cbcd4 Mon Sep 17 00:00:00 2001
From: Filipe Brandenburger <filbranden@google.com>
Date: Wed, 10 Aug 2016 13:27:07 -0700
Subject: [PATCH] libmount: Preserve empty string value in optstr parsing

Recent mount (since the switch to libmount in v2.22) drops the '=' in
mount options that are set to an empty value.  For example, the command
line below will be affected:

  # mount -o rw,myopt='' -t tmpfs tmpfs /mnt/tmp

Fix that by preserving an empty string in the options passed to the
mount(2) syscall when they are present on the command line.

Add test cases to ensure empty string handling is working as expected
and in order to prevent regressions in the future.

Also tested manually by stracing mount commands (on a kernel which
accepts a special extra option, for testing purposes.)

Before this commit:

  # strace -e mount ./mount -t tmpfs -o rw,myopt='' tmpfs /mnt/tmp
  mount("tmpfs", "/mnt/tmp", "tmpfs", MS_MGC_VAL, "myarg") = -1 EINVAL (Invalid argument)

After this commit:

  # strace -e mount ./mount -t tmpfs -o rw,myopt='' tmpfs /mnt/tmp
  mount("tmpfs", "/mnt/tmp", "tmpfs", MS_MGC_VAL, "myopt=") = 0

All test cases pass, including newly added test cases.  Also checked
them with valgrind using:

  $ tests/run.sh --memcheck libmount/optstr

Fixes #332.

Signed-off-by: Filipe Brandenburger <filbranden@google.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
Upstream: http://github.com/karelzak/util-linux/commit/727c689908c5e68c92aa1dd65e0d3bdb6d91c1e5
Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1740572
---
 libmount/src/optstr.c                         |  4 +--
 .../libmount/optstr-append-empty-value        |  1 +
 .../libmount/optstr-deduplicate-empty         |  1 +
 .../libmount/optstr-prepend-empty-value       |  1 +
 .../libmount/optstr-remove-empty-value        |  1 +
 tests/expected/libmount/optstr-set-empty      |  1 +
 tests/expected/libmount/optstr-set-new-empty  |  1 +
 .../libmount/optstr-set-new-end-empty         |  1 +
 tests/ts/libmount/optstr                      | 28 +++++++++++++++++++
 9 files changed, 37 insertions(+), 2 deletions(-)
 create mode 100644 tests/expected/libmount/optstr-append-empty-value
 create mode 100644 tests/expected/libmount/optstr-deduplicate-empty
 create mode 100644 tests/expected/libmount/optstr-prepend-empty-value
 create mode 100644 tests/expected/libmount/optstr-remove-empty-value
 create mode 100644 tests/expected/libmount/optstr-set-empty
 create mode 100644 tests/expected/libmount/optstr-set-new-empty
 create mode 100644 tests/expected/libmount/optstr-set-new-end-empty

diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c
index 3c680ff6e..7bd9bbdb5 100644
--- a/libmount/src/optstr.c
+++ b/libmount/src/optstr.c
@@ -186,7 +186,7 @@ static int __mnt_optstr_append_option(char **optstr,
 	sz = osz + nsz + 1;		/* 1: '\0' */
 	if (osz)
 		sz++;			/* ',' options separator */
-	if (vsz)
+	if (value)
 		sz += vsz + 1;		/* 1: '=' */
 
 	p = realloc(*optstr, sz);
@@ -202,7 +202,7 @@ static int __mnt_optstr_append_option(char **optstr,
 	memcpy(p, name, nsz);
 	p += nsz;
 
-	if (vsz) {
+	if (value) {
 		*p++ = '=';
 		memcpy(p, value, vsz);
 		p += vsz;
diff --git a/tests/expected/libmount/optstr-append-empty-value b/tests/expected/libmount/optstr-append-empty-value
new file mode 100644
index 000000000..35adf5c72
--- /dev/null
+++ b/tests/expected/libmount/optstr-append-empty-value
@@ -0,0 +1 @@
+result: >aaa,bbb=BBB,ccc,ddd=<
diff --git a/tests/expected/libmount/optstr-deduplicate-empty b/tests/expected/libmount/optstr-deduplicate-empty
new file mode 100644
index 000000000..63b74f678
--- /dev/null
+++ b/tests/expected/libmount/optstr-deduplicate-empty
@@ -0,0 +1 @@
+result: >bbb,ccc,xxx,ddd,AAA=,fff=eee<
diff --git a/tests/expected/libmount/optstr-prepend-empty-value b/tests/expected/libmount/optstr-prepend-empty-value
new file mode 100644
index 000000000..4cea63527
--- /dev/null
+++ b/tests/expected/libmount/optstr-prepend-empty-value
@@ -0,0 +1 @@
+result: >ddd=,aaa,bbb=BBB,ccc<
diff --git a/tests/expected/libmount/optstr-remove-empty-value b/tests/expected/libmount/optstr-remove-empty-value
new file mode 100644
index 000000000..eee5c95b9
--- /dev/null
+++ b/tests/expected/libmount/optstr-remove-empty-value
@@ -0,0 +1 @@
+result: >aaa,ccc<
diff --git a/tests/expected/libmount/optstr-set-empty b/tests/expected/libmount/optstr-set-empty
new file mode 100644
index 000000000..e0a3300f9
--- /dev/null
+++ b/tests/expected/libmount/optstr-set-empty
@@ -0,0 +1 @@
+result: >aaa,bbb=,ccc<
diff --git a/tests/expected/libmount/optstr-set-new-empty b/tests/expected/libmount/optstr-set-new-empty
new file mode 100644
index 000000000..a1cfb3721
--- /dev/null
+++ b/tests/expected/libmount/optstr-set-new-empty
@@ -0,0 +1 @@
+result: >aaa=,bbb=BBB,ccc<
diff --git a/tests/expected/libmount/optstr-set-new-end-empty b/tests/expected/libmount/optstr-set-new-end-empty
new file mode 100644
index 000000000..d0e9880f3
--- /dev/null
+++ b/tests/expected/libmount/optstr-set-new-end-empty
@@ -0,0 +1 @@
+result: >aaa,bbb=BBB,ccc=<
diff --git a/tests/ts/libmount/optstr b/tests/ts/libmount/optstr
index f6a5c0530..07a548963 100755
--- a/tests/ts/libmount/optstr
+++ b/tests/ts/libmount/optstr
@@ -20,6 +20,10 @@ ts_init_subtest "append-value"
 ts_valgrind $TESTPROG --append "aaa,bbb=BBB,ccc" "ddd" "DDD" &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "append-empty-value"
+ts_valgrind $TESTPROG --append "aaa,bbb=BBB,ccc" "ddd" "" &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_init_subtest "prepend"
 ts_valgrind $TESTPROG --prepend "aaa,bbb=BBB,ccc" "ddd" &> $TS_OUTPUT
 ts_finalize_subtest
@@ -28,6 +32,10 @@ ts_init_subtest "prepend-value"
 ts_valgrind $TESTPROG --prepend "aaa,bbb=BBB,ccc" "ddd" "DDD" &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "prepend-empty-value"
+ts_valgrind $TESTPROG --prepend "aaa,bbb=BBB,ccc" "ddd" "" &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_init_subtest "set-remove"
 ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "bbb" &> $TS_OUTPUT
 ts_finalize_subtest
@@ -40,14 +48,26 @@ ts_init_subtest "set-large"
 ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "bbb" "XXX-YYY-ZZZ" &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "set-empty"
+ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "bbb" "" &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_init_subtest "set-new"
 ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "aaa" "XXX" &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "set-new-empty"
+ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "aaa" "" &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_init_subtest "set-new-end"
 ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "ccc" "XXX" &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "set-new-end-empty"
+ts_valgrind $TESTPROG --set "aaa,bbb=BBB,ccc" "ccc" "" &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_init_subtest "get"
 ts_valgrind $TESTPROG --get "aaa,bbb=BBB,ccc" "aaa" &> $TS_OUTPUT
 ts_finalize_subtest
@@ -68,6 +88,10 @@ ts_init_subtest "remove-value"
 ts_valgrind $TESTPROG --remove "aaa,bbb=BBB,ccc" "bbb" &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "remove-empty-value"
+ts_valgrind $TESTPROG --remove "aaa,bbb=,ccc" "bbb" &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_init_subtest "split"
 ts_valgrind $TESTPROG --split "aaa,bbb=BBB,ccc,x-bar,x-foo=foodata,user=kzak,noexec,nosuid,loop=/dev/loop0" &> $TS_OUTPUT
 ts_finalize_subtest
@@ -92,4 +116,8 @@ ts_init_subtest "deduplicate"
 ts_valgrind $TESTPROG --dedup bbb,ccc,AAA,xxx,AAA=a,AAA=bbb,ddd,AAA=ccc,fff=eee AAA &> $TS_OUTPUT
 ts_finalize_subtest
 
+ts_init_subtest "deduplicate-empty"
+ts_valgrind $TESTPROG --dedup bbb,ccc,AAA,xxx,AAA=a,AAA=bbb,ddd,AAA=,fff=eee AAA &> $TS_OUTPUT
+ts_finalize_subtest
+
 ts_finalize
-- 
2.21.0