C#: Teach data flow library about CFG splitting

Data flow nodes for expressions do not take CFG splitting into account. Example:

```
if (b)
    x = tainted;
x = x.ToLower();
if (!b)
    Use(x);
```

Flow is incorrectly reported from `tainted` to `x` in `Use(x)`, because the step
from `tainted` to `x.ToLower()` throws away the information that `b = true`.

The solution is to remember the splitting in data flow expression nodes, that is,
to represent the exact control flow node instead of just the expression. With that
we get flow from `tainted` to `[b = true] x.ToLower()`, but not from `tainted` to
`[b = false] x.ToLower()`.

The data flow API remains unchanged, but in order for analyses to fully benefit from
CFG splitting, sanitizers in particular should be CFG-based instead of expression-based:

```
if (b)
   x = tainted;
   if (IsInvalid(x))
       return;
Use(x);
```

If the call to `IsInvalid()` is a sanitizer, then defining an expression node to be
a sanitizer using `GuardedExpr` will be too conservative (`x` in `Use(x)` is in fact
not guarded). However, `[b = true] x` in `[b = true] Use(x)` is guarded, and to help
defining guard-based sanitizers, the class `GuardedDataFlowNode` has been introduced.
This commit is contained in:
Tom Hvitved
2019-01-03 15:28:15 +01:00
parent f768abb0e6
commit b2f99dbbc7
27 changed files with 811 additions and 344 deletions

View File

@@ -399,5 +399,5 @@
| ViableCallable.cs:422:13:422:37 | call to method Mock | ViableCallable.Mock<A4>() |
| ViableCallable.cs:424:9:424:21 | call to method M | C15.A4.M<T1>() |
| ViableCallable.cs:424:9:424:21 | call to method M | C15.A5.M<T1>() |
| ViableCallable.cs:439:16:439:26 | call to method M1 | C16<String,Int32>.M1(string) |
| ViableCallable.cs:439:9:439:19 | call to method M1 | C16<String,Int32>.M1(string) |
| ViableCallable.cs:442:9:442:24 | call to method M2 | C16<String,Int32>.M2<T>(Func<T>) |