From 759968136d68ba178904313c38ad1003525c58ac Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Tue, 26 May 2026 07:03:32 +0000 Subject: [PATCH 1/2] tools: mkimage: fix get_basename crash on paths with dotted directories The get_basename() helper in tools/fit_image.c searches the entire input path for the last '/' and the last '.' independently. When the last '.' falls at an offset earlier than the last '/' (for example "./mydt", "a.b/c", or "sub.d/leaf"), 'end' points before 'start' and the computed length is negative. The subsequent size check uses signed comparison so the negative value passes through unchanged, and memcpy() is then called with that length implicitly cast to size_t, which segfaults. Restrict the dot search to the substring that follows the last slash so that only an extension in the filename component can become the end of the basename. This matches the function's stated intent of stripping an extension from the leaf, and keeps the existing behaviour for typical inputs such as "arch/arm/dts/foo.dtb". Reproducer that previously segfaulted and now produces a valid image: echo dummy > kernel.bin echo dummy > ./mydt ./tools/mkimage -f auto -A arm -O linux -T kernel -C none \ -a 0x80000000 -e 0x80000000 -n test \ -d kernel.bin -b ./mydt out.itb Signed-off-by: Aristo Chen Reviewed-by: Quentin Schulz --- tools/fit_image.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/fit_image.c b/tools/fit_image.c index 1dbc14c63e4..6c129117297 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -265,8 +265,14 @@ static void get_basename(char *str, int size, const char *fname) */ p = strrchr(fname, '/'); start = p ? p + 1 : fname; - p = strrchr(fname, '.'); - end = p ? p : fname + strlen(fname); + /* + * Search for the extension dot only within the basename. Searching + * the whole path would let a dot in the directory part (for example + * "./mydt" or "a.b/c") place 'end' before 'start' and produce a + * negative length, which the size check below does not catch. + */ + p = strrchr(start, '.'); + end = p ? p : start + strlen(start); len = end - start; if (len >= size) len = size - 1; From 4a4452a03916d8687442b1d0af5098be986e439e Mon Sep 17 00:00:00 2001 From: Aristo Chen Date: Tue, 26 May 2026 07:03:33 +0000 Subject: [PATCH 2/2] test/py: cover get_basename crash on paths with dotted directories Add a parametrized regression test for the fix in the previous commit. The test invokes mkimage in auto-FIT mode (-f auto) with a -b argument whose directory component contains a '.' and whose leaf either lacks an extension or is a plain identifier. Before the fix these inputs caused get_basename() to compute a negative length and segfault inside memcpy. The test asserts that mkimage exits successfully and that the fdt sub-image description matches the expected stripped basename, covering "./mydt", "./sub.d/leaf", and "./a.b/c". A control input of "./mydt.dtb" is also exercised to confirm normal extension stripping still works. Signed-off-by: Aristo Chen --- test/py/tests/test_fit_mkimage_validate.py | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/test/py/tests/test_fit_mkimage_validate.py b/test/py/tests/test_fit_mkimage_validate.py index 170b2a8cbbb..5922f071dd8 100644 --- a/test/py/tests/test_fit_mkimage_validate.py +++ b/test/py/tests/test_fit_mkimage_validate.py @@ -7,6 +7,7 @@ import os import subprocess import pytest import fit_util +import utils import re @pytest.mark.boardspec('sandbox') @@ -103,3 +104,59 @@ def test_fit_invalid_default_config(ubman): assert result.returncode != 0, "mkimage should fail due to missing default config" assert re.search(r"Default configuration '.*' not found under /configurations", result.stderr) + +@pytest.mark.boardspec('sandbox') +@pytest.mark.requiredtool('dtc') +@pytest.mark.requiredtool('fdtget') +@pytest.mark.parametrize('dtb_relpath,expected_desc', [ + # Crash triggers: last '.' precedes last '/', or leaf has no extension. + ('./mydt', 'mydt'), + ('./sub.d/leaf', 'leaf'), + ('./a.b/c', 'c'), + # Control case: extension lives in the leaf, no dotted directory. + ('./mydt.dtb', 'mydt'), +]) +def test_fit_auto_basename_dotted_directory(ubman, dtb_relpath, expected_desc): + """Regression test: mkimage -f auto must not crash when a -b path has a + '.' in its directory portion. + + Before the fix, get_basename() in tools/fit_image.c searched the whole + path for both the last '/' and the last '.'. When the '.' fell before + the '/', the computed length went negative and was passed unchanged to + memcpy(), which segfaulted. This test exercises three crashing paths + plus one control input. + """ + build_dir = ubman.config.build_dir + kernel = fit_util.make_kernel(ubman, 'kernel.bin', 'kernel') + itb_fname = fit_util.make_fname(ubman, 'auto_basename.itb') + + # Materialize the dtb at the requested relative path inside build_dir. + dtb_abs = os.path.join(build_dir, dtb_relpath) + os.makedirs(os.path.dirname(dtb_abs), exist_ok=True) + with open(dtb_abs, 'wb') as f: + f.write(b'dummy') + + cmd = ['./tools/mkimage', '-f', 'auto', + '-A', 'arm', '-O', 'linux', '-T', 'kernel', '-C', 'none', + '-a', '0x80000000', '-e', '0x80000000', '-n', 'test', + '-d', kernel, + '-b', dtb_relpath, + itb_fname] + # Run with cwd=build_dir so both ./tools/mkimage and the relative -b + # path resolve the same way the bug originally reproduced. + result = subprocess.run(cmd, capture_output=True, text=True, + cwd=build_dir) + + assert result.returncode == 0, ( + f"mkimage crashed or failed on -b {dtb_relpath!r}: " + f"rc={result.returncode}\nstdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + # The fdt sub-image description is set from get_basename(). Read it back + # from the produced FIT (a device tree) rather than parsing mkimage's + # console output. + desc = utils.run_and_log( + ubman, ['fdtget', itb_fname, '/images/fdt-1', 'description']).strip() + assert desc == expected_desc, ( + f"Expected /images/fdt-1 description {expected_desc!r}, got {desc!r}" + )