/
githubmirror
/
ostree
Обзор
Документация
Войти
/
githubmirror
/
ostree
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
tests/test-kargs.c
340 строк
14 KB
Joseph Marrero Corchado
kargs: Fix crash on quoted values in /proc/cmdline
26 июн 2026, 16:29
26 июн 2026, 16:29
4f104a3
Код
Авторство
О чём код?
/* * Copyright (C) 2015 Red Hat, Inc. * * SPDX-License-Identifier: LGPL-2.0+ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <https://www.gnu.org/licenses/>. */ #include "config.h" #include "ostree-kernel-args-private.h" #include "otutil.h" static gboolean check_string_existance (OstreeKernelArgs *karg, const char *string_to_find) { g_auto (GStrv) string_list = ostree_kernel_args_to_strv (karg); return g_strv_contains ((const char *const *)string_list, string_to_find); } static gboolean kernel_args_entry_value_equal (gconstpointer data, gconstpointer value) { const OstreeKernelArgsEntry *e = data; return g_strcmp0 (_ostree_kernel_args_entry_get_value (e), value) == 0; } static gboolean kernel_args_entry_key_equal (gconstpointer data, gconstpointer key) { const OstreeKernelArgsEntry *e = data; return g_strcmp0 (_ostree_kernel_args_entry_get_key (e), key) == 0; } static void test_kargs_delete (void) { g_autoptr (GError) error = NULL; gboolean ret; __attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); ostree_kernel_args_append (karg, "single_key=test"); ostree_kernel_args_append (karg, "test=firstval"); ostree_kernel_args_append (karg, "test=secondval"); ostree_kernel_args_append (karg, "test="); ostree_kernel_args_append (karg, "test"); /* Delete a non-existant key should fail */ ret = ostree_kernel_args_delete (karg, "non_existant_key", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Delete a key with multiple values when only specifying key should work if a no-value * variant exists */ ret = ostree_kernel_args_delete (karg, "test", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "test")); /* Trying again now should fail since there are only kargs with various values */ ret = ostree_kernel_args_delete (karg, "test", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Delete a key with a non existant value should fail */ ret = ostree_kernel_args_delete (karg, "test=non_existant_value", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Delete a key with only one value should fail if the value doesn't match */ ret = ostree_kernel_args_delete (karg, "single_key=non_existent_value", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Delete a key with only one value should succeed by only specifying key */ ret = ostree_kernel_args_delete (karg, "single_key", &error); g_assert_no_error (error); g_assert (ret); /* verify the value array is properly updated */ GPtrArray *kargs_array = _ostree_kernel_arg_get_key_array (karg); g_assert (!ot_ptr_array_find_with_equal_func (kargs_array, "single_key", kernel_args_entry_value_equal, NULL)); g_assert (!check_string_existance (karg, "single_key")); /* Delete specific key/value pair */ ret = ostree_kernel_args_delete (karg, "test=secondval", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "test=secondval")); /* Delete key/value pair with empty string value */ ret = ostree_kernel_args_delete (karg, "test=", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "test=")); ret = ostree_kernel_args_delete (karg, "test=firstval", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "test=firstval")); /* Check that we can delete duplicate keys */ ostree_kernel_args_append (karg, "test=foo"); ostree_kernel_args_append (karg, "test=foo"); check_string_existance (karg, "test=foo"); ret = ostree_kernel_args_delete (karg, "test=foo", &error); g_assert_no_error (error); g_assert (ret); g_assert (check_string_existance (karg, "test=foo")); ret = ostree_kernel_args_delete (karg, "test=foo", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "test=foo")); /* Make sure we also gracefully do this for key-only args */ ostree_kernel_args_append (karg, "nosmt"); ostree_kernel_args_append (karg, "nosmt"); check_string_existance (karg, "nosmt"); ret = ostree_kernel_args_delete (karg, "nosmt", &error); g_assert_no_error (error); g_assert (ret); g_assert (check_string_existance (karg, "nosmt")); ret = ostree_kernel_args_delete (karg, "nosmt", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "nosmt")); /* Make sure we also support quotes and spaces */ ostree_kernel_args_append (karg, "foo=\"1 2\" bar=0"); check_string_existance (karg, "foo=\"1 2\""); check_string_existance (karg, "bar=0"); ret = ostree_kernel_args_delete (karg, "foo=\"1 2\" bar=0", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "foo=\"1 2\"")); g_assert (!check_string_existance (karg, "bar=0")); } static void test_kargs_replace (void) { g_autoptr (GError) error = NULL; gboolean ret; __attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); ostree_kernel_args_append (karg, "single_key"); ostree_kernel_args_append (karg, "test=firstval"); ostree_kernel_args_append (karg, "test=secondval"); /* Replace when the input key is non-existant should fail */ ret = ostree_kernel_args_new_replace (karg, "nonexistantkey", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Replace non-existant value with input key=nonexistantvalue=newvalue should fail */ ret = ostree_kernel_args_new_replace (karg, "single_key=nonexistantval=newval", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Replace with input key=value will fail for a key with multiple values */ ret = ostree_kernel_args_new_replace (karg, "test=newval", &error); g_assert (!ret); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_clear_error (&error); /* Replace with input key=value for a key with single value should succeed * Also note, we also allow ''(empty string) valid to be a value */ ret = ostree_kernel_args_new_replace (karg, "single_key=newvalue", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "single_key")); g_assert (check_string_existance (karg, "single_key=newvalue")); /* Replace with input key=value=newvalue if key and value both * exist, the action should succeed */ ret = ostree_kernel_args_new_replace (karg, "test=firstval=newval", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "test=firstval")); g_assert (check_string_existance (karg, "test=newval")); /* Replace with input contains quotes and spaces, it should support */ ostree_kernel_args_append (karg, "foo=1 bar=\"1 2\""); ret = ostree_kernel_args_new_replace (karg, "foo=\"1 2\" bar", &error); g_assert_no_error (error); g_assert (ret); g_assert (!check_string_existance (karg, "foo=1")); g_assert (!check_string_existance (karg, "bar=\"1 2\"")); g_assert (check_string_existance (karg, "foo=\"1 2\"")); g_assert (check_string_existance (karg, "bar")); } /* In this function, we want to verify that ostree_kernel_args_append * and ostree_kernel_args_to_string is correct. After that * we will use these two functions(append and tostring) in other tests: delete and replace */ static void test_kargs_append (void) { __attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *append_arg = ostree_kernel_args_new (); /* Some valid cases (key=value) pair */ ostree_kernel_args_append (append_arg, "test=valid"); ostree_kernel_args_append (append_arg, "test=secondvalid"); ostree_kernel_args_append (append_arg, "test="); ostree_kernel_args_append (append_arg, "test"); ostree_kernel_args_append (append_arg, "second_test"); ostree_kernel_args_append (append_arg, "second_test=0 second_test=\"1 2\""); /* We loops through the kargs inside table to verify * the functionality of append because at this stage * we have yet to find the conversion kargs to string fully "functional" */ GHashTable *kargs_table = _ostree_kernel_arg_get_kargs_table (append_arg); GLNX_HASH_TABLE_FOREACH_KV (kargs_table, const char *, key, GPtrArray *, value_array) { if (g_str_equal (key, "test")) { g_assert (ot_ptr_array_find_with_equal_func (value_array, "valid", kernel_args_entry_value_equal, NULL)); g_assert (ot_ptr_array_find_with_equal_func (value_array, "secondvalid", kernel_args_entry_value_equal, NULL)); g_assert (ot_ptr_array_find_with_equal_func (value_array, "", kernel_args_entry_value_equal, NULL)); g_assert (ot_ptr_array_find_with_equal_func (value_array, NULL, kernel_args_entry_value_equal, NULL)); } else { g_assert_cmpstr (key, ==, "second_test"); g_assert (ot_ptr_array_find_with_equal_func (value_array, NULL, kernel_args_entry_value_equal, NULL)); g_assert (ot_ptr_array_find_with_equal_func (value_array, "0", kernel_args_entry_value_equal, NULL)); g_assert (ot_ptr_array_find_with_equal_func (value_array, "\"1 2\"", kernel_args_entry_value_equal, NULL)); } } /* verify the value array is properly updated */ GPtrArray *kargs_array = _ostree_kernel_arg_get_key_array (append_arg); g_assert ( ot_ptr_array_find_with_equal_func (kargs_array, "test", kernel_args_entry_key_equal, NULL)); g_assert (ot_ptr_array_find_with_equal_func (kargs_array, "second_test", kernel_args_entry_key_equal, NULL)); /* Up till this point, we verified that the above was all correct, we then * check ostree_kernel_args_to_string has the right result */ g_auto (GStrv) kargs_list = ostree_kernel_args_to_strv (append_arg); g_assert (g_strv_contains ((const char *const *)kargs_list, "test=valid")); g_assert (g_strv_contains ((const char *const *)kargs_list, "test=secondvalid")); g_assert (g_strv_contains ((const char *const *)kargs_list, "test=")); g_assert (g_strv_contains ((const char *const *)kargs_list, "test")); g_assert (g_strv_contains ((const char *const *)kargs_list, "second_test")); g_assert (g_strv_contains ((const char *const *)kargs_list, "second_test=0")); g_assert (g_strv_contains ((const char *const *)kargs_list, "second_test=\"1 2\"")); g_assert_cmpint (7, ==, g_strv_length (kargs_list)); } /* Regression test: parsing a /proc/cmdline-style string containing quoted * kernel args with spaces must not crash. Commit abc7d5b9 added a * quote-aware splitter (split_kernel_args) but ostree_kernel_args_append_proc_cmdline * still used a naive g_strsplit(" ") that broke quoted tokens apart, causing a * g_assert_false(quoted) abort. * * Bootloaders may reformat quotes -- e.g. GRUB turns testparam="value with spaces" * into "testparam=value with spaces" in /proc/cmdline. Both forms must be handled. */ static void test_kargs_quoted_cmdline (void) { /* Test 1: Standard quoted value (as stored by rpm-ostree) */ { __attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); ostree_kernel_args_parse_append (karg, "root=UUID=abc quiet testparam=\"value with spaces\" rw"); g_assert (check_string_existance (karg, "root=UUID=abc")); g_assert (check_string_existance (karg, "quiet")); g_assert (check_string_existance (karg, "testparam=\"value with spaces\"")); g_assert (check_string_existance (karg, "rw")); } /* Test 2: GRUB-reformatted quoting (quotes wrapping entire token) * /proc/cmdline may show: "testparam=value with spaces" */ { __attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); ostree_kernel_args_parse_append (karg, "root=UUID=abc quiet \"testparam=value with spaces\" rw"); g_assert (check_string_existance (karg, "root=UUID=abc")); g_assert (check_string_existance (karg, "quiet")); g_assert (check_string_existance (karg, "\"testparam=value with spaces\"")); g_assert (check_string_existance (karg, "rw")); } /* Test 3: Multiple quoted args */ { __attribute__ ((cleanup (ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); ostree_kernel_args_parse_append (karg, "foo=\"1 2\" bar=\"3 4\""); g_assert (check_string_existance (karg, "foo=\"1 2\"")); g_assert (check_string_existance (karg, "bar=\"3 4\"")); g_auto (GStrv) kargs_list = ostree_kernel_args_to_strv (karg); g_assert_cmpint (2, ==, g_strv_length (kargs_list)); } } int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); g_test_add_func ("/kargs/kargs_append", test_kargs_append); g_test_add_func ("/kargs/kargs_delete", test_kargs_delete); g_test_add_func ("/kargs/kargs_replace", test_kargs_replace); g_test_add_func ("/kargs/kargs_quoted_cmdline", test_kargs_quoted_cmdline); return g_test_run (); }