C#: Re-factor CSV validation into a separate file.

This commit is contained in:
Michael Nebel
2022-08-04 09:28:04 +02:00
parent 8db454aa15
commit 19469a26d7
7 changed files with 126 additions and 119 deletions

View File

@@ -0,0 +1,112 @@
/** Provides a query predicate to check the CSV data for validation errors. */
import csharp
private import internal.AccessPathSyntax
private import internal.FlowSummaryImpl::Private::External
private import internal.FlowSummaryImplSpecific
private import ExternalFlow
/** Holds if some row in a CSV-based flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
exists(
string pred, string namespace, string type, string name, string signature, string ext,
string provenance
|
sourceModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "source"
or
sinkModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
or
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance) and
pred = "summary"
or
negativeSummaryModel(namespace, type, name, signature, provenance) and
ext = "" and
pred = "nonesummary"
|
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
or
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
msg = "Dubious type \"" + type + "\" in " + pred + " model."
or
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
msg = "Dubious member name \"" + name + "\" in " + pred + " model."
or
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+\\*,\\[\\]]*\\)") and
msg = "Dubious signature \"" + signature + "\" in " + pred + " model."
or
not ext.regexpMatch("|Attribute") and
msg = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
or
not provenance = ["manual", "generated"] and
msg = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
)
or
exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
or
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
|
(
invalidSpecComponent(input, part) and
not part = "" and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _)
or
part = input.getToken(_) and
parseParam(part, _)
) and
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
)
or
exists(string pred, string output, string part |
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
or
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
|
invalidSpecComponent(output, part) and
not part = "" and
not (part = ["Argument", "Parameter"] and pred = "source") and
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
)
or
exists(string pred, string row, int expect |
sourceModel(row) and expect = 9 and pred = "source"
or
sinkModel(row) and expect = 9 and pred = "sink"
or
summaryModel(row) and expect = 10 and pred = "summary"
|
exists(int cols |
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
cols != expect and
msg =
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
" in " + row + "."
)
or
exists(string b |
b = row.splitAt(";", 2) and
not b = ["true", "false"] and
msg = "Invalid boolean \"" + b + "\" in " + pred + " model."
)
)
or
exists(string row, string kind | summaryModel(row) |
kind = row.splitAt(";", 8) and
not kind = ["taint", "value"] and
msg = "Invalid kind \"" + kind + "\" in summary model."
)
or
exists(string row, string kind | sinkModel(row) |
kind = row.splitAt(";", 7) and
not kind = ["code", "sql", "xss", "remote", "html"] and
msg = "Invalid kind \"" + kind + "\" in sink model."
)
or
exists(string row, string kind | sourceModel(row) |
kind = row.splitAt(";", 7) and
not kind = "local" and
msg = "Invalid kind \"" + kind + "\" in source model."
)
}

View File

@@ -174,13 +174,17 @@ class NegativeSummaryModelCsv extends Unit {
abstract predicate row(string row);
}
private predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
/** Holds if `row` is a source model. */
predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
private predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
/** Holds if `row` is a sink model. */
predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
private predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
/** Holds if `row` is a summary model. */
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
private predicate negativeSummaryModel(string row) { any(NegativeSummaryModelCsv s).row(row) }
/** Holds if `row` is a negative summary model. */
predicate negativeSummaryModel(string row) { any(NegativeSummaryModelCsv s).row(row) }
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
@@ -311,115 +315,6 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
)
}
/** Provides a query predicate to check the CSV data for validation errors. */
module CsvValidation {
/** Holds if some row in a CSV-based flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
exists(
string pred, string namespace, string type, string name, string signature, string ext,
string provenance
|
sourceModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "source"
or
sinkModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
or
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance) and
pred = "summary"
or
negativeSummaryModel(namespace, type, name, signature, provenance) and
ext = "" and
pred = "nonesummary"
|
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
msg = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
or
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
msg = "Dubious type \"" + type + "\" in " + pred + " model."
or
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
msg = "Dubious member name \"" + name + "\" in " + pred + " model."
or
not signature.regexpMatch("|\\([a-zA-Z0-9_<>\\.\\+\\*,\\[\\]]*\\)") and
msg = "Dubious signature \"" + signature + "\" in " + pred + " model."
or
not ext.regexpMatch("|Attribute") and
msg = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
or
not provenance = ["manual", "generated"] and
msg = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
)
or
exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
or
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
|
(
invalidSpecComponent(input, part) and
not part = "" and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _)
or
part = input.getToken(_) and
parseParam(part, _)
) and
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
)
or
exists(string pred, string output, string part |
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
or
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
|
invalidSpecComponent(output, part) and
not part = "" and
not (part = ["Argument", "Parameter"] and pred = "source") and
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
)
or
exists(string pred, string row, int expect |
sourceModel(row) and expect = 9 and pred = "source"
or
sinkModel(row) and expect = 9 and pred = "sink"
or
summaryModel(row) and expect = 10 and pred = "summary"
|
exists(int cols |
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
cols != expect and
msg =
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
" in " + row + "."
)
or
exists(string b |
b = row.splitAt(";", 2) and
not b = ["true", "false"] and
msg = "Invalid boolean \"" + b + "\" in " + pred + " model."
)
)
or
exists(string row, string kind | summaryModel(row) |
kind = row.splitAt(";", 8) and
not kind = ["taint", "value"] and
msg = "Invalid kind \"" + kind + "\" in summary model."
)
or
exists(string row, string kind | sinkModel(row) |
kind = row.splitAt(";", 7) and
not kind = ["code", "sql", "xss", "remote", "html"] and
not kind.matches("encryption-%") and
msg = "Invalid kind \"" + kind + "\" in sink model."
)
or
exists(string row, string kind | sourceModel(row) |
kind = row.splitAt(";", 7) and
not kind = ["local", "file"] and
msg = "Invalid kind \"" + kind + "\" in source model."
)
}
}
private predicate elementSpec(
string namespace, string type, boolean subtypes, string name, string signature, string ext
) {

View File

@@ -1,3 +1,4 @@
invalidModelRow
edges
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object |
| ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | ExternalFlow.cs:10:18:10:33 | call to method StepArgRes |
@@ -151,7 +152,6 @@ nodes
| ExternalFlow.cs:196:18:196:40 | call to method MixedFlowArgs | semmle.label | call to method MixedFlowArgs |
| ExternalFlow.cs:196:38:196:39 | access to local variable o2 : Object | semmle.label | access to local variable o2 : Object |
subpaths
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 |
| ExternalFlow.cs:18:18:18:24 | access to local variable argOut1 | ExternalFlow.cs:15:29:15:40 | object creation of type Object : Object | ExternalFlow.cs:18:18:18:24 | access to local variable argOut1 | $@ | ExternalFlow.cs:15:29:15:40 | object creation of type Object : Object | object creation of type Object : Object |

View File

@@ -3,9 +3,9 @@
*/
import csharp
import semmle.code.csharp.dataflow.ExternalFlow
import DataFlow::PathGraph
import CsvValidation
import semmle.code.csharp.dataflow.CsvValidation
import semmle.code.csharp.dataflow.ExternalFlow
class SummaryModelTest extends SummaryModelCsv {
override predicate row(string row) {

View File

@@ -1,8 +1,8 @@
import csharp
import DataFlow
import semmle.code.csharp.dataflow.CsvValidation
import semmle.code.csharp.dataflow.ExternalFlow
import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation
class SinkModelTest extends SinkModelCsv {
override predicate row(string row) {

View File

@@ -1,8 +1,8 @@
import csharp
import DataFlow
import semmle.code.csharp.dataflow.CsvValidation
import semmle.code.csharp.dataflow.ExternalFlow
import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation
class SourceModelTest extends SourceModelCsv {
override predicate row(string row) {

View File

@@ -1,10 +1,10 @@
import csharp
import DataFlow
import semmle.code.csharp.dataflow.CsvValidation
import semmle.code.csharp.dataflow.ExternalFlow
import semmle.code.csharp.dataflow.FlowSummary
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import CsvValidation
private class SummaryModelTest extends SummaryModelCsv {
override predicate row(string row) {