Skip to content

Commit dd3a04b

Browse files
committed
added validation of expressions to prevent malicious code execution via eval()
At the point when eval is called, all symbols should have already been resolved to their values. That means we only need to allow for numeric characters along with arithmetic and bitwise operators, round brackets and whitespace. The character 'x' is also accepted to allow for hex numbers such as 0x123. If any other character is encountered the expression is deemed invalid. This change also removes the try/except around the eval. As all symbols have been resolved, the only thing that can be left is a valid expression. If it does not evaluate, an exception *should* be raised rather than being silently ignored (and hoping for an exception down the line).
1 parent 66eeb61 commit dd3a04b

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

esp32_ulp/opcodes.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from uctypes import struct, addressof, LITTLE_ENDIAN, UINT32, BFUINT32, BF_POS, BF_LEN
77

88
from .soc import *
9-
from .util import split_tokens
9+
from .util import split_tokens, validate_expression
1010

1111
# XXX dirty hack: use a global for the symbol table
1212
symbols = None
@@ -277,11 +277,9 @@ def eval_arg(arg):
277277
else:
278278
parts.append(token)
279279
parts = "".join(parts)
280-
try:
281-
parts = str(eval(parts))
282-
except:
283-
pass
284-
return parts
280+
if not validate_expression(parts):
281+
raise ValueError('Unsupported expression: %s' % parts)
282+
return str(eval(parts))
285283

286284

287285
def arg_qualify(arg):

esp32_ulp/util.py

+9
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,12 @@ def file_exists(filename):
5252
except:
5353
pass
5454
return False
55+
56+
57+
def validate_expression(param):
58+
for token in split_tokens(param):
59+
for c in token:
60+
if ('0' <= c <= '9') or c in ' \t+-*/%()<>&|^!~x':
61+
continue
62+
return False
63+
return True

tests/util.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
2-
from esp32_ulp.util import split_tokens, file_exists
2+
from esp32_ulp.util import split_tokens, file_exists, validate_expression
33

44
tests = []
55

@@ -31,6 +31,27 @@ def test_split_tokens():
3131
assert split_tokens("#test") == ['#', 'test']
3232

3333

34+
@test
35+
def test_validate_expression():
36+
assert validate_expression('') is True
37+
assert validate_expression('1') is True
38+
assert validate_expression('1+1') is True
39+
assert validate_expression('(1+1)') is True
40+
assert validate_expression('(1+1)*2') is True
41+
assert validate_expression('(1 + 1)') is True
42+
assert validate_expression('10 % 2') is True
43+
assert validate_expression('0x100 << 2') is True
44+
assert validate_expression('0x100~1') is True
45+
assert validate_expression('!1^2*3+4/5&6|7') is True
46+
assert validate_expression('(((((1+1) * 2') is True # valid characters, even if expression is not valid
47+
48+
assert validate_expression(':') is False
49+
assert validate_expression('_') is False
50+
assert validate_expression('=') is False
51+
assert validate_expression('.') is False
52+
assert validate_expression('0b1010') is False # binutils does not support encoding binary numbers like this
53+
54+
3455
@test
3556
def test_file_exists():
3657
testfile = '.testfile'

0 commit comments

Comments
 (0)