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

Skip to content

Commit 364de55

Browse files
author
Benjamin Muskalla
committed
Support parameter->parameter flow
1 parent cd11ef3 commit 364de55

4 files changed

Lines changed: 204 additions & 1 deletion

File tree

java/ql/src/utils/model-generator/CaptureSummaryModels.ql

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import semmle.code.java.dataflow.internal.DataFlowImplCommon
1212
string captureFlow(Callable api) {
1313
result = captureQualifierFlow(api) or
1414
result = captureParameterFlowToReturnValue(api) or
15+
result = captureFieldFlowIn(api) or
16+
result = captureParameterToParameterFlow(api) or
1517
// TODO: merge next two?
1618
result = captureFieldFlowOut(api) or
1719
result = captureFieldFlowIntoParam(api)
@@ -49,6 +51,36 @@ string captureFieldFlowIntoParam(Callable api) {
4951
)
5052
}
5153

54+
class FieldAssignment extends AssignExpr {
55+
FieldAssignment() { exists(Field f | f.getAnAccess() = this.getDest()) }
56+
}
57+
58+
class ParameterToFieldConfig extends TaintTracking::Configuration {
59+
ParameterToFieldConfig() { this = "ParameterToFieldConfig" }
60+
61+
override predicate isSource(DataFlow::Node source) {
62+
not source.asParameter().getType() instanceof PrimitiveType
63+
}
64+
65+
override predicate isSink(DataFlow::Node sink) {
66+
exists(FieldAssignment a |
67+
a.getSource().getAChildExpr() = sink.asExpr() or a.getSource() = sink.asExpr()
68+
)
69+
}
70+
}
71+
72+
string captureFieldFlowIn(Callable api) {
73+
exists(DataFlow::ParameterNode source, DataFlow::ExprNode sink, ParameterToFieldConfig config |
74+
sink.asExpr().getEnclosingCallable().getDeclaringType() =
75+
source.asParameter().getCallable().getDeclaringType() and
76+
config.hasFlow(source, sink) and
77+
source.asParameter().getCallable() = api
78+
|
79+
result =
80+
asTaintModel(api, "Argument[" + source.asParameter().getPosition() + "]", "Argument[-1]")
81+
)
82+
}
83+
5284
class ParameterToReturnValueTaintConfig extends TaintTracking::Configuration {
5385
ParameterToReturnValueTaintConfig() { this = "ParameterToReturnValueTaintConfig" }
5486

@@ -87,6 +119,18 @@ string captureParameterFlowToReturnValue(Callable api) {
87119
)
88120
}
89121

122+
string captureParameterToParameterFlow(Callable api) {
123+
exists(DataFlow::ParameterNode source, DataFlow::PostUpdateNode sink |
124+
source.getEnclosingCallable() = api and
125+
sink.getPreUpdateNode().asExpr() = api.getAParameter().getAnAccess() and
126+
TaintTracking::localTaint(source, sink)
127+
|
128+
result =
129+
asTaintModel(api, parameterAccess(source.asParameter()),
130+
parameterAccess(sink.getPreUpdateNode().asExpr().(VarAccess).getVariable().(Parameter)))
131+
)
132+
}
133+
90134
// TODO: handle cases like Ticker
91135
// TODO: "com.google.common.base;Converter;true;convertAll;(Iterable);;Element of Argument[0];Element of ReturnValue;taint",
92136
// TODO: infer interface from multiple implementations? e.g. UriComponentsContributor
Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1+
| p;Factory;false;create;(String);;Argument[0];Argument[-1];taint; |
2+
| p;Factory;false;create;(String,int);;Argument[0];Argument[-1];taint; |
13
| p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;taint; |
24
| p;FluentAPI;false;returnsThis;(String);;Argument[-1];ReturnValue;value; |
5+
| p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[-1];taint; |
6+
| p;ImmutablePojo;false;getValue;();;Argument[-1];ReturnValue;taint; |
7+
| p;ImmutablePojo;false;or;(String);;Argument[-1];ReturnValue;taint; |
8+
| p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;taint; |
39
| p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;taint; |
410
| p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;taint; |
11+
| p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[-1];taint; |
12+
| p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[-1];taint; |
13+
| p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[-1];taint; |
14+
| p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[-1];taint; |
15+
| p;Joiner;false;add;(CharSequence);;Argument[-1];ReturnValue;value; |
16+
| p;Joiner;false;merge;(Joiner);;Argument[-1];ReturnValue;value; |
17+
| p;Joiner;false;setEmptyValue;(CharSequence);;Argument[-1];ReturnValue;value; |
18+
| p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[-1];taint; |
19+
| p;Joiner;false;toString;();;Argument[-1];ReturnValue;taint; |
520
| p;ParamFlow;true;addTo;(String,List);;Argument[0];Element of Argument[1];taint; |
621
| p;ParamFlow;true;returnArrayElement;(String[]);;ArrayElement of Argument[0];ReturnValue;taint; |
722
| p;ParamFlow;true;returnCollectionElement;(List);;Element of Argument[0];ReturnValue;taint; |
@@ -10,4 +25,8 @@
1025
| p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;taint; |
1126
| p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;taint; |
1227
| p;ParamFlow;true;returnVarArgElement;(String[]);;ArrayElement of Argument[0];ReturnValue;taint; |
13-
| p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;taint; |
28+
| p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;taint; |
29+
| p;ParamFlow;true;writeChunked;(byte[],OutputStream);;ArrayElement of Argument[0];Argument[1];taint; |
30+
| p;Pojo;false;fillIn;(List);;Argument[-1];Element of Argument[0];taint; |
31+
| p;Pojo;false;getValue;();;Argument[-1];ReturnValue;taint; |
32+
| p;Pojo;false;setValue;(String);;Argument[0];Argument[-1];taint; |
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package p;
2+
3+
public final class Factory {
4+
5+
private String value;
6+
7+
private int intValue;
8+
9+
public static Factory create(String value, int foo) {
10+
return new Factory(value, foo);
11+
}
12+
13+
public static Factory create(String value) {
14+
return new Factory(value, 0);
15+
}
16+
17+
private Factory(String value, int intValue) {
18+
this.value = value;
19+
this.intValue = intValue;
20+
}
21+
22+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package p;
2+
3+
import java.util.Arrays;
4+
import java.util.Objects;
5+
6+
public final class Joiner {
7+
private final String prefix;
8+
private final String delimiter;
9+
private final String suffix;
10+
private String[] elts;
11+
private int size;
12+
private int len;
13+
private String emptyValue;
14+
public Joiner(CharSequence delimiter) {
15+
this(delimiter, "", "");
16+
}
17+
18+
public Joiner(CharSequence delimiter,
19+
CharSequence prefix,
20+
CharSequence suffix) {
21+
Objects.requireNonNull(prefix, "The prefix must not be null");
22+
Objects.requireNonNull(delimiter, "The delimiter must not be null");
23+
Objects.requireNonNull(suffix, "The suffix must not be null");
24+
this.prefix = prefix.toString();
25+
this.delimiter = delimiter.toString();
26+
this.suffix = suffix.toString();
27+
checkAddLength(0, 0);
28+
}
29+
30+
public Joiner setEmptyValue(CharSequence emptyValue) {
31+
this.emptyValue = Objects.requireNonNull(emptyValue,
32+
"The empty value must not be null").toString();
33+
return this;
34+
}
35+
36+
private static int getChars(String s, char[] chars, int start) {
37+
int len = s.length();
38+
s.getChars(0, len, chars, start);
39+
return len;
40+
}
41+
42+
@Override
43+
public String toString() {
44+
final String[] elts = this.elts;
45+
if (elts == null && emptyValue != null) {
46+
return emptyValue;
47+
}
48+
final int size = this.size;
49+
final int addLen = prefix.length() + suffix.length();
50+
if (addLen == 0) {
51+
compactElts();
52+
return size == 0 ? "" : elts[0];
53+
}
54+
final String delimiter = this.delimiter;
55+
final char[] chars = new char[len + addLen];
56+
int k = getChars(prefix, chars, 0);
57+
if (size > 0) {
58+
k += getChars(elts[0], chars, k);
59+
for (int i = 1; i < size; i++) {
60+
k += getChars(delimiter, chars, k);
61+
k += getChars(elts[i], chars, k);
62+
}
63+
}
64+
k += getChars(suffix, chars, k);
65+
return new String(chars);
66+
}
67+
68+
public Joiner add(CharSequence newElement) {
69+
final String elt = String.valueOf(newElement);
70+
if (elts == null) {
71+
elts = new String[8];
72+
} else {
73+
if (size == elts.length)
74+
elts = Arrays.copyOf(elts, 2 * size);
75+
len = checkAddLength(len, delimiter.length());
76+
}
77+
len = checkAddLength(len, elt.length());
78+
elts[size++] = elt;
79+
return this;
80+
}
81+
82+
private int checkAddLength(int oldLen, int inc) {
83+
long newLen = (long)oldLen + (long)inc;
84+
long tmpLen = newLen + (long)prefix.length() + (long)suffix.length();
85+
if (tmpLen != (int)tmpLen) {
86+
throw new OutOfMemoryError("Requested array size exceeds VM limit");
87+
}
88+
return (int)newLen;
89+
}
90+
91+
public Joiner merge(Joiner other) {
92+
Objects.requireNonNull(other);
93+
if (other.elts == null) {
94+
return this;
95+
}
96+
other.compactElts();
97+
return add(other.elts[0]);
98+
}
99+
100+
private void compactElts() {
101+
if (size > 1) {
102+
final char[] chars = new char[len];
103+
int i = 1, k = getChars(elts[0], chars, 0);
104+
do {
105+
k += getChars(delimiter, chars, k);
106+
k += getChars(elts[i], chars, k);
107+
elts[i] = null;
108+
} while (++i < size);
109+
size = 1;
110+
elts[0] = new String(chars);
111+
}
112+
}
113+
114+
public int length() {
115+
return (size == 0 && emptyValue != null) ? emptyValue.length() :
116+
len + prefix.length() + suffix.length();
117+
}
118+
}

0 commit comments

Comments
 (0)