Skip to content

Commit bf2e23b

Browse files
committed
Java: add alert filtering libraries
1 parent 092ad92 commit bf2e23b

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

java/ql/lib/java.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Customizations
44
import semmle.code.FileSystem
55
import semmle.code.Location
66
import semmle.code.Unit
7+
import semmle.code.java.AlertFiltering
78
import semmle.code.java.Annotation
89
import semmle.code.java.Compilation
910
import semmle.code.java.CompilationUnit
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Provides a Java-specific instantiation of the `AlertFiltering` module.
3+
*/
4+
5+
private import codeql.util.AlertFiltering
6+
private import semmle.code.Location
7+
8+
module AlertFiltering = AlertFilteringImpl<Location>;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* Provides Java-specific dataflow config wrappers that apply alert filtering.
3+
*/
4+
5+
private import semmle.code.java.AlertFiltering
6+
private import semmle.code.java.dataflow.DataFlow
7+
8+
// TODO: The FilteredConfig and FilteredStateConfig modules should be additionally parameterized
9+
// with Node and Location types so that they can be shared across languages instead of being
10+
// specific to Java only.
11+
/**
12+
* This wrapper applies alert filters to an existing `DataFlow::ConfigSig` module. It is intended
13+
* to be used in the specific case where both the dataflow sources and the dataflow sinks are
14+
* presented in the query result, so we need to apply the alert filter on either the source or the
15+
* sink.
16+
*
17+
* This wrapper supports this use case by checking whether the source or the sink intersects with
18+
* the alert filter. If so, the wrapped config returns the same sources and sinks as the original.
19+
* If there is no intersection, the wrapped config has no sources or sinks, thus eliminating the
20+
* corresponding dataflow computation (which would produce no results that would pass the alert
21+
* filter anyway).
22+
*/
23+
module FilteredConfig<DataFlow::ConfigSig Config> implements DataFlow::ConfigSig {
24+
pragma[noinline]
25+
private predicate nonEmptyFilteredSourceOrSink() {
26+
exists(DataFlow::Node n |
27+
Config::isSource(n) or
28+
Config::isSink(n)
29+
|
30+
AlertFiltering::filterByLocation(n.getLocation())
31+
)
32+
}
33+
34+
predicate isSource(DataFlow::Node source) {
35+
nonEmptyFilteredSourceOrSink() and
36+
Config::isSource(source)
37+
}
38+
39+
predicate isSink(DataFlow::Node sink) {
40+
nonEmptyFilteredSourceOrSink() and
41+
Config::isSink(sink)
42+
}
43+
44+
predicate isBarrier = Config::isBarrier/1;
45+
46+
predicate isBarrierIn = Config::isBarrierIn/1;
47+
48+
predicate isBarrierOut = Config::isBarrierOut/1;
49+
50+
predicate isAdditionalFlowStep = Config::isAdditionalFlowStep/2;
51+
52+
predicate allowImplicitRead = Config::allowImplicitRead/2;
53+
54+
predicate neverSkip = Config::neverSkip/1;
55+
56+
predicate fieldFlowBranchLimit = Config::fieldFlowBranchLimit/0;
57+
58+
predicate accessPathLimit = Config::accessPathLimit/0;
59+
60+
predicate getAFeature = Config::getAFeature/0;
61+
62+
predicate sourceGrouping = Config::sourceGrouping/2;
63+
64+
predicate sinkGrouping = Config::sinkGrouping/2;
65+
66+
predicate includeHiddenNodes = Config::includeHiddenNodes/0;
67+
}
68+
69+
/**
70+
* This wrapper applies alert filters to an existing `DataFlow::StateConfigSig` module. It is
71+
* intended to be used in the specific case where both the dataflow sources and the dataflow sinks
72+
* are presented in the query result, so we need to apply the alert filter on either the source or
73+
* the sink.
74+
*
75+
* This wrapper supports this use case by checking whether the source or the sink intersects with
76+
* the alert filter. If so, the wrapped config returns the same sources and sinks as the original.
77+
* If there is no intersection, the wrapped config has no sources or sinks, thus eliminating the
78+
* corresponding dataflow computation (which would produce no results that would pass the alert
79+
* filter anyway).
80+
*/
81+
module FilteredStateConfig<DataFlow::StateConfigSig Config> implements DataFlow::StateConfigSig {
82+
class FlowState = Config::FlowState;
83+
84+
pragma[noinline]
85+
private predicate nonEmptyFilteredSourceOrSink() {
86+
exists(DataFlow::Node n |
87+
Config::isSource(n, _) or
88+
Config::isSink(n, _) or
89+
Config::isSink(n)
90+
|
91+
AlertFiltering::filterByLocation(n.getLocation())
92+
)
93+
}
94+
95+
predicate isSource(DataFlow::Node source, FlowState state) {
96+
nonEmptyFilteredSourceOrSink() and
97+
Config::isSource(source, state)
98+
}
99+
100+
predicate isSink(DataFlow::Node sink, FlowState state) {
101+
nonEmptyFilteredSourceOrSink() and
102+
Config::isSink(sink, state)
103+
}
104+
105+
predicate isSink(DataFlow::Node sink) {
106+
nonEmptyFilteredSourceOrSink() and
107+
Config::isSink(sink)
108+
}
109+
110+
predicate isBarrier = Config::isBarrier/1;
111+
112+
predicate isBarrier = Config::isBarrier/2;
113+
114+
predicate isBarrierIn = Config::isBarrierIn/1;
115+
116+
predicate isBarrierIn = Config::isBarrierIn/2;
117+
118+
predicate isBarrierOut = Config::isBarrierOut/1;
119+
120+
predicate isBarrierOut = Config::isBarrierOut/2;
121+
122+
predicate isAdditionalFlowStep = Config::isAdditionalFlowStep/2;
123+
124+
predicate isAdditionalFlowStep = Config::isAdditionalFlowStep/4;
125+
}

0 commit comments

Comments
 (0)