Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6fc1657

Browse files
tausbnStephan Brandauer
authored andcommitted
Java: Add QL support for automodel application mode
1 parent 5de8934 commit 6fc1657

3 files changed

Lines changed: 409 additions & 1 deletion

File tree

Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
/**
2+
* For internal use only.
3+
*/
4+
5+
private import java
6+
private import semmle.code.Location as Location
7+
private import semmle.code.java.dataflow.DataFlow
8+
private import semmle.code.java.dataflow.TaintTracking
9+
private import semmle.code.java.security.PathCreation
10+
private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
11+
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
12+
private import semmle.code.java.security.ExternalAPIs as ExternalAPIs
13+
private import semmle.code.java.Expr as Expr
14+
private import semmle.code.java.security.QueryInjection
15+
private import semmle.code.java.security.RequestForgery
16+
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
17+
import AutomodelSharedCharacteristics as SharedCharacteristics
18+
import AutomodelEndpointTypes as AutomodelEndpointTypes
19+
20+
/**
21+
* A meta data extractor. Any Java extraction mode needs to implement exactly
22+
* one instance of this class.
23+
*/
24+
abstract class MetadataExtractor extends string {
25+
bindingset[this]
26+
MetadataExtractor() { any() }
27+
28+
abstract predicate hasMetadata(
29+
Endpoint e, string package, string type, boolean subtypes, string name, string signature,
30+
int input
31+
);
32+
}
33+
34+
newtype JavaRelatedLocationType = CallContext()
35+
36+
/**
37+
* A class representing nodes that are arguments to calls.
38+
*/
39+
private class ArgumentNode extends DataFlow::Node {
40+
ArgumentNode() { this.asExpr() = [any(Call c).getAnArgument(), any(Call c).getQualifier()] }
41+
}
42+
43+
/**
44+
* A candidates implementation for framework mode.
45+
*
46+
* Some important notes:
47+
* - This mode is using parameters as endpoints.
48+
* - Sink- and neutral-information is being used from MaD models.
49+
* - When available, we use method- and class-java-docs as related locations.
50+
*/
51+
module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
52+
// for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
53+
class Endpoint = ArgumentNode;
54+
55+
class EndpointType = AutomodelEndpointTypes::EndpointType;
56+
57+
class NegativeEndpointType = AutomodelEndpointTypes::NegativeSinkType;
58+
59+
class RelatedLocation = Location::Top;
60+
61+
class RelatedLocationType = JavaRelatedLocationType;
62+
63+
// Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact.
64+
predicate isSanitizer(Endpoint e, EndpointType t) { none() }
65+
66+
RelatedLocation asLocation(Endpoint e) { result = e.asExpr() }
67+
68+
predicate isKnownKind(string kind, string humanReadableKind, EndpointType type) {
69+
kind = "read-file" and
70+
humanReadableKind = "read file" and
71+
type instanceof AutomodelEndpointTypes::TaintedPathSinkType
72+
or
73+
kind = "create-file" and
74+
humanReadableKind = "create file" and
75+
type instanceof AutomodelEndpointTypes::TaintedPathSinkType
76+
or
77+
kind = "sql" and
78+
humanReadableKind = "mad modeled sql" and
79+
type instanceof AutomodelEndpointTypes::SqlSinkType
80+
or
81+
kind = "open-url" and
82+
humanReadableKind = "open url" and
83+
type instanceof AutomodelEndpointTypes::RequestForgerySinkType
84+
or
85+
kind = "jdbc-url" and
86+
humanReadableKind = "jdbc url" and
87+
type instanceof AutomodelEndpointTypes::RequestForgerySinkType
88+
or
89+
kind = "command-injection" and
90+
humanReadableKind = "command injection" and
91+
type instanceof AutomodelEndpointTypes::CommandInjectionSinkType
92+
}
93+
94+
predicate isSink(Endpoint e, string kind) {
95+
exists(string package, string type, string name, string signature, string ext, string input |
96+
sinkSpec(e, package, type, name, signature, ext, input) and
97+
ExternalFlow::sinkModel(package, type, _, name, [signature, ""], ext, input, kind, _)
98+
)
99+
}
100+
101+
predicate isNeutral(Endpoint e) {
102+
exists(string package, string type, string name, string signature |
103+
sinkSpec(e, package, type, name, signature, _, _) and
104+
ExternalFlow::neutralModel(package, type, name, [signature, ""], _, _)
105+
)
106+
}
107+
108+
additional predicate sinkSpec(
109+
Endpoint e, string package, string type, string name, string signature, string ext, string input
110+
) {
111+
FrameworkCandidatesImpl::getCallable(e).hasQualifiedName(package, type, name) and
112+
signature = ExternalFlow::paramsString(getCallable(e)) and
113+
ext = "" and
114+
(
115+
exists(Call c, int argIdx |
116+
e.asExpr() = c.getArgument(argIdx) and
117+
input = "Argument[" + argIdx + "]"
118+
)
119+
or
120+
exists(Call c | e.asExpr() = c.getQualifier() and input = "Argument[this]")
121+
)
122+
// exists(int paramIdx | e.isParameterOf(_, paramIdx) |
123+
// if paramIdx = -1 then input = "Argument[this]" else input = "Argument[" + paramIdx + "]"
124+
// )
125+
}
126+
127+
/**
128+
* Returns the related location for the given endpoint.
129+
*
130+
* Related locations can be JavaDoc comments of the class or the method.
131+
*/
132+
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
133+
type = CallContext() and
134+
result = asLocation(e)
135+
}
136+
137+
/**
138+
* Returns the callable that contains the given endpoint.
139+
*
140+
* Each Java mode should implement this predicate.
141+
*/
142+
additional Callable getCallable(Endpoint e) {
143+
exists(Call c |
144+
e.asExpr() = [c.getAnArgument(), c.getQualifier()] and
145+
result = c.getCallee()
146+
)
147+
}
148+
}
149+
150+
module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics<FrameworkCandidatesImpl>;
151+
152+
class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic;
153+
154+
class Endpoint = FrameworkCandidatesImpl::Endpoint;
155+
156+
/*
157+
* Predicates that are used to surface prompt examples and candidates for classification with an ML model.
158+
*/
159+
160+
/**
161+
* A MetadataExtractor that extracts metadata for framework mode.
162+
*/
163+
class FrameworkModeMetadataExtractor extends MetadataExtractor {
164+
FrameworkModeMetadataExtractor() { this = "FrameworkModeMetadataExtractor" }
165+
166+
/**
167+
* By convention, the subtypes property of the MaD declaration should only be
168+
* true when there _can_ exist any subtypes with a different implementation.
169+
*
170+
* It would technically be ok to always use the value 'true', but this would
171+
* break convention.
172+
*/
173+
boolean considerSubtypes(Callable callable) {
174+
if
175+
callable.isStatic() or
176+
callable.getDeclaringType().isStatic() or
177+
callable.isFinal() or
178+
callable.getDeclaringType().isFinal()
179+
then result = false
180+
else result = true
181+
}
182+
183+
override predicate hasMetadata(
184+
Endpoint e, string package, string type, boolean subtypes, string name, string signature,
185+
int input
186+
) {
187+
exists(Call call, Callable callable |
188+
call.getCallee() = callable and
189+
(
190+
e.asExpr() = call.getArgument(input)
191+
or
192+
e.asExpr() = call.getQualifier() and input = -1
193+
) and
194+
package = callable.getDeclaringType().getPackage().getName() and
195+
type = callable.getDeclaringType().getErasure().(RefType).nestedName() and
196+
subtypes = this.considerSubtypes(callable) and
197+
name = callable.getName() and
198+
signature = ExternalFlow::paramsString(callable)
199+
)
200+
}
201+
}
202+
203+
/*
204+
* EndpointCharacteristic classes that are specific to Automodel for Java.
205+
*/
206+
207+
/**
208+
* A negative characteristic that indicates that an is-style boolean method is unexploitable even if it is a sink.
209+
*
210+
* A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
211+
* type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
212+
* the dangerous/interesting thing, so we want the latter to be modeled as the sink.
213+
*
214+
* TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
215+
*/
216+
private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
217+
UnexploitableIsCharacteristic() { this = "unexploitable (is-style boolean method)" }
218+
219+
override predicate appliesToEndpoint(Endpoint e) {
220+
not FrameworkCandidatesImpl::isSink(e, _) and
221+
FrameworkCandidatesImpl::getCallable(e).getName().matches("is%") and
222+
FrameworkCandidatesImpl::getCallable(e).getReturnType() instanceof BooleanType
223+
}
224+
}
225+
226+
/**
227+
* A negative characteristic that indicates that an existence-checking boolean method is unexploitable even if it is a
228+
* sink.
229+
*
230+
* A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
231+
* boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
232+
* dangerous/interesting thing, so we want the latter to be modeled as the sink.
233+
*/
234+
private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
235+
UnexploitableExistsCharacteristic() { this = "unexploitable (existence-checking boolean method)" }
236+
237+
override predicate appliesToEndpoint(Endpoint e) {
238+
not FrameworkCandidatesImpl::isSink(e, _) and
239+
exists(Callable callable |
240+
callable = FrameworkCandidatesImpl::getCallable(e) and
241+
callable.getName().toLowerCase() = ["exists", "notexists"] and
242+
callable.getReturnType() instanceof BooleanType
243+
)
244+
}
245+
}
246+
247+
/**
248+
* A negative characteristic that indicates that an endpoint is an argument to an exception, which is not a sink.
249+
*/
250+
private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
251+
ExceptionCharacteristic() { this = "exception" }
252+
253+
override predicate appliesToEndpoint(Endpoint e) {
254+
FrameworkCandidatesImpl::getCallable(e).getDeclaringType().getASupertype*() instanceof
255+
TypeThrowable
256+
}
257+
}
258+
259+
/**
260+
* A characteristic that limits candidates to parameters of methods that are recognized as `ModelApi`, iow., APIs that
261+
* are considered worth modeling.
262+
*/
263+
private class NotAModelApiParameter extends CharacteristicsImpl::UninterestingToModelCharacteristic {
264+
NotAModelApiParameter() { this = "not a model API parameter" }
265+
266+
override predicate appliesToEndpoint(Endpoint e) {
267+
not exists(ModelExclusions::ModelApi api |
268+
exists(Call c |
269+
c.getCallee() = api and
270+
exists(int argIdx | exists(api.getParameter(argIdx)) |
271+
argIdx = -1 and e.asExpr() = c.getQualifier()
272+
or
273+
argIdx >= 0 and e.asExpr() = c.getArgument(argIdx)
274+
)
275+
)
276+
)
277+
}
278+
}
279+
280+
/**
281+
* A negative characteristic that filters out non-public methods. Non-public methods are not interesting to include in
282+
* the standard Java modeling, because they cannot be called from outside the package.
283+
*/
284+
private class NonPublicMethodCharacteristic extends CharacteristicsImpl::UninterestingToModelCharacteristic
285+
{
286+
NonPublicMethodCharacteristic() { this = "non-public method" }
287+
288+
override predicate appliesToEndpoint(Endpoint e) {
289+
not FrameworkCandidatesImpl::getCallable(e).isPublic()
290+
}
291+
}
292+
293+
/**
294+
* Holds if the given endpoint has a self-contradictory combination of characteristics. Detects errors in our endpoint
295+
* characteristics. Lists the problematic characteristics and their implications for all such endpoints, together with
296+
* an error message indicating why this combination is problematic.
297+
*
298+
* Copied from
299+
* javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/ContradictoryEndpointCharacteristics.ql
300+
*/
301+
predicate erroneousEndpoints(
302+
Endpoint endpoint, EndpointCharacteristic characteristic,
303+
AutomodelEndpointTypes::EndpointType endpointType, float confidence, string errorMessage,
304+
boolean ignoreKnownModelingErrors
305+
) {
306+
// An endpoint's characteristics should not include positive indicators with medium/high confidence for more than one
307+
// sink/source type (including the negative type).
308+
exists(
309+
EndpointCharacteristic characteristic2, AutomodelEndpointTypes::EndpointType endpointClass2,
310+
float confidence2
311+
|
312+
endpointType != endpointClass2 and
313+
(
314+
endpointType instanceof AutomodelEndpointTypes::SinkType and
315+
endpointClass2 instanceof AutomodelEndpointTypes::SinkType
316+
or
317+
endpointType instanceof AutomodelEndpointTypes::SourceType and
318+
endpointClass2 instanceof AutomodelEndpointTypes::SourceType
319+
) and
320+
characteristic.appliesToEndpoint(endpoint) and
321+
characteristic2.appliesToEndpoint(endpoint) and
322+
characteristic.hasImplications(endpointType, true, confidence) and
323+
characteristic2.hasImplications(endpointClass2, true, confidence2) and
324+
confidence > SharedCharacteristics::mediumConfidence() and
325+
confidence2 > SharedCharacteristics::mediumConfidence() and
326+
(
327+
ignoreKnownModelingErrors = true and
328+
not knownOverlappingCharacteristics(characteristic, characteristic2)
329+
or
330+
ignoreKnownModelingErrors = false
331+
)
332+
) and
333+
errorMessage = "Endpoint has high-confidence positive indicators for multiple classes"
334+
or
335+
// An endpoint's characteristics should not include positive indicators with medium/high confidence for some class and
336+
// also include negative indicators with medium/high confidence for this same class.
337+
exists(EndpointCharacteristic characteristic2, float confidence2 |
338+
characteristic.appliesToEndpoint(endpoint) and
339+
characteristic2.appliesToEndpoint(endpoint) and
340+
characteristic.hasImplications(endpointType, true, confidence) and
341+
characteristic2.hasImplications(endpointType, false, confidence2) and
342+
confidence > SharedCharacteristics::mediumConfidence() and
343+
confidence2 > SharedCharacteristics::mediumConfidence()
344+
) and
345+
ignoreKnownModelingErrors = false and
346+
errorMessage = "Endpoint has high-confidence positive and negative indicators for the same class"
347+
}
348+
349+
/**
350+
* Holds if `characteristic1` and `characteristic2` are among the pairs of currently known positive characteristics that
351+
* have some overlap in their results. This indicates a problem with the underlying Java modeling. Specifically,
352+
* `PathCreation` is prone to FPs.
353+
*/
354+
private predicate knownOverlappingCharacteristics(
355+
EndpointCharacteristic characteristic1, EndpointCharacteristic characteristic2
356+
) {
357+
characteristic1 != characteristic2 and
358+
characteristic1 = ["mad taint step", "create path", "read file", "known non-sink"] and
359+
characteristic2 = ["mad taint step", "create path", "read file", "known non-sink"]
360+
}

0 commit comments

Comments
 (0)