Skip to content

Commit e488a74

Browse files
committed
Merge branch 'tob/quantum-csharp' of github.com:trailofbits/codeql into tob/quantum-csharp
2 parents 50c98f6 + 3e70e8e commit e488a74

File tree

2 files changed

+81
-42
lines changed

2 files changed

+81
-42
lines changed

csharp/ql/lib/experimental/quantum/dotnet/FlowAnalysis.qll

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -191,43 +191,21 @@ module ModeLiteralFlow {
191191
* `ToArray()` on the stream, or a wrapped stream.
192192
*/
193193
module StreamFlow {
194-
private class Stream extends Class {
195-
Stream() { this.getABaseType().hasFullyQualifiedName("System.IO", "Stream") }
196-
}
197-
198-
/**
199-
* A `Stream` object creation.
200-
*/
201-
private class StreamCreation extends ObjectCreation {
202-
StreamCreation() { this.getObjectType() instanceof Stream }
203-
204-
Expr getInputArg() {
205-
result = this.getAnArgument() and
206-
result.getType().hasFullyQualifiedName("System", "Byte[]")
207-
}
208-
209-
Expr getStreamArg() {
210-
result = this.getAnArgument() and
211-
result.getType() instanceof Stream
212-
}
213-
}
214-
215-
private class StreamUse extends MethodCall {
216-
StreamUse() {
217-
this.getQualifier().getType() instanceof Stream and
218-
this.getTarget().hasName("ToArray")
219-
}
220-
221-
Expr getOutput() { result = this }
222-
}
223-
224194
private module StreamConfig implements DataFlow::ConfigSig {
225-
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StreamCreation }
195+
predicate isSource(DataFlow::Node source) {
196+
source.asExpr() instanceof StreamCreation
197+
or
198+
exists(StreamUse use | source.asExpr() = use.getQualifier())
199+
or
200+
exists(Expr use | source.asExpr() = use and use.getType() instanceof Stream)
201+
}
226202

227203
predicate isSink(DataFlow::Node sink) {
228204
sink.asExpr() instanceof StreamCreation
229205
or
230206
exists(StreamUse use | sink.asExpr() = use.getQualifier())
207+
or
208+
exists(Expr use | sink.asExpr() = use and use.getType() instanceof Stream)
231209
}
232210

233211
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
@@ -247,21 +225,25 @@ module StreamFlow {
247225

248226
private module StreamFlow = DataFlow::Global<StreamConfig>;
249227

250-
StreamCreation getWrappedStream(
228+
StreamCreation getWrappedStreamCreation(
251229
StreamCreation stream, StreamFlow::PathNode source, StreamFlow::PathNode sink
252230
) {
253231
source.getNode().asExpr() = result and
254232
sink.getNode().asExpr() = stream and
255233
StreamFlow::flowPath(source, sink)
256234
}
257235

258-
StreamUse getStreamUse(
259-
StreamCreation stream, StreamFlow::PathNode source, StreamFlow::PathNode sink
260-
) {
261-
source.getNode().asExpr() = stream and
236+
StreamUse getLaterUse(Expr use, StreamFlow::PathNode source, StreamFlow::PathNode sink) {
237+
source.getNode().asExpr() = use and
262238
sink.getNode().asExpr() = result.getQualifier() and
263239
StreamFlow::flowPath(source, sink)
264240
}
241+
242+
StreamUse getEarlierUse(Expr use, StreamFlow::PathNode source, StreamFlow::PathNode sink) {
243+
source.getNode().asExpr() = result.getQualifier() and
244+
sink.getNode().asExpr() = use and
245+
StreamFlow::flowPath(source, sink)
246+
}
265247
}
266248

267249
/**

csharp/ql/lib/experimental/quantum/dotnet/OperationInstances.qll

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,46 @@ class CipherMode extends MemberConstant {
169169
}
170170
}
171171

172+
class Stream extends Class {
173+
Stream() { this.getABaseType().hasFullyQualifiedName("System.IO", "Stream") }
174+
}
175+
176+
/**
177+
* A `Stream` object creation.
178+
*/
179+
class StreamCreation extends ObjectCreation {
180+
StreamCreation() { this.getObjectType() instanceof Stream }
181+
182+
Expr getInputArg() {
183+
result = this.getAnArgument() and
184+
result.getType().hasFullyQualifiedName("System", "Byte[]")
185+
}
186+
187+
Expr getStreamArg() {
188+
result = this.getAnArgument() and
189+
result.getType() instanceof Stream
190+
}
191+
}
192+
193+
class StreamUse extends MethodCall {
194+
StreamUse() {
195+
this.getQualifier().getType() instanceof Stream and
196+
this.getTarget().hasName(["ToArray", "Write"])
197+
}
198+
199+
predicate isIntermediate() { this.getTarget().hasName("Write") }
200+
201+
Expr getInputArg() {
202+
this.isIntermediate() and
203+
result = this.getArgument(0)
204+
}
205+
206+
Expr getOutput() {
207+
not this.isIntermediate() and
208+
result = this
209+
}
210+
}
211+
172212
class CryptoStreamCreation extends ObjectCreation {
173213
CryptoStreamCreation() { this.getObjectType() instanceof CryptoStream }
174214

@@ -253,11 +293,16 @@ class CryptoStreamOperationInstance extends Crypto::KeyOperationInstance instanc
253293
)
254294
}
255295

256-
// Inputs can be passed either through the `stream` argument when the
257-
// `CryptoStream` is created, or through calls to `Write()` on the
258-
// `CryptoStream` object.
296+
// Inputs can be passed to the `CryptoStream` instance in a number of ways.
297+
//
298+
// 1. Through the `stream` argument when the `CryptoStream` is created
299+
// 2. Through calls to `Write()` on (a stream wrapped by) the stream argument
300+
// 3. Through calls to write on this `CryptoStream` object
259301
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
260-
result.asExpr() = StreamFlow::getWrappedStream(this, _, _).getInputArg() or
302+
result.asExpr() = this.getWrappedStreamCreation().getInputArg()
303+
or
304+
result.asExpr() = this.getEarlierWrappedStreamUse().getInputArg()
305+
or
261306
result.asExpr() = CryptoStreamFlow::getUseFromCreation(this, _, _).getInputArg()
262307
}
263308

@@ -267,7 +312,19 @@ class CryptoStreamOperationInstance extends Crypto::KeyOperationInstance instanc
267312
// We perform backwards dataflow to identify stream objects that are wrapped
268313
// by the `CryptoStream` object, and then we look for calls to `ToArray()`
269314
// on those streams.
270-
result.asExpr() =
271-
StreamFlow::getStreamUse(any(StreamFlow::getWrappedStream(this, _, _)), _, _).getOutput()
315+
result.asExpr() = this.getLaterWrappedStreamUse().getOutput()
316+
}
317+
318+
// Gets either this stream, or a stream wrapped by this stream.
319+
StreamCreation getWrappedStreamCreation() {
320+
result = StreamFlow::getWrappedStreamCreation(this, _, _)
321+
}
322+
323+
StreamUse getEarlierWrappedStreamUse() {
324+
result = StreamFlow::getEarlierUse(this.getWrappedStreamCreation().getStreamArg(), _, _)
325+
}
326+
327+
StreamUse getLaterWrappedStreamUse() {
328+
result = StreamFlow::getLaterUse(this.getWrappedStreamCreation().getStreamArg(), _, _)
272329
}
273330
}

0 commit comments

Comments
 (0)