Skip to content

Commit 98f2ca6

Browse files
committed
crash-decode: do not eval() linker script memory expressions
The crash-decode helper evaluated arithmetic from a user-supplied linker script with eval(), so a crafted crash bundle could run arbitrary Python on the analyst's machine. Parse the expressions with a restricted evaluator that only accepts integer literals and basic arithmetic operators. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 3f7738d commit 98f2ca6

1 file changed

Lines changed: 38 additions & 2 deletions

File tree

scripts/sof-crash-decode.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,42 @@
3535
import os
3636
import json
3737
import shlex
38+
import ast
39+
import operator
40+
41+
42+
# Operators allowed when evaluating arithmetic from an untrusted linker script.
43+
_SAFE_OPS = {
44+
ast.Add: operator.add, ast.Sub: operator.sub,
45+
ast.Mult: operator.mul, ast.Div: operator.floordiv,
46+
ast.Mod: operator.mod, ast.LShift: operator.lshift,
47+
ast.RShift: operator.rshift, ast.BitOr: operator.or_,
48+
ast.BitAnd: operator.and_, ast.BitXor: operator.xor,
49+
ast.USub: operator.neg, ast.UAdd: operator.pos,
50+
}
51+
52+
53+
def safe_eval_int(expr):
54+
"""Evaluate an integer arithmetic expression without executing code.
55+
56+
A crash bundle's linker.cmd is attacker-controllable, so its MEMORY
57+
expressions must never be passed to eval(). Only integer literals and
58+
basic arithmetic operators are accepted; anything else raises ValueError.
59+
"""
60+
def _eval(node):
61+
if isinstance(node, ast.Expression):
62+
return _eval(node.body)
63+
if isinstance(node, ast.Constant):
64+
if isinstance(node.value, int):
65+
return node.value
66+
raise ValueError("non-integer constant")
67+
if isinstance(node, ast.BinOp) and type(node.op) in _SAFE_OPS:
68+
return _SAFE_OPS[type(node.op)](_eval(node.left), _eval(node.right))
69+
if isinstance(node, ast.UnaryOp) and type(node.op) in _SAFE_OPS:
70+
return _SAFE_OPS[type(node.op)](_eval(node.operand))
71+
raise ValueError("unsupported expression")
72+
73+
return _eval(ast.parse(expr, mode='eval'))
3874

3975
XTENSA_EXCCAUSE = {
4076
0: "No Error (or IllegalInstruction)",
@@ -151,8 +187,8 @@ def parse_linker_cmd(filepath):
151187
org_expr = m_org.group(1).strip()
152188
len_expr = m_len.group(1).strip()
153189
try:
154-
org_val = eval(org_expr)
155-
len_val = eval(len_expr)
190+
org_val = safe_eval_int(org_expr)
191+
len_val = safe_eval_int(len_expr)
156192
# Ignore debug regions
157193
if not (name.startswith('.debug') or name.startswith('.stab')):
158194
regions.append({'name': name, 'start': org_val, 'end': org_val + len_val})

0 commit comments

Comments
 (0)