Skip to content

Commit b7e4bd2

Browse files
committed
Java: Use an IPA type instead of a string
While the string representation is useful for quickly modifying queries, it's a bit clunky when the data needs to be further parsed. Instead, the two queries now select all of the columns of the sinkmodel separately (which makes it easy to pull them out of the relevant output later on).
1 parent 6f24d93 commit b7e4bd2

File tree

3 files changed

+93
-24
lines changed

3 files changed

+93
-24
lines changed

java/ql/src/Telemetry/AutomodelAlertSinkUtil.qll

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,72 @@ private import semmle.code.java.security.TaintedPathQuery
1111
private import semmle.code.java.security.SqlInjectionQuery
1212
private import AutomodelJavaUtil
1313

14+
private newtype TSinkModel =
15+
MkSinkModel(
16+
string package, string type, boolean subtypes, string name, string signature, string input,
17+
string ext, string kind, string provenance
18+
) {
19+
ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
20+
}
21+
22+
class SinkModel extends TSinkModel {
23+
string package;
24+
string type;
25+
boolean subtypes;
26+
string name;
27+
string signature;
28+
string input;
29+
string ext;
30+
string kind;
31+
string provenance;
32+
33+
SinkModel() {
34+
this = MkSinkModel(package, type, subtypes, name, signature, input, ext, kind, provenance)
35+
}
36+
37+
/** Gets the package for this sink model. */
38+
string getPackage() { result = package }
39+
40+
/** Gets the type for this sink model. */
41+
string getType() { result = type }
42+
43+
/** Gets whether this sink model considers subtypes. */
44+
boolean getSubtypes() { result = subtypes }
45+
46+
/** Gets the name for this sink model. */
47+
string getName() { result = name }
48+
49+
/** Gets the signature for this sink model. */
50+
string getSignature() { result = signature }
51+
52+
/** Gets the input for this sink model. */
53+
string getInput() { result = input }
54+
55+
/** Gets the extension for this sink model. */
56+
string getExt() { result = ext }
57+
58+
/** Gets the kind for this sink model. */
59+
string getKind() { result = kind }
60+
61+
/** Gets the provenance for this sink model. */
62+
string getProvenance() { result = provenance }
63+
64+
/** Gets a string representation of this sink model. */
65+
string toString() {
66+
result =
67+
"SinkModel(" + package + ", " + type + ", " + subtypes + ", " + name + ", " + signature + ", "
68+
+ input + ", " + ext + ", " + kind + ", " + provenance + ")"
69+
}
70+
71+
/** Gets a string representation of this sink model as it would appear in a Models-as-Data file. */
72+
string getRepr() {
73+
result =
74+
"\"" + package + "\", \"" + type + "\", " + pyBool(subtypes) + ", \"" + name + "\", \"" +
75+
signature + "\", \"" + ext + "\", \"" + input + "\", \"" + kind + "\", \"" + provenance +
76+
"\""
77+
}
78+
}
79+
1480
/** An expression that may correspond to a sink model. */
1581
private class PotentialSinkModelExpr extends Expr {
1682
/**
@@ -36,6 +102,12 @@ private class PotentialSinkModelExpr extends Expr {
36102
signature = ExternalFlow::paramsString(callable)
37103
)
38104
}
105+
106+
/** Gets a sink model that corresponds to this expression. */
107+
SinkModel getSinkModel() {
108+
this.hasSignature(result.getPackage(), result.getType(), result.getSubtypes(), result.getName(),
109+
result.getSignature(), result.getInput())
110+
}
39111
}
40112

41113
private string pyBool(boolean b) {
@@ -46,21 +118,12 @@ private string pyBool(boolean b) {
46118

47119
/**
48120
* Gets a string representation of the existing sink model at the expression `e`, in the format in
49-
* which it would appear in a Models-as-Data file.
121+
* which it would appear in a Models-as-Data file. Also restricts the provenance of the sink model
122+
* to be `ai-generated`.
50123
*/
51124
string getSinkModelRepr(PotentialSinkModelExpr e) {
52-
exists(
53-
string package, string type, boolean subtypes, string name, string signature, string input,
54-
string ext, string kind, string provenance
55-
|
56-
e.hasSignature(package, type, subtypes, name, signature, input) and
57-
ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
58-
provenance = "ai-generated" and
59-
result =
60-
"\"" + package + "\", \"" + type + "\", " + pyBool(subtypes) + ", \"" + name + "\", \"" +
61-
signature + "\", \"" + ext + "\", \"" + input + "\", \"" + kind + "\", \"" + provenance +
62-
"\""
63-
)
125+
result = e.getSinkModel().getRepr() and
126+
e.getSinkModel().getProvenance() = "ai-generated"
64127
}
65128

66129
/**
@@ -78,17 +141,17 @@ string getSinkModelQueryRepr(PotentialSinkModelExpr e) {
78141
private module SinkTallier<DataFlow::ConfigSig Config> {
79142
module ConfigFlow = TaintTracking::Global<Config>;
80143

81-
predicate getSinkModelCount(int c, string s) {
82-
s = getSinkModelRepr(any(ConfigFlow::PathNode sink).getNode().asExpr()) and
144+
predicate getSinkModelCount(int c, SinkModel s) {
145+
s = any(ConfigFlow::PathNode sink).getNode().asExpr().(PotentialSinkModelExpr).getSinkModel() and
83146
c =
84147
strictcount(ConfigFlow::PathNode sink |
85148
ConfigFlow::flowPath(_, sink) and
86-
s = getSinkModelRepr(sink.getNode().asExpr())
149+
s = sink.getNode().asExpr().(PotentialSinkModelExpr).getSinkModel()
87150
)
88151
}
89152
}
90153

91-
predicate sinkModelTallyPerQuery(string queryName, int alertCount, string sinkModel) {
154+
predicate sinkModelTallyPerQuery(string queryName, int alertCount, SinkModel sinkModel) {
92155
queryName = "java/request-forgery" and
93156
SinkTallier<RequestForgeryConfig>::getSinkModelCount(alertCount, sinkModel)
94157
or
@@ -115,7 +178,7 @@ predicate sinkModelTallyPerQuery(string queryName, int alertCount, string sinkMo
115178
SinkTallier<QueryInjectionFlowConfig>::getSinkModelCount(alertCount, sinkModel)
116179
}
117180

118-
predicate sinkModelTally(int alertCount, string sinkModel) {
181+
predicate sinkModelTally(int alertCount, SinkModel sinkModel) {
119182
sinkModelTallyPerQuery(_, _, sinkModel) and
120183
alertCount = sum(int c | sinkModelTallyPerQuery(_, c, sinkModel))
121184
}

java/ql/src/Telemetry/AutomodelAlertSinks.ql

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
private import java
1010
private import AutomodelAlertSinkUtil
1111

12-
from int alertCount, string sinkModel
13-
where sinkModelTally(alertCount, sinkModel)
14-
select alertCount, sinkModel
12+
from int alertCount, SinkModel s
13+
where sinkModelTally(alertCount, s) and s.getProvenance() = "ai-generated"
14+
select alertCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes,
15+
s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext,
16+
s.getKind() as kind, s.getProvenance() as provenance

java/ql/src/Telemetry/AutomodelAlertSinksPerQuery.ql

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
private import java
1010
private import AutomodelAlertSinkUtil
1111

12-
from string queryId, int alertCount, string sinkModel
13-
where sinkModelTallyPerQuery(queryId, alertCount, sinkModel)
14-
select queryId, alertCount, sinkModel
12+
from string queryId, int alertCount, SinkModel s
13+
where
14+
sinkModelTallyPerQuery(queryId, alertCount, s) and
15+
s.getProvenance() = "ai-generated"
16+
select queryId, alertCount, s.getPackage() as package, s.getType() as type,
17+
s.getSubtypes() as subtypes, s.getName() as name, s.getSignature() as signature,
18+
s.getInput() as input, s.getExt() as ext, s.getKind() as kind, s.getProvenance() as provenance

0 commit comments

Comments
 (0)