Skip to content

Commit 92198e1

Browse files
Add local file writes as external location sinks
1 parent be6af4b commit 92198e1

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import csharp
66
private import Remote
77
private import semmle.code.csharp.commons.Loggers
88
private import semmle.code.csharp.frameworks.system.Web
9+
private import semmle.code.csharp.frameworks.system.IO
910
private import semmle.code.csharp.dataflow.ExternalFlow
11+
private import semmle.code.csharp.dataflow.DataFlow
1012

1113
/**
1214
* An external location sink.
@@ -63,3 +65,66 @@ class CookieStorageSink extends ExternalLocationSink, RemoteFlowSink {
6365
)
6466
}
6567
}
68+
69+
private predicate isFileWriteCall(Expr stream, Expr data) {
70+
exists(MethodCall mc, Method m | mc.getTarget() = m.getAnOverrider*() |
71+
mc.getTarget().hasQualifiedName("System.IO", "Stream", ["Write", "WriteAsync"]) and
72+
stream = mc.getQualifier() and
73+
data = mc.getArgument(0)
74+
or
75+
mc.getTarget()
76+
.hasQualifiedName("System.IO", "TextWriter",
77+
["Write", "WriteAsync", "WriteLine", "WriteLineAsync"]) and
78+
stream = mc.getQualifier() and
79+
data = mc.getArgument(0)
80+
or
81+
mc.getTarget().hasQualifiedName("System.Xml.Linq", "XDocument", ["Save", "SaveAsync"]) and
82+
data = mc.getQualifier() and
83+
stream = mc.getArgument(0)
84+
)
85+
}
86+
87+
private module LocalFileOutputStreamConfig implements DataFlow::ConfigSig {
88+
predicate isSource(DataFlow::Node src) {
89+
exists(MethodCall mc | mc = src.asExpr() |
90+
mc.getTarget().hasQualifiedName("System.IO", "File", ["Open", "Create", "OpenWrite"])
91+
or
92+
mc.getTarget()
93+
.hasQualifiedName("System.IO", "FileInfo",
94+
["AppendText", "Create", "CreateText", "Open", "OpenText", "OpenWrite"])
95+
)
96+
or
97+
exists(ObjectCreation oc | oc = src.asExpr() |
98+
oc.getObjectType() instanceof SystemIOStreamWriterClass and
99+
oc.getArgument(0).getType() instanceof StringType
100+
)
101+
}
102+
103+
predicate isSink(DataFlow::Node sink) { isFileWriteCall(sink.asExpr(), _) }
104+
105+
predicate isBarrier(DataFlow::Node node) {
106+
node.asExpr()
107+
.(ObjectCreation)
108+
.getObjectType()
109+
.hasQualifiedName("System.Security.Cryptography", "CryptoStream")
110+
}
111+
112+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
113+
exists(ObjectCreation oc |
114+
node2.asExpr() = oc and
115+
node1.asExpr() = oc.getArgument(0) and
116+
oc.getObjectType() instanceof SystemIOStreamWriterClass
117+
)
118+
}
119+
}
120+
121+
private module LocalFileOutputStreamFlow = DataFlow::Make<LocalFileOutputStreamConfig>;
122+
123+
class LocalFileOutputSink extends ExternalLocationSink {
124+
LocalFileOutputSink() {
125+
exists(DataFlow::Node streamSink |
126+
LocalFileOutputStreamFlow::hasFlow(_, streamSink) and
127+
isFileWriteCall(streamSink.asExpr(), this.asExpr())
128+
)
129+
}
130+
}

0 commit comments

Comments
 (0)