Skip to content

Commit 6804e20

Browse files
authored
Merge pull request #8451 from michaelnebel/csharp/modelgenerator-improvements
C#: Model generator improvements and more tests
2 parents 647d374 + b204f78 commit 6804e20

File tree

6 files changed

+198
-15
lines changed

6 files changed

+198
-15
lines changed

csharp/ql/lib/semmle/code/csharp/commons/Collections.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** Provides classes for collections. */
22

33
import csharp
4+
import semmle.code.csharp.frameworks.system.Collections
45

56
private string modifyMethodName() {
67
result =
@@ -66,6 +67,12 @@ class CollectionType extends RefType {
6667
}
6768
}
6869

70+
/** Holds if `t` is a collection type. */
71+
predicate isCollectionType(ValueOrRefType t) {
72+
t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and
73+
not t instanceof StringType
74+
}
75+
6976
/** An object creation that creates an empty collection. */
7077
class EmptyCollectionCreation extends ObjectCreation {
7178
EmptyCollectionCreation() {

csharp/ql/src/utils/model-generator/ModelGeneratorUtilsSpecific.qll

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import csharp
22
import semmle.code.csharp.dataflow.internal.DataFlowPrivate
33
private import semmle.code.csharp.commons.Util
4+
private import semmle.code.csharp.commons.Collections
45
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
56
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
67

@@ -28,14 +29,8 @@ predicate asPartialModel = Csv::asPartialModel/1;
2829
*/
2930
predicate isRelevantType(Type t) { not t instanceof Enum }
3031

31-
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
32-
t.getName().regexpMatch("byte|char|Byte|Char")
33-
}
34-
3532
private string parameterAccess(Parameter p) {
36-
if
37-
p.getType() instanceof ArrayType and
38-
not isPrimitiveTypeUsedForBulkData(p.getType().(ArrayType).getElementType())
33+
if isCollectionType(p.getType())
3934
then result = "Argument[" + p.getPosition() + "].Element"
4035
else result = "Argument[" + p.getPosition() + "]"
4136
}
Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
| Summaries;BasicFlow;false;AssignFieldToArray;(System.Object[]);Argument[Qualifier];Argument[0].Element;taint |
2-
| Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint |
3-
| Summaries;BasicFlow;false;ReturnArrayElement;(System.Int32[]);Argument[0].Element;ReturnValue;taint |
1+
| NoSummaries;PublicClassFlow;false;PublicReturn;(System.Int32);Argument[0];ReturnValue;taint |
2+
| Summaries;BaseClassFlow;true;ReturnParam;(System.Int32);Argument[0];ReturnValue;taint |
43
| Summaries;BasicFlow;false;ReturnField;();Argument[Qualifier];ReturnValue;taint |
54
| Summaries;BasicFlow;false;ReturnParam0;(System.String,System.Object);Argument[0];ReturnValue;taint |
65
| Summaries;BasicFlow;false;ReturnParam1;(System.String,System.Object);Argument[1];ReturnValue;taint |
@@ -9,3 +8,23 @@
98
| Summaries;BasicFlow;false;ReturnSubstring;(System.String);Argument[0];ReturnValue;taint |
109
| Summaries;BasicFlow;false;ReturnThis;(System.Object);Argument[Qualifier];ReturnValue;value |
1110
| Summaries;BasicFlow;false;SetField;(System.String);Argument[0];Argument[Qualifier];taint |
11+
| Summaries;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);Argument[Qualifier];Argument[0].Element;taint |
12+
| Summaries;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);Argument[1];Argument[0].Element;taint |
13+
| Summaries;CollectionFlow;false;AssignFieldToArray;(System.Object[]);Argument[Qualifier];Argument[0].Element;taint |
14+
| Summaries;CollectionFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint |
15+
| Summaries;CollectionFlow;false;ReturnArrayElement;(System.Int32[]);Argument[0].Element;ReturnValue;taint |
16+
| Summaries;CollectionFlow;false;ReturnFieldInAList;();Argument[Qualifier];ReturnValue;taint |
17+
| Summaries;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);Argument[0].Element;ReturnValue;taint |
18+
| Summaries;DerivedClass1Flow;false;ReturnParam1;(System.Int32,System.Int32);Argument[1];ReturnValue;taint |
19+
| Summaries;DerivedClass2Flow;false;ReturnParam0;(System.Int32,System.Int32);Argument[0];ReturnValue;taint |
20+
| Summaries;DerivedClass2Flow;false;ReturnParam;(System.Int32);Argument[0];ReturnValue;taint |
21+
| Summaries;GenericFlow<>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);Argument[Qualifier];Argument[0].Element;taint |
22+
| Summaries;GenericFlow<>;false;AddToGenericList<>;(System.Collections.Generic.List<S>,S);Argument[1];Argument[0].Element;taint |
23+
| Summaries;GenericFlow<>;false;ReturnFieldInGenericList;();Argument[Qualifier];ReturnValue;taint |
24+
| Summaries;GenericFlow<>;false;ReturnGenericElement<>;(System.Collections.Generic.List<S>);Argument[0].Element;ReturnValue;taint |
25+
| Summaries;GenericFlow<>;false;ReturnGenericField;();Argument[Qualifier];ReturnValue;taint |
26+
| Summaries;GenericFlow<>;false;ReturnGenericParam<>;(S);Argument[0];ReturnValue;taint |
27+
| Summaries;GenericFlow<>;false;SetGenericField;(T);Argument[0];Argument[Qualifier];taint |
28+
| Summaries;IEnumerableFlow;false;ReturnFieldInIEnumerable;();Argument[Qualifier];ReturnValue;taint |
29+
| Summaries;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);Argument[0].Element;ReturnValue;taint |
30+
| Summaries;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable<System.Object>);Argument[0].Element;ReturnValue;taint |
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
3+
namespace NoSummaries;
4+
5+
// Single class with a method that produces a flow summary.
6+
// Just to prove that, if a method like this is correctly exposed, a flow summary will be captured.
7+
public class PublicClassFlow
8+
{
9+
public int PublicReturn(int input)
10+
{
11+
return input;
12+
}
13+
}
14+
15+
public sealed class PublicClassNoFlow
16+
{
17+
private int PrivateReturn(int input)
18+
{
19+
return input;
20+
}
21+
22+
internal int InternalReturn(int input)
23+
{
24+
return input;
25+
}
26+
27+
private class PrivateClassNoFlow
28+
{
29+
public int ReturnParam(int input)
30+
{
31+
return input;
32+
}
33+
}
34+
35+
private class PrivateClassNestedPublicClassNoFlow
36+
{
37+
public class NestedPublicClassFlow
38+
{
39+
public int ReturnParam(int input)
40+
{
41+
return input;
42+
}
43+
}
44+
}
45+
}

csharp/ql/test/utils/model-generator/Summaries.cs

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Linq;
3+
using System.Collections.Generic;
24

35
namespace Summaries;
46

@@ -31,6 +33,21 @@ public string ReturnSubstring(string s)
3133
return s.Substring(0, 1);
3234
}
3335

36+
public void SetField(string s)
37+
{
38+
tainted = s;
39+
}
40+
41+
public string ReturnField()
42+
{
43+
return tainted;
44+
}
45+
}
46+
47+
public class CollectionFlow
48+
{
49+
private string tainted;
50+
3451
public int ReturnArrayElement(int[] input)
3552
{
3653
return input[0];
@@ -41,18 +58,117 @@ public void AssignToArray(int data, int[] target)
4158
target[0] = data;
4259
}
4360

44-
public void SetField(string s)
61+
public void AssignFieldToArray(object[] target)
4562
{
46-
tainted = s;
63+
target[0] = tainted;
4764
}
4865

49-
public string ReturnField()
66+
public object ReturnListElement(List<object> input)
67+
{
68+
return input[0];
69+
}
70+
71+
public void AddToList(List<object> input, object data)
72+
{
73+
input.Add(data);
74+
}
75+
76+
public void AddFieldToList(List<string> input)
77+
{
78+
input.Add(tainted);
79+
}
80+
81+
public List<string> ReturnFieldInAList()
82+
{
83+
return new List<string> { tainted };
84+
}
85+
}
86+
87+
public class IEnumerableFlow
88+
{
89+
private string tainted;
90+
91+
public IEnumerable<string> ReturnIEnumerable(IEnumerable<string> input)
92+
{
93+
return input;
94+
}
95+
96+
public object ReturnIEnumerableElement(IEnumerable<object> input)
97+
{
98+
return input.First();
99+
}
100+
101+
public IEnumerable<string> ReturnFieldInIEnumerable()
102+
{
103+
return new List<string> { tainted };
104+
}
105+
}
106+
107+
public class GenericFlow<T>
108+
{
109+
private T tainted;
110+
111+
public void SetGenericField(T t)
112+
{
113+
tainted = t;
114+
}
115+
116+
public T ReturnGenericField()
50117
{
51118
return tainted;
52119
}
53120

54-
public void AssignFieldToArray(object[] target)
121+
public void AddFieldToGenericList(List<T> input)
55122
{
56-
target[0] = tainted;
123+
input.Add(tainted);
124+
}
125+
126+
public List<T> ReturnFieldInGenericList()
127+
{
128+
return new List<T> { tainted };
129+
}
130+
131+
public S ReturnGenericParam<S>(S input)
132+
{
133+
return input;
134+
}
135+
136+
public S ReturnGenericElement<S>(List<S> input)
137+
{
138+
return input[0];
139+
}
140+
141+
public void AddToGenericList<S>(List<S> input, S data)
142+
{
143+
input.Add(data);
57144
}
58145
}
146+
147+
public abstract class BaseClassFlow
148+
{
149+
public virtual int ReturnParam(int input)
150+
{
151+
return input;
152+
}
153+
}
154+
155+
public class DerivedClass1Flow : BaseClassFlow
156+
{
157+
public int ReturnParam1(int input0, int input1)
158+
{
159+
return input1;
160+
}
161+
}
162+
163+
public class DerivedClass2Flow : BaseClassFlow
164+
{
165+
public override int ReturnParam(int input)
166+
{
167+
return input;
168+
}
169+
170+
public int ReturnParam0(int input0, int input1)
171+
{
172+
return input0;
173+
}
174+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle-extractor-options: /r:System.Linq.dll

0 commit comments

Comments
 (0)