diff --git a/leep/cli.py b/leep/cli.py index 1a3e95f..5eb2a8a 100644 --- a/leep/cli.py +++ b/leep/cli.py @@ -43,27 +43,16 @@ def parseTransaction(xact): Example Implied Transaction ------------------------------------------- regname Read from named register (str) 'regname' - regaddr Read from explicit address (int) 'regaddr' regname=val Write (int) 'val' to named register (str) 'regname' - regaddr=val Write (int) 'val' to explicit address (int) 'regaddr' regname=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at the address of named register (str) 'regname' - regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at - address (int) 'regaddr' regname+offset Read from address = romx['regname']['base_addr'] + (int) 'offset' - regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset' regname:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] - regaddr:size Read (int) 'size' elements starting from (int) 'regaddr' regname+offset=val Write (int) 'val' to address romx['regname']['base_addr'] + (int) 'offset' regname+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at address romx['regname']['base_addr'] + (int) 'offset' - regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset' - regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at - address (int) 'regaddr' regname+offset:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] + \ (int) 'offset' - regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset' - I'm not sure what use case the "regaddr+offset" syntax supports, but it does no harm to include it. NOTE! Deliberately not supporting "regname-offset" (negative offsets) as it's use case is unclear and a '_' to '-' typo could potentially collide with legitimate transactions. """ @@ -74,13 +63,16 @@ def parseTransaction(xact): size = None if _match: groups = _match.groups() - regstr = groups[0] # Always starts with 'regname' or 'regaddr' + regstr = groups[0] # Always starts with 'regname' + if regstr.isdigit() or regstr.lower().startswith("0x") or regstr.lower().startswith("0b"): + raise ValueError("Absolute numeric addresses are not allowed. Use symbolic register names instead.") if groups[1] == '=': wval = _expandWriteVals(groups[2]) elif groups[1] == '+': offset = _int(groups[2]) elif groups[1] == ':': size = _int(groups[2]) + if groups[3] == '=': if groups[1] == '=': raise Exception("Malformed transaction: {}".format(xact)) @@ -91,15 +83,9 @@ def parseTransaction(xact): size = _int(groups[4]) else: raise Exception("Failed to match: {}".format(xact)) - try: - reg = _int(regstr) - except ValueError: - reg = regstr + reg = regstr if size is None: - if wval is None: - size = None - else: - size = 0 + size = 0 if wval is not None else None return (reg, offset, size, wval) diff --git a/leep/raw.py b/leep/raw.py index 7305d75..d5c63ae 100644 --- a/leep/raw.py +++ b/leep/raw.py @@ -106,20 +106,12 @@ def log2(n): def _int(s): + if isinstance(s, str) and (s.isdigit() or s.lower().startswith(('0x', '0b'))): + raise ValueError("Absolute numeric addressing is not allowed. Use symbolic register names instead.") try: - # Catch actual ints return int(s) except ValueError: - pass - if hasattr(s, 'startswith'): - try: - if s.startswith('0x'): - return int(s, 16) - elif s.startswith('0b'): - return int(s, 2) - except ValueError: - pass - return None + return None class LEEPDevice(DeviceBase): @@ -176,9 +168,11 @@ def _decode(self, reg, instance=[]): "data_width": 32, "sign": "unsigned", } + if isinstance(reg, str) and (reg.isdigit() or reg.lower().startswith(('0x', '0b'))): + raise ValueError("Absolute numeric addressing is not allowed. Use symbolic register names instead.") _reg = _int(reg) if _reg is not None: - return "0x{:x}".format(_reg), _reg, 1, info + raise ValueError("Absolute numeric addressing is not allowed. Use symbolic register names instead.") if instance is not None: reg = self.expand_regname(reg, instance=instance) info = self.get_reg_info(reg, instance=None) diff --git a/leep/test/test_cli.py b/leep/test/test_cli.py index d78e6e8..74fe2f2 100644 --- a/leep/test/test_cli.py +++ b/leep/test/test_cli.py @@ -238,46 +238,48 @@ def test_parseTransaction(): # CLI string: result (reg, offset, read_size, write_vals) # regname Read from named register (str) 'regname' "foo": ("foo", 0, None, None), - # regaddr Read from explicit address (int) 'regaddr' - "0x100": (0x100, 0, None, None), # regname=val Write (int) 'val' to named register (str) 'regname' "foo=42": ("foo", 0, 0, 42), "bar=0x42": ("bar", 0, 0, 0x42), "foo_baz=0b100": ("foo_baz", 0, 0, 0b100), - # regaddr=val Write (int) 'val' to explicit address (int) 'regaddr' - "0x123=100": (0x123, 0, 0, 100), - "123=0xabc": (123, 0, 0, 0xabc), - "0b1010=-10": (0b1010, 0, 0, -10), # regname=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at the # address of named register (str) 'regname' "reg_foo=1,2,3,4,5": ("reg_foo", 0, 0, [1, 2, 3, 4, 5]), - # regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at - # address (int) 'regaddr' - "0x4000=1,-1,0,42,0x10": (0x4000, 0, 0, [1, -1, 0, 42, 0x10]), # regname+offset Read from address = romx['regname']['base_addr'] + (int) 'offset' "BINGO+100": ("BINGO", 100, None, None), - # regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset' - "0x100+100": (0x100, 100, None, None), # regname:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] "_reg_:32": ("_reg_", 0, 32, None), - # regaddr:size Read (int) 'size' elements starting from (int) 'regaddr' - "0:0xff": (0, 0, 0xff, None), # regname+offset=val Write (int) 'val' to address romx['regname']['base_addr'] + (int) 'offset' "bandit+0x100=5000": ("bandit", 0x100, 0, 5000), # regname+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at # address romx['regname']['base_addr'] + (int) 'offset' "status+0x20=50,40,0x30": ("status", 0x20, 0, [50, 40, 0x30]), - # regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset' - "128+0xc0=-1000": (128, 0xc0, 0, -1000), - # regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at - # address (int) 'regaddr' - "0x128+0xc0=1,0,1,0,2": (0x128, 0xc0, 0, [1, 0, 1, 0, 2]), # regname+offset:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] + \ # (int) 'offset' "Socks+0x100:100": ("Socks", 0x100, 100, None), - # regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset' - "0x4000+15:0b1111": (0x4000, 15, 0b1111, None), } + bads = [ + # regaddr Read from explicit address (int) 'regaddr' + "0x100", + # regaddr=val Write (int) 'val' to explicit address (int) 'regaddr' + "0x123=100", + "123=0xabc", + "0b1010=-10", + # regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at + # address (int) 'regaddr' + "0x4000=1,-1,0,42,0x10", + # regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset' + "0x100+100", + # regaddr:size Read (int) 'size' elements starting from (int) 'regaddr' + "0:0xff", + # regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset' + "128+0xc0=-1000", + # regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at + # address (int) 'regaddr' + "0x128+0xc0=1,0,1,0,2", + # regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset' + "0x4000+15:0b1111", + ] errors = 0 for _input, _expected in dd.items(): try: @@ -287,6 +289,17 @@ def test_parseTransaction(): if result != _expected: print("Failed on input: {}.\n Expected: {}\n Result: {}".format(_input, _expected, result)) errors += 1 + + for _input in bads: + try: + result = parseTransaction(_input) + print(f"Expected an exception for input: { _input } but got {result}") + errors += 1 + except ValueError: + pass + except Exception as ex: + print(f"Unexpected exception for input: { _input }: { ex }") + errors += 1 return errors @@ -318,4 +331,8 @@ def runServer(args): parserTest = subparsers.add_parser("test", help="Run regression tests.") parserTest.set_defaults(handler=doTests) args = parser.parse_args() - sys.exit(args.handler(args)) + try: + args.handler(args) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) diff --git a/leep/test/test_raw.py b/leep/test/test_raw.py index 6c15f8d..0adb987 100644 --- a/leep/test/test_raw.py +++ b/leep/test/test_raw.py @@ -1,4 +1,3 @@ - import logging import unittest @@ -195,15 +194,21 @@ def test_raw_int(): from leep.raw import _int tests = { "foo": None, - "123": 123, - "0x100": 0x100, - "0b1000": 0b1000, + "123": 123, # should raise error + "0x100": 0x100, # should raise error + "0b1000": 0b1000, # should raise error "0xreg": None, "0bentry": None, } - for key, val in tests.items(): - if val != _int(key): - raise Exception("Test failed _int({}) = {} != {}".format(key, _int(key), val)) + for key in tests: + try: + result = _int(key) + if result is not None: + print(f"Found passing absolute numeric address: {key} -> {result}") + raise Exception(f"Test failed _int({key}) = {result} (accepted when it shouldn't)") + except ValueError: + print(f"Expected ValueError for input '{key}' detected, as intended") + continue return True