Skip to content

Commit 2582b08

Browse files
author
Stephan Brandauer
authored
Merge pull request github#13747 from github/tausbn/exclude-qualifier-argument-for-existing-models
Java: Exclude qualifier argument for existing models
2 parents 0a0e347 + 13027a1 commit 2582b08

5 files changed

+37
-29
lines changed

java/ql/src/Telemetry/AutomodelApplicationModeCharacteristics.qll

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummary
1212
private import semmle.code.java.security.ExternalAPIs as ExternalAPIs
1313
private import semmle.code.java.Expr as Expr
1414
private import semmle.code.java.security.QueryInjection
15-
private import semmle.code.java.security.RequestForgery
1615
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
1716
private import AutomodelJavaUtil as AutomodelJavaUtil
1817
private import semmle.code.java.security.PathSanitizer as PathSanitizer
@@ -26,7 +25,17 @@ newtype JavaRelatedLocationType = CallContext()
2625
* A class representing nodes that are arguments to calls.
2726
*/
2827
private class ArgumentNode extends DataFlow::Node {
29-
ArgumentNode() { this.asExpr() = [any(Call c).getAnArgument(), any(Call c).getQualifier()] }
28+
Call c;
29+
30+
ArgumentNode() {
31+
exists(Argument arg | this.asExpr() = arg and not arg.isVararg() and c = arg.getCall())
32+
or
33+
this.(DataFlow::ImplicitVarargsArray).getCall() = c
34+
or
35+
this = DataFlow::getInstanceArgument(c)
36+
}
37+
38+
Call getCall() { result = c }
3039
}
3140

3241
/**
@@ -67,19 +76,19 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
6776

6877
predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
6978

70-
predicate isSink(Endpoint e, string kind) {
79+
predicate isSink(Endpoint e, string kind, string provenance) {
7180
exists(string package, string type, string name, string signature, string ext, string input |
7281
sinkSpec(e, package, type, name, signature, ext, input) and
73-
ExternalFlow::sinkModel(package, type, _, name, [signature, ""], ext, input, kind, _)
82+
ExternalFlow::sinkModel(package, type, _, name, [signature, ""], ext, input, kind, provenance)
7483
)
7584
or
76-
isCustomSink(e, kind)
85+
isCustomSink(e, kind) and provenance = "custom-sink"
7786
}
7887

7988
predicate isNeutral(Endpoint e) {
8089
exists(string package, string type, string name, string signature |
8190
sinkSpec(e, package, type, name, signature, _, _) and
82-
ExternalFlow::neutralModel(package, type, name, [signature, ""], "sink", _)
91+
ExternalFlow::neutralModel(package, type, name, [signature, ""], _, _)
8392
)
8493
}
8594

@@ -136,10 +145,6 @@ private module ApplicationModeGetCallable implements AutomodelSharedGetCallable:
136145
* should be empty.
137146
*/
138147
private predicate isCustomSink(Endpoint e, string kind) {
139-
e.asExpr() instanceof ArgumentToExec and kind = "command injection"
140-
or
141-
e instanceof RequestForgerySink and kind = "request forgery"
142-
or
143148
e instanceof QueryInjectionSink and kind = "sql"
144149
}
145150

@@ -200,7 +205,7 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
200205
UnexploitableIsCharacteristic() { this = "unexploitable (is-style boolean method)" }
201206

202207
override predicate appliesToEndpoint(Endpoint e) {
203-
not ApplicationCandidatesImpl::isSink(e, _) and
208+
not ApplicationCandidatesImpl::isSink(e, _, _) and
204209
ApplicationModeGetCallable::getCallable(e).getName().matches("is%") and
205210
ApplicationModeGetCallable::getCallable(e).getReturnType() instanceof BooleanType
206211
}
@@ -218,7 +223,7 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
218223
UnexploitableExistsCharacteristic() { this = "unexploitable (existence-checking boolean method)" }
219224

220225
override predicate appliesToEndpoint(Endpoint e) {
221-
not ApplicationCandidatesImpl::isSink(e, _) and
226+
not ApplicationCandidatesImpl::isSink(e, _, _) and
222227
exists(Callable callable |
223228
callable = ApplicationModeGetCallable::getCallable(e) and
224229
callable.getName().toLowerCase() = ["exists", "notexists"] and
@@ -313,7 +318,8 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
313318

314319
/**
315320
* A negative characteristic that indicates that an endpoint is a non-sink argument to a method whose sinks have already
316-
* been modeled.
321+
* been modeled _manually_. This is restricted to manual sinks only, because only during the manual process do we have
322+
* the expectation that all sinks present in a method have been considered.
317323
*
318324
* WARNING: These endpoints should not be used as negative samples for training, because some sinks may have been missed
319325
* when the method was modeled. Specifically, as we start using ATM to merge in new declarations, we can be less sure
@@ -324,14 +330,14 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
324330
private class OtherArgumentToModeledMethodCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic
325331
{
326332
OtherArgumentToModeledMethodCharacteristic() {
327-
this = "other argument to a method that has already been modeled"
333+
this = "other argument to a method that has already been modeled manually"
328334
}
329335

330336
override predicate appliesToEndpoint(Endpoint e) {
331-
not ApplicationCandidatesImpl::isSink(e, _) and
332-
exists(DataFlow::Node otherSink |
333-
ApplicationCandidatesImpl::isSink(otherSink, _) and
334-
e.asExpr() = otherSink.asExpr().(Argument).getCall().getAnArgument() and
337+
not ApplicationCandidatesImpl::isSink(e, _, _) and
338+
exists(Endpoint otherSink |
339+
ApplicationCandidatesImpl::isSink(otherSink, _, "manual") and
340+
e.getCall() = otherSink.getCall() and
335341
e != otherSink
336342
)
337343
}

java/ql/src/Telemetry/AutomodelApplicationModeExtractCandidates.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ where
6464
// label it as a sink for one of the sink types of query B, for which it's already a known sink. This would result in
6565
// overlap between our detected sinks and the pre-existing modeling. We assume that, if a sink has already been
6666
// modeled in a MaD model, then it doesn't belong to any additional sink types, and we don't need to reexamine it.
67-
not CharacteristicsImpl::isSink(endpoint, _) and
67+
not CharacteristicsImpl::isSink(endpoint, _, _) and
6868
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input) and
6969
// The message is the concatenation of all sink types for which this endpoint is known neither to be a sink nor to be
7070
// a non-sink, and we surface only endpoints that have at least one such sink type.

java/ql/src/Telemetry/AutomodelFrameworkModeCharacteristics.qll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,17 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
5050

5151
predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
5252

53-
predicate isSink(Endpoint e, string kind) {
53+
predicate isSink(Endpoint e, string kind, string provenance) {
5454
exists(string package, string type, string name, string signature, string ext, string input |
5555
sinkSpec(e, package, type, name, signature, ext, input) and
56-
ExternalFlow::sinkModel(package, type, _, name, [signature, ""], ext, input, kind, _)
56+
ExternalFlow::sinkModel(package, type, _, name, [signature, ""], ext, input, kind, provenance)
5757
)
5858
}
5959

6060
predicate isNeutral(Endpoint e) {
6161
exists(string package, string type, string name, string signature |
6262
sinkSpec(e, package, type, name, signature, _, _) and
63-
ExternalFlow::neutralModel(package, type, name, [signature, ""], "sink", _)
63+
ExternalFlow::neutralModel(package, type, name, [signature, ""], _, _)
6464
)
6565
}
6666

@@ -154,7 +154,7 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
154154
UnexploitableIsCharacteristic() { this = "unexploitable (is-style boolean method)" }
155155

156156
override predicate appliesToEndpoint(Endpoint e) {
157-
not FrameworkCandidatesImpl::isSink(e, _) and
157+
not FrameworkCandidatesImpl::isSink(e, _, _) and
158158
FrameworkModeGetCallable::getCallable(e).getName().matches("is%") and
159159
FrameworkModeGetCallable::getCallable(e).getReturnType() instanceof BooleanType
160160
}
@@ -172,7 +172,7 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
172172
UnexploitableExistsCharacteristic() { this = "unexploitable (existence-checking boolean method)" }
173173

174174
override predicate appliesToEndpoint(Endpoint e) {
175-
not FrameworkCandidatesImpl::isSink(e, _) and
175+
not FrameworkCandidatesImpl::isSink(e, _, _) and
176176
exists(Callable callable |
177177
callable = FrameworkModeGetCallable::getCallable(e) and
178178
callable.getName().toLowerCase() = ["exists", "notexists"] and

java/ql/src/Telemetry/AutomodelFrameworkModeExtractCandidates.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ where
2828
// label it as a sink for one of the sink types of query B, for which it's already a known sink. This would result in
2929
// overlap between our detected sinks and the pre-existing modeling. We assume that, if a sink has already been
3030
// modeled in a MaD model, then it doesn't belong to any additional sink types, and we don't need to reexamine it.
31-
not CharacteristicsImpl::isSink(endpoint, _) and
31+
not CharacteristicsImpl::isSink(endpoint, _, _) and
3232
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, parameterName) and
3333
// The message is the concatenation of all sink types for which this endpoint is known neither to be a sink nor to be
3434
// a non-sink, and we surface only endpoints that have at least one such sink type.

java/ql/src/Telemetry/AutomodelSharedCharacteristics.qll

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ signature module CandidateSig {
5858
predicate isSanitizer(Endpoint e, EndpointType t);
5959

6060
/**
61-
* Holds if `e` is a sink with the label `kind`.
61+
* Holds if `e` is a sink with the label `kind`, and provenance `provenance`.
6262
*/
63-
predicate isSink(Endpoint e, string kind);
63+
predicate isSink(Endpoint e, string kind, string provenance);
6464

6565
/**
6666
* Holds if `e` is not a sink of any kind.
@@ -87,7 +87,7 @@ signature module CandidateSig {
8787
* implementations of endpoint characteristics exported by this module.
8888
*/
8989
module SharedCharacteristics<CandidateSig Candidate> {
90-
predicate isSink = Candidate::isSink/2;
90+
predicate isSink = Candidate::isSink/3;
9191

9292
predicate isNeutral = Candidate::isNeutral/1;
9393

@@ -282,7 +282,9 @@ module SharedCharacteristics<CandidateSig Candidate> {
282282
this = madKind + "-characteristic"
283283
}
284284

285-
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSink(e, madKind) }
285+
override predicate appliesToEndpoint(Candidate::Endpoint e) {
286+
Candidate::isSink(e, madKind, _)
287+
}
286288

287289
override Candidate::EndpointType getSinkType() { result = endpointType }
288290
}

0 commit comments

Comments
 (0)