From a6b64860b39102ae8b1ad9723fb2cdfbb67c17fd Mon Sep 17 00:00:00 2001 From: Albert Esteve Date: Fri, 7 Feb 2025 14:41:22 +0100 Subject: [PATCH] stages/kernel-cmdline: add max cmdline option Add an additional option called `kernel_line_size` to allow setting a maximum cmdline size check value for custom kernels or other restrictions. This will override the arch defaults, if not set, then the size map is checked, and if the current architecture is not in the map, fallback to 4096, which is the max value allowed for COMMAND_LINE_SIZE. Signed-off-by: Albert Esteve --- stages/org.osbuild.kernel-cmdline | 3 +- stages/org.osbuild.kernel-cmdline.meta.json | 6 ++ stages/test/test_kernel_cmdline.py | 63 +++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 stages/test/test_kernel_cmdline.py diff --git a/stages/org.osbuild.kernel-cmdline b/stages/org.osbuild.kernel-cmdline index b0ea4899..df72094f 100755 --- a/stages/org.osbuild.kernel-cmdline +++ b/stages/org.osbuild.kernel-cmdline @@ -29,7 +29,8 @@ MAX_SIZE_MAP = { def main(tree, options): root_fs_uuid = options.get("root_fs_uuid", "") additional = options.get("kernel_opts", "") - max_cmdline_size = MAX_SIZE_MAP.get(platform.machine().lower(), 4096) + max_cmdline_size = options.get("kernel_cmdline_size", + MAX_SIZE_MAP.get(platform.machine().lower(), 4096)) params = [] diff --git a/stages/org.osbuild.kernel-cmdline.meta.json b/stages/org.osbuild.kernel-cmdline.meta.json index 4ba73d4e..e511078b 100644 --- a/stages/org.osbuild.kernel-cmdline.meta.json +++ b/stages/org.osbuild.kernel-cmdline.meta.json @@ -30,6 +30,12 @@ "description": "Additional kernel boot options", "type": "string", "default": "" + }, + "kernel_cmdline_size": { + "description": "Sets a custom maximum kernel cmdline size", + "type": "integer", + "minimum": 256, + "maximum": 4096 } } } diff --git a/stages/test/test_kernel_cmdline.py b/stages/test/test_kernel_cmdline.py new file mode 100644 index 00000000..9b0c87fd --- /dev/null +++ b/stages/test/test_kernel_cmdline.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +from unittest import mock + +import pytest # type: ignore + +from osbuild import testutil + +STAGE_NAME = "org.osbuild.kernel-cmdline" + + +@pytest.mark.parametrize("options, expected", [ + ({"kernel_opts": "--custom-opt=some"}, "--custom-opt=some"), + ({"root_fs_uuid": "some-uuid"}, "root=UUID=some-uuid"), + ({"root_fs_uuid": "other-uuid", "kernel_opts": "--custom-opt=other"}, + "root=UUID=other-uuid --custom-opt=other"), +]) +def test_kernel_cmdline(tmp_path, stage_module, options, expected): + tree = tmp_path / "tree" + tree.mkdir() + + stage_module.main(tree, options) + cmdline_file = tree / "etc" / "kernel" / "cmdline" + assert cmdline_file.exists() + assert cmdline_file.read_text() == expected + + +@pytest.mark.parametrize("options, arch", [ + ({"kernel_opts": "a" * 2049}, "x86_64"), + ({"kernel_opts": "a" * 1025}, "arm"), + ({"kernel_opts": "a" * 2049}, "aarch64"), + ({"kernel_opts": "a" * 257, "kernel_cmdline_size": 256}, "any"), +]) +@mock.patch("platform.machine") +def test_kernel_opts_size_check(mock_machine, tmp_path, stage_module, options, arch): + tree = tmp_path / "tree" + tree.mkdir() + mock_machine.return_value = arch + + with pytest.raises(ValueError) as e: + stage_module.main(tree, options) + assert str(e.value).startswith("The size of the kernel cmdline options cannot be larger than") + + +@pytest.mark.parametrize("options, expected_error", [ + ({"kernel_cmdline_size": 256}, ""), + ({"kernel_cmdline_size": 4096}, ""), + ({"kernel_cmdline_size": "not integer"}, "is not of type 'integer'"), + ({"kernel_cmdline_size": 0}, "is less than the minimum of 256"), + ({"kernel_cmdline_size": 4097}, "is greater than the maximum of 4096"), +]) +def test_schema_validation_kernel_cmdline(stage_schema, options, expected_error): + test_input = { + "type": STAGE_NAME, + "options": options + } + res = stage_schema.validate(test_input) + + if not expected_error: + assert res.valid + else: + assert not res.valid + testutil.assert_jsonschema_error_contains(res, expected_error, expected_num_errs=1)