Skip to content

Commit e85c4b5

Browse files
committed
Update query from code review feedback to express it as a dataflow problem.
1 parent 4a77f45 commit e85c4b5

File tree

1 file changed

+62
-57
lines changed

1 file changed

+62
-57
lines changed

java/ql/src/experimental/Security/CWE/CWE-470/LoadClassNoSignatureCheck.ql

Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
22
* @name Load 3rd party classes or code ('unsafe reflection') without signature check
3-
* @description Load classes or code from 3rd party package without checking the
3+
* @description Load classes or code from 3rd party package without checking the
44
* package signature but only rely on package name.
5-
* This makes it susceptible to package namespace squatting
5+
* This makes it susceptible to package namespace squatting
66
* potentially leading to arbitrary code execution.
77
* @problem.severity error
88
* @precision high
9-
* @kind problem
9+
* @kind path-problem
1010
* @id java/unsafe-reflection
1111
* @tags security
1212
* experimental
@@ -16,70 +16,75 @@
1616
import java
1717
import semmle.code.java.dataflow.DataFlow
1818
import semmle.code.java.dataflow.TaintTracking
19+
import semmle.code.java.controlflow.Guards
20+
import semmle.code.java.dataflow.SSA
21+
import semmle.code.java.frameworks.android.Intent
1922

23+
class CheckSignaturesGuard extends Guard instanceof EqualityTest {
24+
MethodAccess checkSignatures;
2025

21-
MethodAccess getClassLoaderReachableMethodAccess(DataFlow::Node node)
22-
{
23-
exists(MethodAccess maGetClassLoader |
24-
maGetClassLoader.getCallee().getName() = "getClassLoader" and
25-
maGetClassLoader.getQualifier() = node.asExpr() and
26-
result = maGetClassLoader.getControlFlowNode().getASuccessor+()
26+
CheckSignaturesGuard() {
27+
this.getAnOperand() = checkSignatures and
28+
checkSignatures
29+
.getMethod()
30+
.hasQualifiedName("android.content.pm", "PackageManager", "checkSignatures") and
31+
exists(Expr signatureCheckResult |
32+
this.getAnOperand() = signatureCheckResult and signatureCheckResult != checkSignatures
33+
|
34+
signatureCheckResult.(CompileTimeConstantExpr).getIntValue() = 0 or
35+
signatureCheckResult
36+
.(FieldRead)
37+
.getField()
38+
.hasQualifiedName("android.content.pm", "PackageManager", "SIGNATURE_MATCH")
2739
)
40+
}
41+
42+
Expr getCheckedExpr() { result = checkSignatures.getArgument(0) }
2843
}
2944

30-
MethodAccess getDangerousReachableMethodAccess(MethodAccess ma)
31-
{
32-
ma.getCallee().hasName(["getMethod", "getDeclaredMethod"]) and
33-
(
34-
result = ma.getControlFlowNode().getASuccessor*() and
35-
result.getCallee().hasName("invoke")
36-
or
37-
exists(AssignExpr ae |
38-
ae.getSource() = ma and
39-
ae.getDest().(VarAccess).getVariable() =
40-
result.getQualifier().(VarAccess).getVariable()
41-
)
45+
predicate signatureChecked(Expr safe) {
46+
exists(CheckSignaturesGuard g, SsaVariable v |
47+
v.getAUse() = g.getCheckedExpr() and
48+
safe = v.getAUse() and
49+
g.controls(safe.getBasicBlock(), g.(EqualityTest).polarity())
4250
)
4351
}
4452

45-
module SignaturePackageConfig implements DataFlow::ConfigSig {
46-
predicate isSource(DataFlow::Node source) {
47-
exists(MethodAccess maCheckSignatures |
48-
maCheckSignatures
49-
.getMethod()
50-
.hasQualifiedName("android.content.pm", "PackageManager", "checkSignatures") and
51-
source.asExpr() = maCheckSignatures.getArgument(0)
53+
module InsecureLoadingConfig implements DataFlow::ConfigSig {
54+
predicate isSource(DataFlow::Node src) {
55+
exists(Method m | m = src.asExpr().(MethodAccess).getMethod() |
56+
m.getDeclaringType().getASourceSupertype*() instanceof TypeContext and
57+
m.hasName("createPackageContext") and
58+
not signatureChecked(src.asExpr().(MethodAccess).getArgument(0))
59+
)
60+
}
61+
62+
predicate isSink(DataFlow::Node sink) {
63+
exists(MethodAccess ma |
64+
ma.getMethod().hasQualifiedName("java.lang", "ClassLoader", "loadClass")
65+
|
66+
sink.asExpr() = ma.getQualifier()
5267
)
53-
}
68+
}
5469

55-
predicate isSink(DataFlow::Node sink) {
56-
exists (MethodAccess maCreatePackageContext |
57-
(maCreatePackageContext.getCallee().getDeclaringType().getQualifiedName() = "android.content.ContextWrapper" or
58-
maCreatePackageContext.getCallee().getDeclaringType().getQualifiedName() = "android.content.Context") and
59-
maCreatePackageContext.getCallee().getName() = "createPackageContext" and
60-
sink.asExpr() = maCreatePackageContext.getArgument(0)
61-
)
62-
}
70+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
71+
exists(MethodAccess ma, Method m |
72+
ma.getMethod() = m and
73+
m.getDeclaringType().getASourceSupertype*() instanceof TypeContext and
74+
m.hasName("getClassLoader")
75+
|
76+
node1.asExpr() = ma.getQualifier() and
77+
node2.asExpr() = ma
78+
)
79+
}
6380
}
6481

65-
module SigPkgCfg = TaintTracking::Global<SignaturePackageConfig>;
82+
module InsecureLoadFlow = TaintTracking::Global<InsecureLoadingConfig>;
83+
84+
import InsecureLoadFlow::PathGraph
85+
86+
from InsecureLoadFlow::PathNode source, InsecureLoadFlow::PathNode sink
87+
where InsecureLoadFlow::flowPath(source, sink)
88+
select sink.getNode(), source, sink, "Class loaded from a $@ without signature check",
89+
source.getNode(), "third party library"
6690

67-
predicate isSignaturesChecked(MethodAccess maCreatePackageContext)
68-
{
69-
SigPkgCfg::flowToExpr(maCreatePackageContext.getArgument(0))
70-
}
71-
72-
from
73-
MethodAccess maCreatePackageContext, LocalVariableDeclExpr lvdePackageContext,
74-
DataFlow::Node sinkPackageContext, MethodAccess maGetMethod, MethodAccess maInvoke
75-
where
76-
maCreatePackageContext
77-
.getMethod()
78-
.hasQualifiedName("android.content", ["ContextWrapper", "Context"], "createPackageContext") and
79-
not isSignaturesChecked(maCreatePackageContext) and
80-
lvdePackageContext.getEnclosingStmt() = maCreatePackageContext.getEnclosingStmt() and
81-
TaintTracking::localTaint(DataFlow::exprNode(lvdePackageContext.getAnAccess()), sinkPackageContext) and
82-
getClassLoaderReachableMethodAccess(sinkPackageContext) = maGetMethod and
83-
getDangerousReachableMethodAccess(maGetMethod) = maInvoke
84-
select maInvoke, "Potential arbitary code execution due to $@ without $@ signature checking.", sinkPackageContext, "class loading", sinkPackageContext, "package"
85-

0 commit comments

Comments
 (0)