C#: Handle CSV data-flow summaries with out/ref parameters

This commit is contained in:
Tom Hvitved
2021-06-24 15:15:25 +02:00
parent 1e511c0a9e
commit 7a9f9e245f
9 changed files with 383 additions and 368 deletions

View File

@@ -35,22 +35,6 @@ module SummaryComponent {
/** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = return(any(NormalReturnKind rk)) }
/**
* Gets a summary component that represents the return value through the `i`th
* `out` argument of a call.
*/
SummaryComponent outArgument(int i) {
result = return(any(OutReturnKind rk | rk.getPosition() = i))
}
/**
* Gets a summary component that represents the return value through the `i`th
* `ref` argument of a call.
*/
SummaryComponent refArgument(int i) {
result = return(any(RefReturnKind rk | rk.getPosition() = i))
}
/** Gets a summary component that represents a jump to `c`. */
SummaryComponent jump(Callable c) {
result =
@@ -88,18 +72,6 @@ module SummaryComponentStack {
/** Gets a singleton stack representing the return value of a call. */
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }
/**
* Gets a singleton stack representing the return value through the `i`th
* `out` argument of a call.
*/
SummaryComponentStack outArgument(int i) { result = singleton(SummaryComponent::outArgument(i)) }
/**
* Gets a singleton stack representing the return value through the `i`th
* `ref` argument of a call.
*/
SummaryComponentStack refArgument(int i) { result = singleton(SummaryComponent::refArgument(i)) }
/** Gets a singleton stack representing a jump to `c`. */
SummaryComponentStack jump(Callable c) { result = singleton(SummaryComponent::jump(c)) }
}

View File

@@ -383,7 +383,7 @@ private module FrameworkDataFlowAdaptor {
or
exists(int i |
result = TCallableFlowSinkArg(i) and
output = SummaryComponentStack::outArgument(i)
output = SummaryComponentStack::argument(i)
)
or
exists(int i, int j | result = TCallableFlowSinkDelegateArg(i, j) |

View File

@@ -1258,12 +1258,33 @@ private module ReturnNodes {
SummaryReturnNode() {
FlowSummaryImpl::Private::summaryReturnNode(this, rk) and
not rk instanceof JumpReturnKind
or
exists(Parameter p, int pos |
summaryPostUpdateNodeIsOutOrRef(this, p) and
pos = p.getPosition()
|
p.isOut() and rk.(OutReturnKind).getPosition() = pos
or
p.isRef() and rk.(RefReturnKind).getPosition() = pos
)
}
override ReturnKind getKind() { result = rk }
}
}
/**
* Holds if summary node `n` is a post-update node for `out`/`ref` parameter `p`.
* In this case we adjust it to instead be a return node.
*/
private predicate summaryPostUpdateNodeIsOutOrRef(SummaryNode n, Parameter p) {
exists(ParameterNode pn |
FlowSummaryImpl::Private::summaryPostUpdateNode(n, pn) and
pn.getParameter() = p and
p.isOutOrRef()
)
}
import ReturnNodes
/** A data-flow node that represents the output of a call. */
@@ -1841,7 +1862,10 @@ private module PostUpdateNodes {
}
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, _) }
SummaryPostUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this, _) and
not summaryPostUpdateNodeIsOutOrRef(this, _)
}
override Node getPreUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this, result)

View File

@@ -85,6 +85,13 @@ namespace My.Qltest
Sink(objs2[0]);
}
void M14()
{
var s = new string("");
Parse(s, out var i);
Sink(i);
}
object StepArgRes(object x) { return null; }
void StepArgArg(object @in, object @out) { }
@@ -115,6 +122,8 @@ namespace My.Qltest
static S[] Map<S, T>(S[] elements, Func<S, T> f) => throw null;
static void Parse(string s, out int i) => throw null;
static void Sink(object o) { }
}
}

View File

@@ -24,12 +24,12 @@ edges
| ExternalFlow.cs:54:36:54:47 | object creation of type Object : Object | ExternalFlow.cs:54:13:54:16 | [post] this access [element] : Object |
| ExternalFlow.cs:55:18:55:21 | this access [element] : Object | ExternalFlow.cs:55:18:55:41 | call to method StepElementGetter |
| ExternalFlow.cs:60:35:60:35 | o : Object | ExternalFlow.cs:60:47:60:47 | access to parameter o |
| ExternalFlow.cs:60:64:60:75 | object creation of type Object : Object | ExternalFlow.cs:114:46:114:46 | s : Object |
| ExternalFlow.cs:60:64:60:75 | object creation of type Object : Object | ExternalFlow.cs:121:46:121:46 | s : Object |
| ExternalFlow.cs:65:21:65:60 | call to method Apply : Object | ExternalFlow.cs:66:18:66:18 | access to local variable o |
| ExternalFlow.cs:65:45:65:56 | object creation of type Object : Object | ExternalFlow.cs:65:21:65:60 | call to method Apply : Object |
| ExternalFlow.cs:71:30:71:45 | { ..., ... } [element] : Object | ExternalFlow.cs:72:17:72:20 | access to local variable objs [element] : Object |
| ExternalFlow.cs:71:32:71:43 | object creation of type Object : Object | ExternalFlow.cs:71:30:71:45 | { ..., ... } [element] : Object |
| ExternalFlow.cs:72:17:72:20 | access to local variable objs [element] : Object | ExternalFlow.cs:116:34:116:41 | elements [element] : Object |
| ExternalFlow.cs:72:17:72:20 | access to local variable objs [element] : Object | ExternalFlow.cs:123:34:123:41 | elements [element] : Object |
| ExternalFlow.cs:72:23:72:23 | o : Object | ExternalFlow.cs:72:35:72:35 | access to parameter o |
| ExternalFlow.cs:77:24:77:58 | call to method Map [element] : Object | ExternalFlow.cs:78:18:78:21 | access to local variable objs [element] : Object |
| ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | ExternalFlow.cs:77:24:77:58 | call to method Map [element] : Object |
@@ -40,8 +40,11 @@ edges
| ExternalFlow.cs:84:25:84:41 | call to method Map [element] : Object | ExternalFlow.cs:85:18:85:22 | access to local variable objs2 [element] : Object |
| ExternalFlow.cs:84:29:84:32 | access to local variable objs [element] : Object | ExternalFlow.cs:84:25:84:41 | call to method Map [element] : Object |
| ExternalFlow.cs:85:18:85:22 | access to local variable objs2 [element] : Object | ExternalFlow.cs:85:18:85:25 | access to array element |
| ExternalFlow.cs:114:46:114:46 | s : Object | ExternalFlow.cs:60:35:60:35 | o : Object |
| ExternalFlow.cs:116:34:116:41 | elements [element] : Object | ExternalFlow.cs:72:23:72:23 | o : Object |
| ExternalFlow.cs:90:21:90:34 | object creation of type String : String | ExternalFlow.cs:91:19:91:19 | access to local variable s : String |
| ExternalFlow.cs:91:19:91:19 | access to local variable s : String | ExternalFlow.cs:91:30:91:30 | SSA def(i) : Int32 |
| ExternalFlow.cs:91:30:91:30 | SSA def(i) : Int32 | ExternalFlow.cs:92:18:92:18 | (...) ... |
| ExternalFlow.cs:121:46:121:46 | s : Object | ExternalFlow.cs:60:35:60:35 | o : Object |
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | ExternalFlow.cs:72:23:72:23 | o : Object |
nodes
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
| ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | semmle.label | call to method StepArgRes |
@@ -97,8 +100,12 @@ nodes
| ExternalFlow.cs:84:29:84:32 | access to local variable objs [element] : Object | semmle.label | access to local variable objs [element] : Object |
| ExternalFlow.cs:85:18:85:22 | access to local variable objs2 [element] : Object | semmle.label | access to local variable objs2 [element] : Object |
| ExternalFlow.cs:85:18:85:25 | access to array element | semmle.label | access to array element |
| ExternalFlow.cs:114:46:114:46 | s : Object | semmle.label | s : Object |
| ExternalFlow.cs:116:34:116:41 | elements [element] : Object | semmle.label | elements [element] : Object |
| ExternalFlow.cs:90:21:90:34 | object creation of type String : String | semmle.label | object creation of type String : String |
| ExternalFlow.cs:91:19:91:19 | access to local variable s : String | semmle.label | access to local variable s : String |
| ExternalFlow.cs:91:30:91:30 | SSA def(i) : Int32 | semmle.label | SSA def(i) : Int32 |
| ExternalFlow.cs:92:18:92:18 | (...) ... | semmle.label | (...) ... |
| ExternalFlow.cs:121:46:121:46 | s : Object | semmle.label | s : Object |
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | semmle.label | elements [element] : Object |
invalidModelRow
#select
| ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | $@ | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | object creation of type Object : Object |
@@ -115,3 +122,4 @@ invalidModelRow
| ExternalFlow.cs:72:35:72:35 | access to parameter o | ExternalFlow.cs:71:32:71:43 | object creation of type Object : Object | ExternalFlow.cs:72:35:72:35 | access to parameter o | $@ | ExternalFlow.cs:71:32:71:43 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:78:18:78:24 | (...) ... | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | ExternalFlow.cs:78:18:78:24 | (...) ... | $@ | ExternalFlow.cs:77:46:77:57 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:85:18:85:25 | access to array element | ExternalFlow.cs:83:32:83:43 | object creation of type Object : Object | ExternalFlow.cs:85:18:85:25 | access to array element | $@ | ExternalFlow.cs:83:32:83:43 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:92:18:92:18 | (...) ... | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | ExternalFlow.cs:92:18:92:18 | (...) ... | $@ | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | object creation of type String : String |

View File

@@ -24,7 +24,8 @@ class SummaryModelTest extends SummaryModelCsv {
"My.Qltest;D;false;Apply;(System.Func<S,T>,S);;Argument[1];Parameter[0] of Argument[0];value",
"My.Qltest;D;false;Apply;(System.Func<S,T>,S);;ReturnValue of Argument[0];ReturnValue;value",
"My.Qltest;D;false;Map;(S[],System.Func<S,T>);;Element of Argument[0];Parameter[0] of Argument[1];value",
"My.Qltest;D;false;Map;(S[],System.Func<S,T>);;ReturnValue of Argument[1];Element of ReturnValue;value"
"My.Qltest;D;false;Map;(S[],System.Func<S,T>);;ReturnValue of Argument[1];Element of ReturnValue;value",
"My.Qltest;D;false;Parse;(System.String,System.Int32);;Argument[0];Argument[1];taint"
]
}
}

View File

@@ -34,7 +34,7 @@ namespace JsonTest
Object taintedPopulatedObject = new Object();
JsonConvert.PopulateObject(t, taintedPopulatedObject);
Sink(taintedPopulatedObject.tainted); // False negative
Sink(taintedPopulatedObject.tainted);
Object untaintedObject = JsonConvert.DeserializeObject<Object>(u);
Sink(untaintedObject);

View File

@@ -5,6 +5,7 @@
| Json.cs:18:24:18:32 | "tainted" | Json.cs:28:18:28:49 | access to indexer |
| Json.cs:18:24:18:32 | "tainted" | Json.cs:29:18:29:46 | access to array element |
| Json.cs:18:24:18:32 | "tainted" | Json.cs:32:18:32:39 | (...) ... |
| Json.cs:18:24:18:32 | "tainted" | Json.cs:37:18:37:47 | (...) ... |
| Json.cs:18:24:18:32 | "tainted" | Json.cs:44:18:44:24 | access to local variable jobject |
| Json.cs:18:24:18:32 | "tainted" | Json.cs:45:18:45:29 | access to indexer |
| Json.cs:18:24:18:32 | "tainted" | Json.cs:46:18:46:34 | access to indexer |