Merge pull request #799 from markshannon/python-api-tidy-up

Python API tidy up, part 1
This commit is contained in:
Taus
2019-02-21 13:25:17 +01:00
committed by GitHub
72 changed files with 244 additions and 212 deletions

View File

@@ -67,9 +67,9 @@ predicate subscript(Stmt s) {
predicate encode_decode(Expr ex, ClassObject type) {
exists(string name |
ex.(Call).getFunc().(Attribute).getName() = name |
name = "encode" and type = builtin_object("UnicodeEncodeError")
name = "encode" and type = Object::builtin("UnicodeEncodeError")
or
name = "decode" and type = builtin_object("UnicodeDecodeError")
name = "decode" and type = Object::builtin("UnicodeDecodeError")
)
}

View File

@@ -3,9 +3,9 @@ import python
/** Holds if `notimpl` refers to `NotImplemented` or `NotImplemented()` in the `raise` statement */
predicate use_of_not_implemented_in_raise(Raise raise, Expr notimpl) {
notimpl.refersTo(theNotImplementedObject()) and
notimpl.refersTo(Object::notImplemented()) and
(
notimpl = raise.getException() or
notimpl = raise.getException() or
notimpl = raise.getException().(Call).getFunc()
)
}

View File

@@ -13,11 +13,11 @@
import python
FunctionObject iter() {
result = builtin_object("iter")
result = Object::builtin("iter")
}
FunctionObject next() {
result = builtin_object("next")
result = Object::builtin("next")
}
predicate call_to_iter(CallNode call, EssaVariable sequence) {

View File

@@ -107,7 +107,7 @@ private predicate brace_pair(PossibleAdvancedFormatString fmt, int start, int en
private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatString fmt, int args) {
exists(CallNode call |
call = format_expr.getAFlowNode() |
call.getFunction().refersTo(theFormatFunction()) and call.getArg(0).refersTo(_, fmt.getAFlowNode()) and
call.getFunction().refersTo(Object::builtin("format")) and call.getArg(0).refersTo(_, fmt.getAFlowNode()) and
args = count(format_expr.getAnArg()) - 1
or
call.getFunction().(AttrNode).getObject("format").refersTo(_, fmt.getAFlowNode()) and

View File

@@ -19,7 +19,7 @@ import python
predicate numpy_array_type(ClassObject na) {
exists(ModuleObject np | np.getName() = "numpy" or np.getName() = "numpy.core" |
na.getAnImproperSuperType() = np.getAttribute("ndarray")
na.getAnImproperSuperType() = np.attr("ndarray")
)
}

View File

@@ -13,5 +13,5 @@ import python
from CallNode call, ControlFlowNode func
where
major_version() = 2 and call.getFunction() = func and func.refersTo(theApplyFunction())
major_version() = 2 and call.getFunction() = func and func.refersTo(Object::builtin("apply"))
select call, "Call to the obsolete builtin function 'apply'."

View File

@@ -14,5 +14,5 @@ import python
from CallNode call, Context context, ControlFlowNode func
where
context.getAVersion().includes(2, _) and call.getFunction() = func and func.refersTo(context, theInputFunction(), _, _)
context.getAVersion().includes(2, _) and call.getFunction() = func and func.refersTo(context, Object::builtin("input"), _, _)
select call, "The unsafe built-in function 'input' is used."

View File

@@ -70,11 +70,11 @@ predicate correct_raise(string name, ClassObject ex) {
predicate preferred_raise(string name, ClassObject ex) {
attribute_method(name) and ex = theAttributeErrorType()
or
indexing_method(name) and ex = builtin_object("LookupError")
indexing_method(name) and ex = Object::builtin("LookupError")
or
ordering_method(name) and ex = theTypeErrorType()
or
arithmetic_method(name) and ex = builtin_object("ArithmeticError")
arithmetic_method(name) and ex = Object::builtin("ArithmeticError")
}
predicate no_need_to_raise(string name, string message) {

View File

@@ -128,7 +128,7 @@ predicate function_should_close_parameter(Function func) {
}
predicate function_opens_file(FunctionObject f) {
f = theOpenFunction()
f = Object::builtin("open")
or
exists(EssaVariable v, Return ret |
ret.getScope() = f.getFunction() |

View File

@@ -15,7 +15,7 @@ import python
ClassObject jinja2EnvironmentOrTemplate() {
exists(ModuleObject jinja2, string name |
jinja2.getName() = "jinja2" and
jinja2.getAttribute(name) = result |
jinja2.attr(name) = result |
name = "Environment" or
name = "Template"
)

View File

@@ -17,7 +17,7 @@ import semmle.python.web.Http
FunctionObject requestFunction() {
exists(ModuleObject req |
req.getName() = "requests" and
result = req.getAttribute(httpVerbLower())
result = req.attr(httpVerbLower())
)
}

View File

@@ -21,7 +21,7 @@ int minimumSecureKeySize(string algo) {
predicate dsaRsaKeySizeArg(FunctionObject obj, string algorithm, string arg) {
exists(ModuleObject mod |
mod.getAttribute(_) = obj |
mod.attr(_) = obj |
algorithm = "DSA" and
(
mod.getName() = "cryptography.hazmat.primitives.asymmetric.dsa" and arg = "key_size"
@@ -44,7 +44,7 @@ predicate dsaRsaKeySizeArg(FunctionObject obj, string algorithm, string arg) {
predicate ecKeySizeArg(FunctionObject obj, string arg) {
exists(ModuleObject mod |
mod.getAttribute(_) = obj |
mod.attr(_) = obj |
mod.getName() = "cryptography.hazmat.primitives.asymmetric.ec" and arg = "curve"
)
}

View File

@@ -13,11 +13,11 @@
import python
FunctionObject ssl_wrap_socket() {
result = any(ModuleObject ssl | ssl.getName() = "ssl").getAttribute("wrap_socket")
result = any(ModuleObject ssl | ssl.getName() = "ssl").attr("wrap_socket")
}
ClassObject ssl_Context_class() {
result = any(ModuleObject ssl | ssl.getName() = "ssl").getAttribute("SSLContext")
result = any(ModuleObject ssl | ssl.getName() = "ssl").attr("SSLContext")
}
CallNode unsafe_call(string method_name) {

View File

@@ -12,11 +12,11 @@
import python
FunctionObject ssl_wrap_socket() {
result = the_ssl_module().getAttribute("wrap_socket")
result = the_ssl_module().attr("wrap_socket")
}
ClassObject ssl_Context_class() {
result = the_ssl_module().getAttribute("SSLContext")
result = the_ssl_module().attr("SSLContext")
}
string insecure_version_name() {
@@ -69,20 +69,20 @@ predicate unsafe_ssl_wrap_socket_call(CallNode call, string method_name, string
insecure_version = insecure_version_name()
and
(
call.getArgByName("ssl_version").refersTo(the_ssl_module().getAttribute(insecure_version))
call.getArgByName("ssl_version").refersTo(the_ssl_module().attr(insecure_version))
or
probable_insecure_ssl_constant(call, insecure_version)
)
}
ClassObject the_pyOpenSSL_Context_class() {
result = any(ModuleObject m | m.getName() = "pyOpenSSL.SSL").getAttribute("Context")
result = any(ModuleObject m | m.getName() = "pyOpenSSL.SSL").attr("Context")
}
predicate unsafe_pyOpenSSL_Context_call(CallNode call, string insecure_version) {
call = the_pyOpenSSL_Context_class().getACall() and
insecure_version = insecure_version_name() and
call.getArg(0).refersTo(the_pyOpenSSL_module().getAttribute(insecure_version))
call.getArg(0).refersTo(the_pyOpenSSL_module().attr(insecure_version))
}
from CallNode call, string method_name, string insecure_version

View File

@@ -35,12 +35,12 @@ string permissive_permission(int p) {
}
predicate chmod_call(CallNode call, FunctionObject chmod, NumericObject num) {
any(ModuleObject os | os.getName() = "os").getAttribute("chmod") = chmod and
any(ModuleObject os | os.getName() = "os").attr("chmod") = chmod and
chmod.getACall() = call and call.getArg(1).refersTo(num)
}
predicate open_call(CallNode call, FunctionObject open, NumericObject num) {
any(ModuleObject os | os.getName() = "os").getAttribute("open") = open and
any(ModuleObject os | os.getName() = "os").attr("open") = open and
open.getACall() = call and call.getArg(2).refersTo(num)
}

View File

@@ -34,7 +34,7 @@ predicate fewer_characters_than(StrConst str, string char, float fraction) {
}
predicate possible_reflective_name(string name) {
exists(any(ModuleObject m).getAttribute(name))
exists(any(ModuleObject m).attr(name))
or
exists(any(ClassObject c).lookupAttribute(name))
or
@@ -42,7 +42,7 @@ predicate possible_reflective_name(string name) {
or
any(ModuleObject m).getName() = name
or
exists(builtin_object(name))
exists(Object::builtin(name))
}
int char_count(StrConst str) {

View File

@@ -39,14 +39,14 @@ predicate maybe_defined_in_outer_scope(Name n) {
}
Variable relevant_var(Name n) {
n.getVariable() = result and
(corresponding(n, _) or corresponding(_, n))
n.getVariable() = result and
(corresponding(n, _) or corresponding(_, n))
}
predicate same_name(Name n1, Name n2) {
corresponding(n1, n2) and
relevant_var(n1) = relevant_var(n2) and
not exists(builtin_object(n1.getId())) and
not exists(Object::builtin(n1.getId())) and
not maybe_defined_in_outer_scope(n2)
}

View File

@@ -84,7 +84,7 @@ predicate in_notebook(Expr e) {
}
FunctionObject assertRaises() {
result = ModuleObject::named("unittest").getAttribute("TestCase").(ClassObject).lookupAttribute("assertRaises")
result = ModuleObject::named("unittest").attr("TestCase").(ClassObject).lookupAttribute("assertRaises")
}
/** Holds if expression `e` is in a `with` block that tests for exceptions being raised. */

View File

@@ -12,5 +12,5 @@
import python
from CallNode call, string name
where call.getFunction().refersTo(quitterObject(name))
where call.getFunction().refersTo(Object::quitter(name))
select call, "The '" + name + "' site.Quitter object may not exist if the 'site' module is not loaded or is modified."

View File

@@ -15,7 +15,7 @@ predicate monkey_patched_builtin(string name) {
bltn.refersTo(theBuiltinModuleObject()) and
call.getArg(1).getNode() = s and
s.getText() = name and
call.getFunction().refersTo(builtin_object("setattr"))
call.getFunction().refersTo(Object::builtin("setattr"))
)
or
exists(AttrNode attr |

View File

@@ -45,7 +45,7 @@ predicate white_list(string name) {
predicate shadows(Name d, string name, Scope scope, int line) {
exists(LocalVariable l | d.defines(l) and scope instanceof Function and
l.getId() = name and
exists(builtin_object(l.getId()))
exists(Object::builtin(l.getId()))
) and
d.getScope() = scope and
d.getLocation().getStartLine() = line and

View File

@@ -21,7 +21,7 @@ predicate shadows(Name d, GlobalVariable g, Scope scope, int line) {
not exists(Import il, Import ig, Name gd | il.contains(d) and gd.defines(g) and ig.contains(gd)) and
not exists(Assign a | a.getATarget() = d and a.getValue() = g.getAnAccess())
) and
not exists(builtin_object(g.getId())) and
not exists(Object::builtin(g.getId())) and
d.getScope() = scope and
d.getLocation().getStartLine() = line and
exists(Name defn | defn.defines(g) |

View File

@@ -47,8 +47,8 @@ predicate one_item_only(For f) {
predicate points_to_call_to_range(ControlFlowNode f) {
/* (x)range is a function in Py2 and a class in Py3, so we must treat it as a plain object */
exists(Object range, Object call |
range = builtin_object("range") or
range = builtin_object("xrange")
range = Object::builtin("range") or
range = Object::builtin("xrange")
|
f.refersTo(call) and
call.(CallNode).getFunction().refersTo(range)

View File

@@ -24,7 +24,7 @@ predicate declaredInAll(Module m, StrConst name)
predicate mutates_globals(PythonModuleObject m) {
exists(CallNode globals |
globals = theGlobalsFunction().(FunctionObject).getACall() and
globals = Object::builtin("globals").(FunctionObject).getACall() and
globals.getScope() = m.getModule() |
exists(AttrNode attr | attr.getObject() = globals)
or

View File

@@ -90,8 +90,8 @@ predicate use_of_exec(Module m) {
or
exists(CallNode call, FunctionObject exec |
exec.getACall() = call and call.getScope() = m |
exec = builtin_object("exec") or
exec = builtin_object("execfile")
exec = Object::builtin("exec") or
exec = Object::builtin("execfile")
)
}

View File

@@ -109,7 +109,7 @@ private Object attribute_in_scope(Object obj, string name) {
or
exists(ModuleObject mod |
mod = obj |
mod.getAttribute(name) = result and result.(ControlFlowNode).getScope() = mod.getModule()
mod.attr(name) = result and result.(ControlFlowNode).getScope() = mod.getModule()
and not result.(ControlFlowNode).isEntryNode()
)
}

View File

@@ -396,7 +396,7 @@ private predicate attribute_assignment_jump_to_defn_attribute(AttributeAssignmen
private predicate sets_attribute(ArgumentRefinement def, string name) {
exists(CallNode call |
call = def.getDefiningNode() and
call.getFunction().refersTo(builtin_object("setattr")) and
call.getFunction().refersTo(Object::builtin("setattr")) and
def.getInput().getAUse() = call.getArg(0) and
call.getArg(1).getNode().(StrConst).getText() = name
)

View File

@@ -201,7 +201,7 @@ private predicate gettext_installed() {
}
private predicate builtin_constant(string name) {
exists(builtin_object(name))
exists(Object::builtin(name))
or
name = "WindowsError"
or

View File

@@ -21,7 +21,7 @@ abstract class ExternalPackage extends Object {
abstract string getVersion();
Object getAttribute(string name) {
result = this.(ModuleObject).getAttribute(name)
result = this.(ModuleObject).attr(name)
}
PackageObject getPackage() {

View File

@@ -7,7 +7,7 @@ class UnitTestClass extends TestScope {
UnitTestClass() {
exists(ClassObject c |
this = c.getPyClass() |
c.getASuperType() = theUnitTestPackage().getAttribute(_)
c.getASuperType() = theUnitTestPackage().attr(_)
or
c.getASuperType().getName().toLowerCase() = "testcase"
)

View File

@@ -8,7 +8,7 @@ class ZopeInterfaceMethod extends PyFunctionObject {
/** Holds if this method belongs to a class that sub-classes `zope.interface.Interface` */
ZopeInterfaceMethod() {
exists(Object interface, ClassObject owner |
ModuleObject::named("zope.interface").getAttribute("Interface") = interface and
interface = ModuleObject::named("zope.interface").attr("Interface") and
owner.declaredAttribute(_) = this and
owner.getAnImproperSuperType().getABaseType() = interface
)

View File

@@ -196,7 +196,7 @@ predicate function_can_never_return(FunctionObject func) {
not exists(f.getAnExitNode())
)
or
func = theExitFunctionObject()
func = ModuleObject::named("sys").attr("exit")
}
/** Python specific sub-class of generic EssaNodeDefinition */
@@ -570,13 +570,13 @@ predicate potential_builtin_points_to(NameNode f, Object value, ClassObject cls,
(
builtin_name_points_to(f.getId(), value, cls)
or
not exists(builtin_object(f.getId())) and value = unknownValue() and cls = theUnknownType()
not exists(Object::builtin(f.getId())) and value = unknownValue() and cls = theUnknownType()
)
}
pragma [noinline]
predicate builtin_name_points_to(string name, Object value, ClassObject cls) {
value = builtin_object(name) and py_cobjecttypes(value, cls)
value = Object::builtin(name) and py_cobjecttypes(value, cls)
}
module BaseFlow {

View File

@@ -322,7 +322,7 @@ module PointsTo {
/** Holds if `call` is of the form `getattr(arg, "name")`. */
cached predicate getattr(CallNode call, ControlFlowNode arg, string name) {
points_to(call.getFunction(), _, builtin_object("getattr"), _, _) and
points_to(call.getFunction(), _, Object::builtin("getattr"), _, _) and
call.getArg(1).getNode().(StrConst).getText() = name and
arg = call.getArg(0)
}
@@ -1110,9 +1110,9 @@ module PointsTo {
pragma [noinline]
predicate call_points_to_builtin_function(CallNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
exists(BuiltinCallable b |
b != builtin_object("isinstance") and
b != builtin_object("issubclass") and
b != builtin_object("callable") and
b != Object::builtin("isinstance") and
b != Object::builtin("issubclass") and
b != Object::builtin("callable") and
f = get_a_call(b, context) and
cls = b.getAReturnType()
) and
@@ -2007,9 +2007,9 @@ module PointsTo {
exists(ControlFlowNode func, Object obj |
two_args_first_arg_string(def, func, name) and
points_to(func, _, obj, _, _) |
obj = builtin_object("setattr") and result = true
obj = Object::builtin("setattr") and result = true
or
obj != builtin_object("setattr") and result = false
obj != Object::builtin("setattr") and result = false
)
}
@@ -2349,7 +2349,7 @@ module PointsTo {
(
exists(CallNode call |
call = expr and
points_to(call.getFunction(), context, theLenFunction(), _, _) and
points_to(call.getFunction(), context, Object::builtin("len"), _, _) and
use = call.getArg(0) and
val.(SequenceObject).getLength() = result
)

View File

@@ -18,7 +18,7 @@ predicate used_as_regex(Expr s, string mode) {
/* Call to re.xxx(regex, ... [mode]) */
exists(CallNode call, string name |
call.getArg(0).refersTo(_, _, s.getAFlowNode()) and
call.getFunction().refersTo(re.getAttribute(name)) |
call.getFunction().refersTo(re.attr(name)) |
mode = "None"
or
exists(Object obj |
@@ -40,7 +40,7 @@ string mode_from_mode_object(Object obj) {
result = "MULTILINE" or result = "DOTALL" or result = "UNICODE" or
result = "VERBOSE"
) and
ModuleObject::named("sre_constants").getAttribute("SRE_FLAG_" + result) = obj
obj = ModuleObject::named("sre_constants").attr("SRE_FLAG_" + result)
or
exists(BinaryExpr be, Object sub | obj.getOrigin() = be |
be.getOp() instanceof BitOr and

View File

@@ -95,7 +95,7 @@ module Cryptography {
class CipherClass extends ClassObject {
CipherClass() {
ciphers().getAttribute("Cipher") = this
ciphers().attr("Cipher") = this
}
}
@@ -103,7 +103,7 @@ module Cryptography {
class AlgorithmClass extends ClassObject {
AlgorithmClass() {
ciphers().submodule("algorithms").getAttribute(_) = this
ciphers().submodule("algorithms").attr(_) = this
}
string getAlgorithmName() {

View File

@@ -12,7 +12,7 @@ private ModuleObject theTracebackModule() {
}
private FunctionObject traceback_function(string name) {
result = theTracebackModule().getAttribute(name)
result = theTracebackModule().attr(name)
}
/**

View File

@@ -242,11 +242,11 @@ private predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
or
exists(ModuleObject copy, string name |
name = "copy" or name = "deepcopy" |
copy.getAttribute(name).(FunctionObject).getACall() = tonode and
copy.attr(name).(FunctionObject).getACall() = tonode and
tonode.getArg(0) = fromnode
)
or
tonode.getFunction().refersTo(builtin_object("reversed")) and
tonode.getFunction().refersTo(Object::builtin("reversed")) and
tonode.getArg(0) = fromnode
}
@@ -937,7 +937,7 @@ library module TaintFlowImplementation {
pragma [noinline]
predicate getattr_step(TaintedNode fromnode, TrackedValue totaint, CallContext tocontext, CallNode tonode) {
exists(ControlFlowNode arg, string name |
tonode.getFunction().refersTo(builtin_object("getattr")) and
tonode.getFunction().refersTo(Object::builtin("getattr")) and
arg = tonode.getArg(0) and
name = tonode.getArg(1).getNode().(StrConst).getText() and
arg = fromnode.getNode() and

View File

@@ -11,10 +11,6 @@ import semmle.python.security.TaintTracking
import semmle.python.security.strings.Untrusted
private ModuleObject subprocessModule() {
result.getName() = "subprocess"
}
private ModuleObject osOrPopenModule() {
result.getName() = "os" or
result.getName() = "popen2"
@@ -22,7 +18,7 @@ private ModuleObject osOrPopenModule() {
private Object makeOsCall() {
exists(string name |
result = subprocessModule().getAttribute(name) |
result = ModuleObject::named("subprocess").attr(name) |
name = "Popen" or
name = "call" or
name = "check_call" or
@@ -79,7 +75,7 @@ class ShellCommand extends TaintSink {
or
exists(CallNode call, string name |
call.getAnArg() = this and
call.getFunction().refersTo(osOrPopenModule().getAttribute(name)) |
call.getFunction().refersTo(osOrPopenModule().attr(name)) |
name = "system" or
name = "popen" or
name.matches("popen_")

View File

@@ -12,9 +12,9 @@ import semmle.python.security.strings.Untrusted
private FunctionObject exec_or_eval() {
result = builtin_object("exec")
result = Object::builtin("exec")
or
result = builtin_object("eval")
result = Object::builtin("eval")
}
/** A taint sink that represents an argument to exec or eval that is vulnerable to malicious input.

View File

@@ -12,7 +12,7 @@ import semmle.python.security.strings.Untrusted
private FunctionObject marshalLoads() {
result = any(ModuleObject marshal | marshal.getName() = "marshal").getAttribute("loads")
result = ModuleObject::named("marshal").attr("loads")
}

View File

@@ -20,12 +20,12 @@ private class PathSanitizer extends Sanitizer {
}
private FunctionObject abspath() {
exists(ModuleObject os, ModuleObject os_path |
os.getName() = "os" and
os.getAttribute("path") = os_path |
os_path.getAttribute("abspath") = result
exists(ModuleObject os_path |
ModuleObject::named("os").attr("path") = os_path
|
os_path.attr("abspath") = result
or
os_path.getAttribute("normpath") = result
os_path.attr("normpath") = result
)
}
@@ -84,7 +84,7 @@ class OpenNode extends TaintSink {
OpenNode() {
exists(CallNode call |
call.getFunction().refersTo(builtin_object("open")) and
call.getFunction().refersTo(Object::builtin("open")) and
call.getAnArg() = this
)
}

View File

@@ -20,7 +20,7 @@ private ModuleObject pickleModule() {
}
private FunctionObject pickleLoads() {
result = pickleModule().getAttribute("loads")
result = pickleModule().attr("loads")
}
/** `pickle.loads(untrusted)` vulnerability. */

View File

@@ -33,7 +33,7 @@ private class ExpatParser extends TaintKind {
}
private FunctionObject expatCreateParseFunction() {
result = ModuleObject::named("xml.parsers.expat").getAttribute("ParserCreate")
result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate")
}
private class ExpatCreateParser extends TaintSource {
@@ -52,13 +52,13 @@ private class ExpatCreateParser extends TaintSource {
}
private FunctionObject xmlFromString() {
result = xmlElementTreeModule().getAttribute("fromstring")
result = xmlElementTreeModule().attr("fromstring")
or
result = xmlMiniDomModule().getAttribute("parseString")
result = xmlMiniDomModule().attr("parseString")
or
result = xmlPullDomModule().getAttribute("parseString")
result = xmlPullDomModule().attr("parseString")
or
result = xmlSaxModule().getAttribute("parseString")
result = xmlSaxModule().attr("parseString")
}
/** A (potentially) malicious XML string. */

View File

@@ -12,13 +12,8 @@ import semmle.python.security.TaintTracking
import semmle.python.security.strings.Untrusted
private ModuleObject yamlModule() {
result.getName() = "yaml"
}
private FunctionObject yamlLoad() {
result = yamlModule().getAttribute("load")
result = ModuleObject::named("yaml").attr("load")
}
/** `yaml.load(untrusted)` vulnerability. */

View File

@@ -110,9 +110,8 @@ private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
/* tonode = os.path.join(..., fromnode, ...) */
private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
exists(FunctionObject path_join |
exists(ModuleObject os | os.getName() = "os" |
os.getAttribute("path").(ModuleObject).getAttribute("join") = path_join
) |
path_join = ModuleObject::named("os").attr("path").(ModuleObject).attr("join")
and
tonode = path_join.getACall() and tonode.getAnArg() = fromnode
)
}

View File

@@ -7,10 +7,10 @@ predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
or
exists(ModuleObject copy, string name |
name = "copy" or name = "deepcopy" |
copy.getAttribute(name).(FunctionObject).getACall() = tonode and
copy.attr(name).(FunctionObject).getACall() = tonode and
tonode.getArg(0) = fromnode
)
or
tonode.getFunction().refersTo(builtin_object("reversed")) and
tonode.getFunction().refersTo(Object::builtin("reversed")) and
tonode.getArg(0) = fromnode
}

View File

@@ -91,7 +91,7 @@ private predicate json_subscript_taint(SubscriptNode sub, ControlFlowNode obj, E
private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
exists(FunctionObject json_loads |
any(ModuleObject json | json.getName() = "json").getAttribute("loads") = json_loads and
any(ModuleObject json | json.getName() = "json").attr("loads") = json_loads and
json_loads.getACall() = tonode and tonode.getArg(0) = fromnode
)
}

View File

@@ -495,9 +495,9 @@ ClassObject theUnicodeType() {
/** The builtin class '(x)range' */
ClassObject theRangeType() {
result = builtin_object("xrange")
result = Object::builtin("xrange")
or
major_version() = 3 and result = builtin_object("range")
major_version() = 3 and result = Object::builtin("range")
}
/** The builtin class for bytes. str in Python2, bytes in Python3 */
@@ -590,20 +590,20 @@ ClassObject theBuiltinPropertyType() {
/** The builtin class 'IOError' */
ClassObject theIOErrorType() {
result = builtin_object("IOError")
result = Object::builtin("IOError")
}
/** The builtin class 'super' */
ClassObject theSuperType() {
result = builtin_object("super")
result = Object::builtin("super")
}
/** The builtin class 'StopIteration' */
ClassObject theStopIterationType() {
result = builtin_object("StopIteration")
result = Object::builtin("StopIteration")
}
/** The builtin class 'NotImplementedError' */
ClassObject theNotImplementedErrorType() {
result = builtin_object("NotImplementedError")
result = Object::builtin("NotImplementedError")
}

View File

@@ -31,7 +31,7 @@ class RaisingNode extends ControlFlowNode {
}
private predicate quits() {
this.(CallNode).getFunction().refersTo(quitterObject(_))
this.(CallNode).getFunction().refersTo(Object::quitter(_))
}
/** Gets the type of an exception that may be raised
@@ -49,7 +49,7 @@ class RaisingNode extends ControlFlowNode {
pragma[noinline]
private ClassObject systemExitRaise() {
this.quits() and result = builtin_object("SystemExit")
this.quits() and result = Object::builtin("SystemExit")
}
pragma [noinline, nomagic]
@@ -62,7 +62,7 @@ class RaisingNode extends ControlFlowNode {
(ex.refersTo(result) or ex.refersTo(_, result, _))
)
or
this.getNode() instanceof ImportExpr and result = builtin_object("ImportError")
this.getNode() instanceof ImportExpr and result = Object::builtin("ImportError")
or
this.getNode() instanceof Print and result = theIOErrorType()
or

View File

@@ -348,21 +348,21 @@ class BuiltinFunctionObject extends BuiltinCallable {
override ClassObject getAReturnType() {
/* Enumerate the types of a few builtin functions, that the CPython analysis misses.
*/
this = builtin_object("hex") and result = theStrType()
this = Object::builtin("hex") and result = theStrType()
or
this = builtin_object("oct") and result = theStrType()
this = Object::builtin("oct") and result = theStrType()
or
this = builtin_object("intern") and result = theStrType()
this = Object::builtin("intern") and result = theStrType()
or
/* Fix a few minor inaccuracies in the CPython analysis */
ext_rettype(this, result) and not (
this = builtin_object("__import__") and result = theNoneType()
this = Object::builtin("__import__") and result = theNoneType()
or
this = builtin_object("compile") and result = theNoneType()
this = Object::builtin("compile") and result = theNoneType()
or
this = builtin_object("sum")
this = Object::builtin("sum")
or
this = builtin_object("filter")
this = Object::builtin("filter")
)
}
@@ -376,4 +376,53 @@ class BuiltinFunctionObject extends BuiltinCallable {
}
/** DEPRECATED -- Use `Object::builtin("apply")` instead. */
Object theApplyFunction() {
result = Object::builtin("apply")
}
/** DEPRECATED -- Use `Object::builtin("hasattr")` instead. */
Object theHasattrFunction() {
result = Object::builtin("hasattr")
}
/** DEPRECATED -- Use `Object::builtin("len")` instead. */
Object theLenFunction() {
result = Object::builtin("len")
}
/** DEPRECATED -- Use `Object::builtin("format")` instead. */
Object theFormatFunction() {
result = Object::builtin("format")
}
/** DEPRECATED -- Use `Object::builtin("open")` instead. */
Object theOpenFunction() {
result = Object::builtin("open")
}
/** DEPRECATED -- Use `Object::builtin("print")` instead. */
Object thePrintFunction() {
result = Object::builtin("print")
}
/** DEPRECATED -- Use `Object::builtin("input")` instead. */
Object theInputFunction() {
result = Object::builtin("input")
}
/** DEPRECATED -- Use `Object::builtin("locals")` instead. */
Object theLocalsFunction() {
result = Object::builtin("locals")
}
/** DEPRECATED -- Use `Object::builtin("globals")()` instead. */
Object theGlobalsFunction() {
result = Object::builtin("globals")
}
/** DEPRECATED -- Use `Object::builtin("sysExit()` instead. */
Object theExitFunctionObject() {
result = ModuleObject::named("sys").attr("exit")
}

View File

@@ -33,10 +33,18 @@ abstract class ModuleObject extends Object {
}
/** Gets the named attribute of this module. Using attributeRefersTo() instead
* may provide better results for presentation. */
* may provide better results for presentation.
* */
pragma [noinline]
abstract Object getAttribute(string name);
/** Gets the named attribute of this module.
* Synonym for `getAttribute(name)` */
pragma [inline]
final Object attr(string name) {
result = this.getAttribute(name)
}
/** Whether the named attribute of this module "refers-to" value, with a known origin.
*/
abstract predicate attributeRefersTo(string name, Object value, ControlFlowNode origin);

View File

@@ -192,7 +192,7 @@ private Object findByName1(string longName) {
exists(string owner, string attrname |
longName = owner + "." + attrname
|
result = findByName0(owner).(ModuleObject).getAttribute(attrname)
result = findByName0(owner).(ModuleObject).attr(attrname)
or
result = findByName0(owner).(ClassObject).lookupAttribute(attrname)
)
@@ -204,7 +204,7 @@ private Object findByName2(string longName) {
exists(string owner, string attrname |
longName = owner + "." + attrname
|
result = findByName1(owner).(ModuleObject).getAttribute(attrname)
result = findByName1(owner).(ModuleObject).attr(attrname)
or
result = findByName1(owner).(ClassObject).lookupAttribute(attrname)
)
@@ -216,7 +216,7 @@ private Object findByName3(string longName) {
exists(string owner, string attrname |
longName = owner + "." + attrname
|
result = findByName2(owner).(ModuleObject).getAttribute(attrname)
result = findByName2(owner).(ModuleObject).attr(attrname)
or
result = findByName2(owner).(ClassObject).lookupAttribute(attrname)
)
@@ -354,6 +354,14 @@ class TupleObject extends SequenceObject {
}
module TupleObject {
TupleObject empty() {
py_cobjecttypes(result, theTupleType()) and not py_citems(result, _, _)
}
}
class NonEmptyTupleObject extends TupleObject {
NonEmptyTupleObject() {
@@ -389,108 +397,82 @@ BuiltinModuleObject theSysModuleObject() {
py_special_objects(result, "sys")
}
/** DEPRECATED -- Use `Object::builtin(name)` instead. */
deprecated
Object builtin_object(string name) {
py_cmembers_versioned(theBuiltinModuleObject(), name, result, major_version().toString())
result = Object::builtin(name)
}
/** The built-in object None */
Object theNoneObject() {
Object theNoneObject() {
py_special_objects(result, "None")
}
/** The built-in object True */
Object theTrueObject() {
Object theTrueObject() {
py_special_objects(result, "True")
}
/** The built-in object False */
Object theFalseObject() {
Object theFalseObject() {
py_special_objects(result, "False")
}
/** The builtin function apply (Python 2 only) */
Object theApplyFunction() {
result = builtin_object("apply")
}
/** The builtin function hasattr */
Object theHasattrFunction() {
result = builtin_object("hasattr")
}
/** The builtin function len */
Object theLenFunction() {
result = builtin_object("len")
}
/** The builtin function format */
Object theFormatFunction() {
result = builtin_object("format")
}
/** The builtin function open */
Object theOpenFunction() {
result = builtin_object("open")
}
/** The builtin function print (Python 2.7 upwards) */
Object thePrintFunction() {
result = builtin_object("print")
}
/** The builtin function input (Python 2 only) */
Object theInputFunction() {
result = builtin_object("input")
}
/** The builtin function locals */
Object theLocalsFunction() {
py_special_objects(result, "locals")
}
/** The builtin function globals */
Object theGlobalsFunction() {
py_special_objects(result, "globals")
}
/** The builtin function sys.exit */
Object theExitFunctionObject() {
py_cmembers_versioned(theSysModuleObject(), "exit", result, major_version().toString())
}
/** The NameError class */
Object theNameErrorType() {
result = builtin_object("NameError")
result = Object::builtin("NameError")
}
/** The StandardError class */
Object theStandardErrorType() {
result = builtin_object("StandardError")
result = Object::builtin("StandardError")
}
/** The IndexError class */
Object theIndexErrorType() {
result = builtin_object("IndexError")
result = Object::builtin("IndexError")
}
/** The LookupError class */
Object theLookupErrorType() {
result = builtin_object("LookupError")
result = Object::builtin("LookupError")
}
/** The named quitter object (quit or exit) in the builtin namespace */
/** DEPRECATED -- Use `Object::quitter(name)` instead. */
deprecated
Object quitterObject(string name) {
(name = "quit" or name = "exit") and
result = builtin_object(name)
result = Object::quitter(name)
}
/** The builtin object `NotImplemented`. Not be confused with `NotImplementedError`. */
/** DEPRECATED -- Use `Object::notImplemented()` instead. */
deprecated
Object theNotImplementedObject() {
result = builtin_object("NotImplemented")
result = Object::builtin("NotImplemented")
}
/** DEPRECATED -- Use `TupleObject::empty()` instead. */
deprecated
Object theEmptyTupleObject() {
py_cobjecttypes(result, theTupleType()) and not py_citems(result, _, _)
result = TupleObject::empty()
}
module Object {
Object builtin(string name) {
py_cmembers_versioned(theBuiltinModuleObject(), name, result, major_version().toString())
}
/** The named quitter object (quit or exit) in the builtin namespace */
Object quitter(string name) {
(name = "quit" or name = "exit") and
result = builtin(name)
}
/** The builtin object `NotImplemented`. Not be confused with `NotImplementedError`. */
Object notImplemented() {
result = builtin("NotImplemented")
}
}

View File

@@ -18,7 +18,7 @@ predicate tracked_object(ControlFlowNode obj, string attr) {
}
predicate open_file(Object obj) {
obj.(CallNode).getFunction().refersTo(theOpenFunction())
obj.(CallNode).getFunction().refersTo(Object::builtin("open"))
}
predicate string_attribute_any(ControlFlowNode n, string attr) {
@@ -26,9 +26,9 @@ predicate string_attribute_any(ControlFlowNode n, string attr) {
exists(Object input |
n.(CallNode).getFunction().refersTo(input) |
if major_version() = 2 then
input = builtin_object("raw_input")
input = Object::builtin("raw_input")
else
input = theInputFunction()
input = Object::builtin("input")
)
or
attr = "file-input" and

View File

@@ -9,7 +9,7 @@ ModuleObject theBottleModule() {
/** The bottle.Bottle class */
ClassObject theBottleClass() {
result = ModuleObject::named("bottle").getAttribute("Bottle")
result = ModuleObject::named("bottle").attr("Bottle")
}
/** Holds if `route` is routed to `func`
@@ -18,7 +18,7 @@ ClassObject theBottleClass() {
predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) {
exists(CallNode decorator_call, string name |
route_call.getFunction().(AttrNode).getObject(name).refersTo(_, theBottleClass(), _) or
route_call.getFunction().refersTo(theBottleModule().getAttribute(name))
route_call.getFunction().refersTo(theBottleModule().attr(name))
|
(name = "route" or name = httpVerbLower()) and
decorator_call.getFunction() = route_call and
@@ -73,7 +73,7 @@ class BottleRoutePointToExtension extends CustomPointsToFact {
override predicate pointsTo(Context context, Object value, ClassObject cls, ControlFlowNode origin) {
context.isImport() and
ModuleObject::named("bottle").getAttribute("Bottle").(ClassObject).attributeRefersTo(name, value, cls, origin)
ModuleObject::named("bottle").attr("Bottle").(ClassObject).attributeRefersTo(name, value, cls, origin)
}
}

View File

@@ -9,7 +9,7 @@ import semmle.python.security.strings.Basic
import semmle.python.web.bottle.General
FunctionObject bottle_redirect() {
result = theBottleModule().getAttribute("redirect")
result = theBottleModule().attr("redirect")
}
/**

View File

@@ -7,7 +7,7 @@ import semmle.python.web.Http
import semmle.python.web.bottle.General
private Object theBottleRequestObject() {
result = theBottleModule().getAttribute("request")
result = theBottleModule().attr("request")
}
class BottleRequestKind extends TaintKind {

View File

@@ -19,7 +19,7 @@ class BottleResponse extends TaintKind {
}
private Object theBottleResponseObject() {
result = theBottleModule().getAttribute("response")
result = theBottleModule().attr("response")
}
class BottleResponseBodyAssignment extends TaintSink {

View File

@@ -12,7 +12,7 @@ class DjangoDbCursor extends DbCursor {
}
private Object theDjangoConnectionObject() {
any(ModuleObject m | m.getName() = "django.db").getAttribute("connection") = result
any(ModuleObject m | m.getName() = "django.db").attr("connection") = result
}
/** A kind of taint source representing sources of django cursor objects.
@@ -38,7 +38,7 @@ class DjangoDbCursorSource extends DbConnectionSource {
ClassObject theDjangoRawSqlClass() {
result = any(ModuleObject m | m.getName() = "django.db.models.expressions").getAttribute("RawSQL")
result = any(ModuleObject m | m.getName() = "django.db.models.expressions").attr("RawSQL")
}
/**

View File

@@ -8,7 +8,7 @@ import semmle.python.web.Http
class DjangoModel extends ClassObject {
DjangoModel() {
any(ModuleObject m | m.getName() = "django.db.models").getAttribute("Model") = this.getAnImproperSuperType()
any(ModuleObject m | m.getName() = "django.db.models").attr("Model") = this.getAnImproperSuperType()
}
}

View File

@@ -82,7 +82,7 @@ private class DjangoFunctionBasedViewRequestArgument extends DjangoRequestSource
private class DjangoView extends ClassObject {
DjangoView() {
any(ModuleObject m | m.getName() = "django.views.generic").getAttribute("View") = this.getAnImproperSuperType()
any(ModuleObject m | m.getName() = "django.views.generic").attr("View") = this.getAnImproperSuperType()
}
}
@@ -109,7 +109,7 @@ class DjangoClassBasedViewRequestArgument extends DjangoRequestSource {
/* Function based views */
predicate url_dispatch(CallNode call, ControlFlowNode regex, FunctionObject view) {
exists(FunctionObject url |
any(ModuleObject m | m.getName() = "django.conf.urls").getAttribute("url") = url and
any(ModuleObject m | m.getName() = "django.conf.urls").attr("url") = url and
url.getArgumentForCall(call, 0) = regex and
url.getArgumentForCall(call, 1).refersTo(view)
)

View File

@@ -17,7 +17,7 @@ class DjangoResponse extends TaintKind {
}
private ClassObject theDjangoHttpResponseClass() {
result = any(ModuleObject m | m.getName() = "django.http.response").getAttribute("HttpResponse") and
result = any(ModuleObject m | m.getName() = "django.http.response").attr("HttpResponse") and
not result = theDjangoHttpRedirectClass()
}

View File

@@ -1,9 +1,9 @@
import python
FunctionObject redirect() {
result = any(ModuleObject m | m.getName() = "django.shortcuts").getAttribute("redirect")
result = any(ModuleObject m | m.getName() = "django.shortcuts").attr("redirect")
}
ClassObject theDjangoHttpRedirectClass() {
result = any(ModuleObject m | m.getName() = "django.http.response").getAttribute("HttpResponseRedirectBase")
result = any(ModuleObject m | m.getName() = "django.http.response").attr("HttpResponseRedirectBase")
}

View File

@@ -8,16 +8,16 @@ ModuleObject theFlaskModule() {
/** The flask app class */
ClassObject theFlaskClass() {
result = theFlaskModule().getAttribute("Flask")
result = theFlaskModule().attr("Flask")
}
/** The flask MethodView class */
ClassObject theFlaskMethodViewClass() {
result = any(ModuleObject m | m.getName() = "flask.views").getAttribute("MethodView")
result = any(ModuleObject m | m.getName() = "flask.views").attr("MethodView")
}
ClassObject theFlaskReponseClass() {
result = theFlaskModule().getAttribute("Response")
result = theFlaskModule().attr("Response")
}
/** Holds if `route` is routed to `func`

View File

@@ -9,7 +9,7 @@ import semmle.python.security.strings.Basic
import semmle.python.web.flask.General
FunctionObject flask_redirect() {
result = theFlaskModule().getAttribute("redirect")
result = theFlaskModule().attr("redirect")
}
/**

View File

@@ -5,7 +5,7 @@ import semmle.python.web.Http
import semmle.python.web.flask.General
private Object theFlaskRequestObject() {
result = theFlaskModule().getAttribute("request")
result = theFlaskModule().attr("request")
}

View File

@@ -10,9 +10,9 @@ import semmle.python.security.strings.Basic
private ClassObject redirectClass() {
exists(ModuleObject ex |
ex.getName() = "pyramid.httpexceptions" |
ex.getAttribute("HTTPFound") = result
ex.attr("HTTPFound") = result
or
ex.getAttribute("HTTPTemporaryRedirect") = result
ex.attr("HTTPTemporaryRedirect") = result
)
}

View File

@@ -12,7 +12,7 @@ class PyramidRequest extends BaseWebobRequest {
}
override ClassObject getClass() {
result = any(ModuleObject m | m.getName() = "pyramid.request").getAttribute("Request")
result = any(ModuleObject m | m.getName() = "pyramid.request").attr("Request")
}
}

View File

@@ -5,7 +5,7 @@ ModuleObject thePyramidViewModule() {
}
Object thePyramidViewConfig() {
result = thePyramidViewModule().getAttribute("view_config")
result = thePyramidViewModule().attr("view_config")
}
predicate is_pyramid_view_function(Function func) {

View File

@@ -3,7 +3,7 @@ import python
import semmle.python.security.TaintTracking
private ClassObject theTornadoRequestHandlerClass() {
result = any(ModuleObject m | m.getName() = "tornado.web").getAttribute("RequestHandler")
result = any(ModuleObject m | m.getName() = "tornado.web").attr("RequestHandler")
}
ClassObject aTornadoRequestHandlerClass() {

View File

@@ -3,11 +3,11 @@ import python
import semmle.python.security.TaintTracking
private ClassObject theTwistedHttpRequestClass() {
result = any(ModuleObject m | m.getName() = "twisted.web.http").getAttribute("Request")
result = any(ModuleObject m | m.getName() = "twisted.web.http").attr("Request")
}
private ClassObject theTwistedHttpResourceClass() {
result = any(ModuleObject m | m.getName() = "twisted.web.resource").getAttribute("Resource")
result = any(ModuleObject m | m.getName() = "twisted.web.resource").attr("Resource")
}
ClassObject aTwistedRequestHandlerClass() {

View File

@@ -45,7 +45,7 @@ class WebobRequest extends BaseWebobRequest {
}
override ClassObject getClass() {
result = any(ModuleObject m | m.getName() = "webob.request").getAttribute("Request")
result = any(ModuleObject m | m.getName() = "webob.request").attr("Request")
}
}