def visitPrint(self, node, walker): """Checks and mutates a print statement. Adds a target to all print statements. 'print foo' becomes 'print >> _print, foo', where _print is the default print target defined for this scope. Alternatively, if the untrusted code provides its own target, we have to check the 'write' method of the target. 'print >> ob, foo' becomes 'print >> (_getattr(ob, 'write') and ob), foo'. Otherwise, it would be possible to call the write method of templates and scripts; 'write' happens to be the name of the method that changes them. """ node = walker.defaultVisitNode(node) self.funcinfo.print_used = True if node.dest is None: node.dest = _print_target_name else: # Pre-validate access to the "write" attribute. # "print >> ob, x" becomes # "print >> (_getattr(ob, 'write') and ob), x" node.dest = ast.And([ ast.CallFunc(_getattr_name, [node.dest, _write_const]), node.dest ]) return node
def visitAugAssign(self, node, walker): """Makes a note that augmented assignment is in use. Note that although augmented assignment of attributes and subscripts is disallowed, augmented assignment of names (such as 'n += 1') is allowed. This could be a problem if untrusted code got access to a mutable database object that supports augmented assignment. """ if node.node.__class__.__name__ == 'Name': node = walker.defaultVisitNode(node) newnode = ast.Assign( [ast.AssName(node.node.name, OP_ASSIGN)], ast.CallFunc(_inplacevar_name, [ ast.Const(node.op), ast.Name(node.node.name), node.expr, ]), ) newnode.lineno = node.lineno return newnode else: node.node.in_aug_assign = True return walker.defaultVisitNode(node)
def visitSubscript(self, node, walker): """Checks all kinds of subscripts. 'foo[bar] += baz' is disallowed. 'a = foo[bar, baz]' becomes 'a = _getitem(foo, (bar, baz))'. 'a = foo[bar]' becomes 'a = _getitem(foo, bar)'. 'a = foo[bar:baz]' becomes 'a = _getitem(foo, slice(bar, baz))'. 'a = foo[:baz]' becomes 'a = _getitem(foo, slice(None, baz))'. 'a = foo[bar:]' becomes 'a = _getitem(foo, slice(bar, None))'. 'del foo[bar]' becomes 'del _write(foo)[bar]'. 'foo[bar] = a' becomes '_write(foo)[bar] = a'. The _write function returns a security proxy. """ node = walker.defaultVisitNode(node) if node.flags == OP_APPLY: # Set 'subs' to the node that represents the subscript or slice. if getattr(node, 'in_aug_assign', False): # We're in an augmented assignment # We might support this later... self.error( node, 'Augmented assignment of ' 'object items and slices is not allowed.') if hasattr(node, 'subs'): # Subscript. subs = node.subs if len(subs) > 1: # example: ob[1,2] subs = ast.Tuple(subs) else: # example: ob[1] subs = subs[0] else: # Slice. # example: obj[0:2] lower = node.lower if lower is None: lower = _None_const upper = node.upper if upper is None: upper = _None_const subs = ast.Sliceobj([lower, upper]) return ast.CallFunc(_getitem_name, [node.expr, subs]) elif node.flags in (OP_DELETE, OP_ASSIGN): # set or remove subscript or slice node.expr = ast.CallFunc(_write_name, [node.expr]) return node
def visitGenExprFor(self, node, walker): # convert # (... for x in expr ...) # to # (... for x in _getiter(expr) ...) node = walker.defaultVisitNode(node) node.iter = ast.CallFunc(_getiter_name, [node.iter]) return node
def visitAssAttr(self, node, walker): """Checks and mutates attribute assignment. 'a.b = c' becomes '_write(a).b = c'. The _write function returns a security proxy. """ self.checkAttrName(node) node = walker.defaultVisitNode(node) node.expr = ast.CallFunc(_write_name, [node.expr]) return node
def visitFor(self, node, walker): # convert # for x in expr: # to # for x in _getiter(expr): # # Note that visitListCompFor is the same thing. # # Also for list comprehensions: # [... for x in expr ...] # to # [... for x in _getiter(expr) ...] node = walker.defaultVisitNode(node) node.list = ast.CallFunc(_getiter_name, [node.list]) return node
def visitGetattr(self, node, walker): """Converts attribute access to a function call. 'foo.bar' becomes '_getattr(foo, "bar")'. Also prevents augmented assignment of attributes, which would be difficult to support correctly. """ self.checkAttrName(node) node = walker.defaultVisitNode(node) if getattr(node, 'in_aug_assign', False): # We're in an augmented assignment # We might support this later... self.error(node, 'Augmented assignment of ' 'attributes is not allowed.') return ast.CallFunc(_getattr_name, [node.expr, ast.Const(node.attrname)])