diff --git a/calc_sums.c b/calc_sums.c index aae1ce96..2084c0be 100644 --- a/calc_sums.c +++ b/calc_sums.c @@ -275,8 +275,11 @@ int calc_sums(struct file_info* info) int find_embedded_crc32(file_t* file, unsigned* crc32) { const char* filepath = file_get_print_path(file, FPathUtf8 | FPathNotNull); - const char* e = filepath + strlen(filepath) - 10; + size_t filepath_length = strlen(filepath); + const char* e; unsigned char raw[4]; + if (filepath_length < 10) return 0; + e = filepath + filepath_length - 10; /* search for the sum enclosed in brackets */ for (; e >= filepath && !IS_PATH_SEPARATOR(*e); e--) { @@ -289,8 +292,10 @@ int find_embedded_crc32(file_t* file, unsigned* crc32) ((unsigned)raw[2] << 8) | (unsigned)raw[3]; return 1; } + if (e - filepath < 10) break; e -= 9; } + if (e == filepath) break; } return 0; } diff --git a/tests/test_embedded_crc_bounds.py b/tests/test_embedded_crc_bounds.py new file mode 100644 index 00000000..3863aee0 --- /dev/null +++ b/tests/test_embedded_crc_bounds.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +from pathlib import Path +import subprocess +import sys +import tempfile +import zlib + +binary = str(Path(sys.argv[1]).resolve()) +crc_value = zlib.crc32(b"A") +crc = f"{crc_value:08X}" +cases = [("a", False), ("123456789", False), ("1234567890", False), + (f"[{crc}]", True), (f"({crc})", True), + (f"prefix_[{crc}].data", True), (f"[{crc}][ZZZZZZZZ]", True), + ("[ZZZZZZZZ]", False), ("x[ZZZZZZZZ]", False), + (f"[{crc}]/plain.data", False), (f"nested/[{crc}].data", True)] +with tempfile.TemporaryDirectory() as directory: + for index, (name, expected) in enumerate(cases): + case_directory = Path(directory, str(index)) + path = case_directory / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(b"A") + result = subprocess.run([binary, "--check-embedded", name], cwd=case_directory, + capture_output=True, text=True, timeout=10) + successful = "OK" in result.stdout and result.returncode == 0 + assert successful == expected, (name, result.returncode, result.stdout, result.stderr) +print(f"PASS: {len(cases)} embedded CRC filename cases") diff --git a/tests/test_embedded_crc_short_paths.py b/tests/test_embedded_crc_short_paths.py new file mode 100644 index 00000000..90119324 --- /dev/null +++ b/tests/test_embedded_crc_short_paths.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +import os +from pathlib import Path +import subprocess +import sys +import tempfile + +binary = str(Path(sys.argv[1]).resolve()) +env = dict(os.environ, ASAN_OPTIONS="detect_invalid_pointer_pairs=2") +with tempfile.TemporaryDirectory() as directory: + Path(directory, "a").write_bytes(b"A") + result = subprocess.run([binary, "--check-embedded", "a"], cwd=directory, + env=env, capture_output=True, text=True, timeout=10) + assert result.returncode == 1, (result.returncode, result.stderr) + assert "file name doesn't contain a CRC32" in result.stderr, result.stderr + assert "invalid-pointer-pair" not in result.stderr, result.stderr +print("PASS: short filename is rejected without invalid pointer comparison")