From 39fa55874151267a86b55095a4c83333d4fa2bc6 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Wed, 28 Jun 2023 14:34:28 -0500 Subject: [PATCH] check the config's CRC32 checksum while reading --- gp2040ce_bintools/storage.py | 14 ++++++++++++-- tests/test_storage.py | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/gp2040ce_bintools/storage.py b/gp2040ce_bintools/storage.py index 79169e1..eea6d53 100644 --- a/gp2040ce_bintools/storage.py +++ b/gp2040ce_bintools/storage.py @@ -1,5 +1,6 @@ """Interact with the protobuf config from a picotool flash dump of a GP2040-CE board.""" import argparse +import binascii import logging from google.protobuf.json_format import MessageToJson @@ -21,6 +22,10 @@ FOOTER_MAGIC = b'\x65\xe3\xf1\xd2' ################# +class ConfigCrcError(ValueError): + """Exception raised when the CRC checksum in the footer doesn't match the actual content's.""" + + class ConfigLengthError(ValueError): """Exception raised when a length sanity check fails.""" @@ -52,7 +57,7 @@ def get_config_footer(content: bytes) -> tuple[int, int, str]: Args: content: bytes from a GP2040-CE board's storage section Returns: - the discovered config size, config CRC, and magic from the config footer + the discovered config size, config CRC checksum, and magic from the config footer Raises: ConfigLengthError, ConfigMagicError: if the provided bytes are not a config footer """ @@ -70,10 +75,15 @@ def get_config_footer(content: bytes) -> tuple[int, int, str]: config_crc = int.from_bytes(reversed(footer[4:8]), 'big') config_magic = f'0x{footer[8:12].hex()}' - # one last sanity check + # more sanity checks if len(content) < config_size + FOOTER_SIZE: raise ConfigLengthError("provided content is not large enough according to the config footer!") + content_crc = binascii.crc32(content[-(config_size + 12):-12]) + if config_crc != content_crc: + raise ConfigCrcError(f"provided content CRC checksum {content_crc} does not match footer's expected CRC " + f"checksum {config_crc}!") + logger.debug("detected footer (size:%s, crc:%s, magic:%s", config_size, config_crc, config_magic) return config_size, config_crc, config_magic diff --git a/tests/test_storage.py b/tests/test_storage.py index 7c4666b..c3e6d39 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -56,6 +56,14 @@ def test_config_footer_bad_magic(storage_dump): _, _, _ = storage.get_config_footer(unmagical) +def test_config_footer_bad_crc(storage_dump): + """Test that a config footer isn't detected if the CRC checksums don't match.""" + corrupt = bytearray(storage_dump) + corrupt[-50:-40] = bytearray(0*10) + with pytest.raises(storage.ConfigCrcError): + _, _, _ = storage.get_config_footer(corrupt) + + def test_config_fails_without_pb2s(storage_dump): """Test that we need the config_pb2 to exist/be compiled for reading the config to work.""" with pytest.raises(ModuleNotFoundError):