Sandboxing eval() (was: Calculator)
Grant Edwards
grant.b.edwards at gmail.com
Sun Jan 19 14:36:16 EST 2020
On 2020-01-19, Jon Ribbens via Python-list <python-list at python.org> wrote:
> On 2020-01-19, musbur at posteo.org <musbur at posteo.org> wrote:
>> Is it actually possible to build a "sandbox" around eval [...]
>>
>> [...]
>>
>> It works, but is it safe?
>
> No, not even slightly. If you want to do this you need to write your
> own interpreter that runs your own domain-specific language.
And for that, one is often pointed to the ast module as a starting
point. Here's an excerpt from an expression evaluator I wrote as part
of a two-pass symbolic assembler. [NB: it may have security issues
too, but they should be easier to find/fix than anything involving
eval()]
# evaluate an arithmetic expression in the context of the symbol table.
# only the operators in the table below are supported
import ast,operator
operators = \
{
# unary
ast.Invert: operator.invert,
ast.USub: operator.neg,
ast.UAdd: operator.pos,
# binary
ast.Add: operator.iadd,
ast.Sub: operator.isub,
ast.Mult: operator.imul,
ast.Div: operator.idiv,
ast.BitXor: operator.ixor,
ast.BitAnd: operator.iand,
ast.BitOr: operator.ior,
ast.LShift: operator.lshift,
ast.RShift: operator.rshift,
ast.Mod: operator.mod,
ast.Pow: operator.pow,
}
def _eval_expr(node):
global symbolTable, PC
if isinstance(node, ast.Name):
if node.id == "PC":
return PC
if node.id not in symbolTable:
raise Exception("name '%s' undefined" % node.id)
return symbolTable[node.id]
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.Str):
if len(node.s) != 1:
raise Exception("invalid string constant '%s' must be single character" % node.s)
return ord(node.s[0])
elif isinstance(node, ast.operator) or isinstance(node, ast.unaryop):
if type(node) not in operators:
errormsg(repr(dir(node)))
raise Exception("illegal operator '%s" % node)
return operators[type(node)]
elif isinstance(node, ast.BinOp):
return _eval_expr(node.op)(_eval_expr(node.left), _eval_expr(node.right))
elif isinstance(node, ast.UnaryOp):
return _eval_expr(node.op)(_eval_expr(node.operand))
else:
raise Exception("unsupported node type %s" % node)
def eval_expr(expr):
return _eval_expr(ast.parse(expr).body[0].value)
More information about the Python-list
mailing list