mirror of
https://github.com/github/codeql.git
synced 2026-05-04 13:15:21 +02:00
Merge branch 'main' into small-cleanups
This commit is contained in:
17
python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
Normal file
17
python/ql/test/experimental/dataflow/ApiGraphs/async_test.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import pkg # $ use=moduleImport("pkg")
|
||||
|
||||
async def foo():
|
||||
coro = pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn()
|
||||
coro # $ use=moduleImport("pkg").getMember("async_func").getReturn()
|
||||
result = await coro # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
|
||||
result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
|
||||
return result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
|
||||
|
||||
async def bar():
|
||||
result = await pkg.async_func() # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
|
||||
return result # $ use=moduleImport("pkg").getMember("async_func").getReturn().getAwaited()
|
||||
|
||||
def check_annotations():
|
||||
# Just to make sure how annotations should look like :)
|
||||
result = pkg.sync_func() # $ use=moduleImport("pkg").getMember("sync_func").getReturn()
|
||||
return result # $ use=moduleImport("pkg").getMember("sync_func").getReturn()
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --lang=3
|
||||
semmle-extractor-options: --lang=3 --max-import-depth=1
|
||||
|
||||
@@ -13,7 +13,8 @@ class ApiUseTest extends InlineExpectationsTest {
|
||||
l = n.getLocation() and
|
||||
// Module variable nodes have no suitable location, so it's best to simply exclude them entirely
|
||||
// from the inline tests.
|
||||
not n instanceof DataFlow::ModuleVariableNode
|
||||
not n instanceof DataFlow::ModuleVariableNode and
|
||||
exists(l.getFile().getRelativePath())
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
conjunctive_lookup
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | bar |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | foo |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | bar |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | foo |
|
||||
calls_lookup
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj1 | foo |
|
||||
| test.py:6:1:6:6 | ControlFlowNode for meth() | meth() | obj2 | bar |
|
||||
@@ -0,0 +1,6 @@
|
||||
if cond:
|
||||
meth = obj1.foo
|
||||
else:
|
||||
meth = obj2.bar
|
||||
|
||||
meth()
|
||||
18
python/ql/test/experimental/dataflow/method-calls/test.ql
Normal file
18
python/ql/test/experimental/dataflow/method-calls/test.ql
Normal file
@@ -0,0 +1,18 @@
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import experimental.dataflow.TestUtil.PrintNode
|
||||
|
||||
query predicate conjunctive_lookup(
|
||||
DataFlow::MethodCallNode methCall, string call, string object, string methodName
|
||||
) {
|
||||
call = prettyNode(methCall) and
|
||||
object = prettyNode(methCall.getObject()) and
|
||||
methodName = methCall.getMethodName()
|
||||
}
|
||||
|
||||
query predicate calls_lookup(
|
||||
DataFlow::MethodCallNode methCall, string call, string object, string methodName
|
||||
) {
|
||||
call = prettyNode(methCall) and
|
||||
exists(DataFlow::Node o | methCall.calls(o, methodName) and object = prettyNode(o))
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
// /**
|
||||
// * @kind path-problem
|
||||
// */
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.python.dataflow.new.SensitiveDataSources
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
class SensitiveDataSourcesTest extends InlineExpectationsTest {
|
||||
SensitiveDataSourcesTest() { this = "SensitiveDataSourcesTest" }
|
||||
|
||||
override string getARelevantTag() { result = "SensitiveDataSource" }
|
||||
override string getARelevantTag() { result in ["SensitiveDataSource", "SensitiveUse"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
@@ -15,6 +20,32 @@ class SensitiveDataSourcesTest extends InlineExpectationsTest {
|
||||
element = source.toString() and
|
||||
value = source.getClassification() and
|
||||
tag = "SensitiveDataSource"
|
||||
or
|
||||
exists(DataFlow::Node use |
|
||||
any(SensitiveUseConfiguration config).hasFlow(source, use) and
|
||||
location = use.getLocation() and
|
||||
element = use.toString() and
|
||||
value = source.getClassification() and
|
||||
tag = "SensitiveUse"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class SensitiveUseConfiguration extends TaintTracking::Configuration {
|
||||
SensitiveUseConfiguration() { this = "SensitiveUseConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node node) { node instanceof SensitiveDataSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node node) {
|
||||
node = API::builtin("print").getACall().getArg(_)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
sensitiveDataExtraStepForCalls(node1, node2)
|
||||
}
|
||||
}
|
||||
// import DataFlow::PathGraph
|
||||
// from SensitiveUseConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
// where cfg.hasFlowPath(source, sink)
|
||||
// select sink, source, sink, "taint from $@", source.getNode(), "here"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
from not_found import get_passwd, account_id
|
||||
from not_found import get_passwd # $ SensitiveDataSource=password
|
||||
from not_found import account_id # $ SensitiveDataSource=id
|
||||
|
||||
def get_password():
|
||||
pass
|
||||
@@ -20,14 +21,60 @@ fetch_certificate() # $ SensitiveDataSource=certificate
|
||||
account_id() # $ SensitiveDataSource=id
|
||||
safe_to_store = encrypt_password(pwd)
|
||||
|
||||
f = get_password
|
||||
f() # $ SensitiveDataSource=password
|
||||
|
||||
# more tests of functions we don't have definition for
|
||||
x = unkown_func_not_even_imported_get_password() # $ SensitiveDataSource=password
|
||||
print(x) # $ SensitiveUse=password
|
||||
|
||||
f = get_passwd
|
||||
x = f()
|
||||
print(x) # $ SensitiveUse=password
|
||||
|
||||
import not_found
|
||||
f = not_found.get_passwd # $ SensitiveDataSource=password
|
||||
x = f()
|
||||
print(x) # $ SensitiveUse=password
|
||||
|
||||
def my_func(non_sensitive_name):
|
||||
x = non_sensitive_name()
|
||||
print(x) # $ SensitiveUse=password
|
||||
f = not_found.get_passwd # $ SensitiveDataSource=password
|
||||
my_func(f)
|
||||
|
||||
# attributes
|
||||
foo = ObjectFromDatabase()
|
||||
foo.secret # $ SensitiveDataSource=secret
|
||||
foo.username # $ SensitiveDataSource=id
|
||||
|
||||
getattr(foo, "password") # $ SensitiveDataSource=password
|
||||
x = "password"
|
||||
getattr(foo, x) # $ SensitiveDataSource=password
|
||||
|
||||
# based on variable/parameter names
|
||||
def my_func(password): # $ SensitiveDataSource=password
|
||||
print(password) # $ SensitiveUse=password
|
||||
|
||||
password = some_function() # $ SensitiveDataSource=password
|
||||
print(password) # $ SensitiveUse=password
|
||||
|
||||
for password in some_function2(): # $ SensitiveDataSource=password
|
||||
print(password) # $ SensitiveUse=password
|
||||
|
||||
with some_function3() as password: # $ SensitiveDataSource=password
|
||||
print(password) # $ SensitiveUse=password
|
||||
|
||||
|
||||
# Special handling of lookups of sensitive properties
|
||||
request.args["password"], # $ MISSING: SensitiveDataSource=password
|
||||
request.args["password"], # $ SensitiveDataSource=password
|
||||
request.args.get("password") # $ SensitiveDataSource=password
|
||||
|
||||
x = "password"
|
||||
request.args.get(x) # $ SensitiveDataSource=password
|
||||
|
||||
# I don't think handling `getlist` is super important, just included it to show what we don't handle
|
||||
request.args.getlist("password")[0] # $ MISSING: SensitiveDataSource=password
|
||||
|
||||
from not_found import password2 as foo # $ SensitiveDataSource=password
|
||||
print(foo) # $ SensitiveUse=password
|
||||
|
||||
Reference in New Issue
Block a user