Skip to content

Commit 84156d6

Browse files
committed
kargs: Fix crash on quoted values in /proc/cmdline
ostree_kernel_args_append_proc_cmdline() crashes with SIGABRT when /proc/cmdline contains quoted kernel arguments with spaces (e.g. "testparam=value with spaces"). This was reported by Arch Linux maintainers when building ostree 2026.1 and reproduced on 2025.7. Root cause: commit abc7d5b ("kargs: parse spaces in kargs input and keep quotes", March 2024) added split_kernel_args(), a quote-aware string splitter, and updated ostree_kernel_args_append() and three other functions to use it. However, it did not update ostree_kernel_args_append_proc_cmdline(), which still used a naive g_strsplit(" ") to tokenize /proc/cmdline. When the cmdline contained quoted values with spaces, g_strsplit broke them into fragments with unterminated quotes. These fragments were then passed to ostree_kernel_args_append() -> split_kernel_args(), which hit a g_assert_false(quoted) and aborted. The bug was latent since v2024.5 because the test-admin-deploy-karg.sh and test-admin-instutil-set-kargs.sh tests read the real /proc/cmdline from the build host. CI environments never had quoted values in their cmdline, so the crash never triggered. The Arch build server recently acquired a quoted value (likely from a kernel or GRUB config change), exposing the bug. Additionally, bootloaders may reformat quotes: what rpm-ostree stores as testparam="value with spaces" appears in /proc/cmdline as "testparam=value with spaces" (GRUB wraps the entire token in quotes instead of just the value). Fix this with two changes: 1. Replace g_strsplit() with split_kernel_args() in ostree_kernel_args_append_proc_cmdline() so the initial tokenization of /proc/cmdline is quote-aware. Individual args passed to ostree_kernel_args_append() are now already properly split. 2. Replace g_assert_false(quoted) in split_kernel_args() with a g_debug() warning that continues execution, treating the remainder as a single token. Since we cannot control what bootloaders put in /proc/cmdline, a hard abort on unterminated quotes is never appropriate. Add a unit test (test_kargs_quoted_cmdline) covering standard quoted values, GRUB-reformatted quoting, and multiple quoted args. Add a kola destructive test (kargs-proc-cmdline-quoted.sh) that injects a quoted karg via rpm-ostree, reboots, and verifies --karg-proc-cmdline and --import-proc-cmdline succeed without crashing. Assisted-by: OpenCode (Claude claude-opus-4-6) Signed-off-by: Joseph Marrero Corchado <jmarrero@redhat.com>
1 parent 1d2b902 commit 84156d6

3 files changed

Lines changed: 101 additions & 9 deletions

File tree

src/libostree/ostree-kernel-args.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,12 @@ split_kernel_args (const char *str)
188188
}
189189
}
190190

191-
// Add the last slice
192-
if (!quoted)
193-
g_ptr_array_add (strv, g_strndup (start, str + len - start));
194-
else
195-
{
196-
g_debug ("Missing terminating quote in '%s'.\n", str);
197-
g_assert_false (quoted);
198-
}
191+
// Add the last slice. If there's an unterminated quote (e.g. from
192+
// bootloader-reformatted /proc/cmdline), treat the remainder as a
193+
// single token rather than aborting.
194+
if (quoted)
195+
g_debug ("Missing terminating quote in '%s', treating remainder as single token.\n", str);
196+
g_ptr_array_add (strv, g_strndup (start, str + len - start));
199197

200198
g_ptr_array_add (strv, NULL);
201199
return (char **)g_ptr_array_free (strv, FALSE);
@@ -681,7 +679,7 @@ ostree_kernel_args_append_proc_cmdline (OstreeKernelArgs *kargs, GCancellable *c
681679

682680
g_strchomp (proc_cmdline);
683681

684-
proc_cmdline_args = g_strsplit (proc_cmdline, " ", -1);
682+
proc_cmdline_args = split_kernel_args (proc_cmdline);
685683
ostree_kernel_args_append_argv_filtered (kargs, proc_cmdline_args, filtered_prefixes);
686684

687685
return TRUE;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
3+
# Verify ostree handles quoted kernel args with spaces in /proc/cmdline.
4+
#
5+
# Regression test for a bug introduced in abc7d5b9 where
6+
# ostree_kernel_args_append_proc_cmdline() used a naive g_strsplit(" ")
7+
# to tokenize /proc/cmdline, then passed the fragments to
8+
# ostree_kernel_args_append() which calls the quote-aware
9+
# split_kernel_args(). Fragments with unterminated quotes caused a
10+
# g_assert_false(quoted) abort.
11+
#
12+
# The bootloader (GRUB) may reformat quoted kargs -- e.g. what
13+
# rpm-ostree stores as testparam="value with spaces" can appear in
14+
# /proc/cmdline as "testparam=value with spaces" (quotes wrapping
15+
# the entire token). The parser must handle both forms.
16+
17+
set -xeuo pipefail
18+
19+
. ${KOLA_EXT_DATA}/libinsttest.sh
20+
21+
case "${AUTOPKGTEST_REBOOT_MARK:-}" in
22+
"")
23+
# Append a quoted karg containing spaces
24+
rpm-ostree kargs --append='testparam="value with spaces"'
25+
/tmp/autopkgtest-reboot "verify"
26+
;;
27+
"verify")
28+
# The karg should be present in /proc/cmdline (possibly reformatted
29+
# by the bootloader, e.g. "testparam=value with spaces")
30+
assert_file_has_content /proc/cmdline testparam
31+
32+
# These commands read /proc/cmdline and previously crashed with:
33+
# g_assert_false(quoted) in split_kernel_args()
34+
ostree admin instutil set-kargs --import-proc-cmdline
35+
echo "ok import-proc-cmdline with quoted kargs"
36+
37+
host_commit=$(ostree admin status | sed -n 's/^.* \(.*\)\.0$/\1/p' | head -1)
38+
ostree admin deploy --karg-proc-cmdline "${host_commit}"
39+
echo "ok deploy --karg-proc-cmdline with quoted kargs"
40+
;;
41+
*)
42+
fatal "Unexpected AUTOPKGTEST_REBOOT_MARK=${AUTOPKGTEST_REBOOT_MARK}"
43+
;;
44+
esac

tests/test-kargs.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,55 @@ test_kargs_append (void)
278278
g_assert_cmpint (7, ==, g_strv_length (kargs_list));
279279
}
280280

281+
/* Regression test: parsing a /proc/cmdline-style string containing quoted
282+
* kernel args with spaces must not crash. Commit abc7d5b9 added a
283+
* quote-aware splitter (split_kernel_args) but ostree_kernel_args_append_proc_cmdline
284+
* still used a naive g_strsplit(" ") that broke quoted tokens apart, causing a
285+
* g_assert_false(quoted) abort.
286+
*
287+
* Bootloaders may reformat quotes -- e.g. GRUB turns testparam="value with spaces"
288+
* into "testparam=value with spaces" in /proc/cmdline. Both forms must be handled.
289+
*/
290+
static void
291+
test_kargs_quoted_cmdline (void)
292+
{
293+
/* Test 1: Standard quoted value (as stored by rpm-ostree) */
294+
{
295+
__attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg
296+
= ostree_kernel_args_new ();
297+
ostree_kernel_args_parse_append (karg,
298+
"root=UUID=abc quiet testparam=\"value with spaces\" rw");
299+
g_assert (check_string_existance (karg, "root=UUID=abc"));
300+
g_assert (check_string_existance (karg, "quiet"));
301+
g_assert (check_string_existance (karg, "testparam=\"value with spaces\""));
302+
g_assert (check_string_existance (karg, "rw"));
303+
}
304+
305+
/* Test 2: GRUB-reformatted quoting (quotes wrapping entire token)
306+
* /proc/cmdline may show: "testparam=value with spaces" */
307+
{
308+
__attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg
309+
= ostree_kernel_args_new ();
310+
ostree_kernel_args_parse_append (karg,
311+
"root=UUID=abc quiet \"testparam=value with spaces\" rw");
312+
g_assert (check_string_existance (karg, "root=UUID=abc"));
313+
g_assert (check_string_existance (karg, "quiet"));
314+
g_assert (check_string_existance (karg, "\"testparam=value with spaces\""));
315+
g_assert (check_string_existance (karg, "rw"));
316+
}
317+
318+
/* Test 3: Multiple quoted args */
319+
{
320+
__attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg
321+
= ostree_kernel_args_new ();
322+
ostree_kernel_args_parse_append (karg, "foo=\"1 2\" bar=\"3 4\"");
323+
g_assert (check_string_existance (karg, "foo=\"1 2\""));
324+
g_assert (check_string_existance (karg, "bar=\"3 4\""));
325+
g_auto (GStrv) kargs_list = ostree_kernel_args_to_strv (karg);
326+
g_assert_cmpint (2, ==, g_strv_length (kargs_list));
327+
}
328+
}
329+
281330
int
282331
main (int argc, char *argv[])
283332
{
@@ -286,5 +335,6 @@ main (int argc, char *argv[])
286335
g_test_add_func ("/kargs/kargs_append", test_kargs_append);
287336
g_test_add_func ("/kargs/kargs_delete", test_kargs_delete);
288337
g_test_add_func ("/kargs/kargs_replace", test_kargs_replace);
338+
g_test_add_func ("/kargs/kargs_quoted_cmdline", test_kargs_quoted_cmdline);
289339
return g_test_run ();
290340
}

0 commit comments

Comments
 (0)