From 60f3ff8c33f94f12b21d26d491d881b4b4020c02 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 8 Dec 2021 12:01:48 +0100 Subject: [PATCH 1/6] C#: Introduce type for Synthetic fields. --- .../code/csharp/dataflow/internal/DataFlowPrivate.qll | 10 +++++++++- .../code/csharp/dataflow/internal/DataFlowPublic.qll | 10 ++++++++++ .../dataflow/internal/FlowSummaryImplSpecific.qll | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 4d588adcfc0..4521fe64247 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -759,7 +759,8 @@ private module Cached { newtype TContent = TFieldContent(Field f) { f.isUnboundDeclaration() } or TPropertyContent(Property p) { p.isUnboundDeclaration() } or - TElementContent() + TElementContent() or + TSyntheticFieldContent(SyntheticField f) pragma[nomagic] private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) { @@ -2038,3 +2039,10 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves predicate allowParameterReturnInSelf(ParameterNode p) { FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p) } + +abstract class SyntheticField extends string { + bindingset[this] + SyntheticField() { any() } + + Type getType() { result instanceof ObjectType } +} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index fa99d518bbd..c554c86be40 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -224,6 +224,16 @@ class FieldContent extends Content, TFieldContent { deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } } +class SyntheticFieldContent extends Content, TSyntheticFieldContent { + private SyntheticField f; + + SyntheticFieldContent() { this = TSyntheticFieldContent(f) } + + SyntheticField getField() { result = f } + + override string toString() { result = "synthetic " + f.toString() } +} + /** A reference to a property. */ class PropertyContent extends Content, TPropertyContent { private Property p; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll index 47664f9b650..84ded304e2f 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll @@ -29,6 +29,8 @@ DataFlowType getContentType(Content c) { or t = c.(PropertyContent).getProperty().getType() or + t = c.(SyntheticFieldContent).getField().getType() + or c instanceof ElementContent and t instanceof ObjectType // we don't know what the actual element type is ) From 063398f24dee24edf0e2a78f649246ef4a6f9a87 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 8 Dec 2021 12:02:35 +0100 Subject: [PATCH 2/6] C#: Use synthetic fields for Task instead of referring to private fields. --- .../csharp/dataflow/LibraryTypeDataFlow.qll | 71 ++++++++++++------- 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll index 764cd6a280b..221df579e18 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll @@ -102,6 +102,11 @@ module AccessPath { result = singleton(any(FieldContent c | c.getField() = f.getUnboundDeclaration())) } + /** Gets a singleton synthetic field access path. */ + AccessPath synthetic(SyntheticField f) { + result = singleton(any(SyntheticFieldContent c | c.getField() = f)) + } + /** Gets an access path representing a property inside a collection. */ AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) } } @@ -1968,9 +1973,7 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading source = TCallableFlowSourceQualifier() and sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and - sinkAp = - AccessPath::field(any(SystemRuntimeCompilerServicesTaskAwaiterStruct s) - .getUnderlyingTaskField()) + sinkAp = AccessPath::synthetic(any(SyntheticTaskAwaiterUnderlyingTaskField s)) or // var awaitable = task.ConfigureAwait(false); // <-- new ConfiguredTaskAwaitable<>(task, false) // // m_configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, false) @@ -1982,21 +1985,40 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading sourceAp = AccessPath::empty() and sink = TCallableFlowSinkReturn() and sinkAp = - AccessPath::cons(any(FieldContent fc | - fc.getField() = - any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t) - .getUnderlyingAwaiterField() - ), - AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s - ).getUnderlyingTaskField())) + AccessPath::cons(any(SyntheticFieldContent sfc | + sfc.getField() instanceof SyntheticConfiguredTaskAwaiterField + ), AccessPath::synthetic(any(SyntheticConfiguredTaskAwaitableUnderlyingTaskField s))) } override predicate requiresAccessPath(Content head, AccessPath tail) { - head.(FieldContent).getField() = - any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t).getUnderlyingAwaiterField() and - tail = - AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s - ).getUnderlyingTaskField()) + head.(SyntheticFieldContent).getField() instanceof SyntheticConfiguredTaskAwaiterField and + tail = AccessPath::synthetic(any(SyntheticConfiguredTaskAwaitableUnderlyingTaskField s)) + } +} + +abstract private class SyntheticTaskField extends SyntheticField { + bindingset[this] + SyntheticTaskField() { any() } + + override Type getType() { result instanceof SystemThreadingTasksTaskTClass } +} + +private class SyntheticTaskAwaiterUnderlyingTaskField extends SyntheticTaskField { + SyntheticTaskAwaiterUnderlyingTaskField() { this = "m_task_task_awaiter" } +} + +private class SyntheticConfiguredTaskAwaitableUnderlyingTaskField extends SyntheticTaskField { + SyntheticConfiguredTaskAwaitableUnderlyingTaskField() { + this = "m_task_configured_task_awaitable" + } +} + +private class SyntheticConfiguredTaskAwaiterField extends SyntheticField { + SyntheticConfiguredTaskAwaiterField() { this = "m_configuredTaskAwaiter" } + + override Type getType() { + result instanceof + SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct } } @@ -2012,9 +2034,7 @@ private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlow extends // var result = awaiter.GetResult(); c = this.getGetAwaiterMethod() and source = TCallableFlowSourceQualifier() and - sourceAp = - AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct s) - .getUnderlyingAwaiterField()) and + sourceAp = AccessPath::synthetic(any(SyntheticConfiguredTaskAwaiterField s)) and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() and preservesValue = true @@ -2113,14 +2133,15 @@ class SystemRuntimeCompilerServicesTaskAwaiterFlow extends LibraryTypeDataFlow, c = this.getGetResultMethod() and source = TCallableFlowSourceQualifier() and sourceAp = - AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()), - AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and + AccessPath::cons(any(SyntheticFieldContent sfc | + sfc.getField() instanceof SyntheticTaskAwaiterUnderlyingTaskField + ), AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() } override predicate requiresAccessPath(Content head, AccessPath tail) { - head.(FieldContent).getField() = this.getUnderlyingTaskField() and + head.(SyntheticFieldContent).getField() instanceof SyntheticTaskAwaiterUnderlyingTaskField and tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty()) } } @@ -2139,14 +2160,16 @@ class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiter c = this.getGetResultMethod() and source = TCallableFlowSourceQualifier() and sourceAp = - AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()), - AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and + AccessPath::cons(any(SyntheticFieldContent sfc | + sfc.getField() instanceof SyntheticConfiguredTaskAwaitableUnderlyingTaskField + ), AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and sink = TCallableFlowSinkReturn() and sinkAp = AccessPath::empty() } override predicate requiresAccessPath(Content head, AccessPath tail) { - head.(FieldContent).getField() = this.getUnderlyingTaskField() and + head.(SyntheticFieldContent).getField() instanceof + SyntheticConfiguredTaskAwaitableUnderlyingTaskField and tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty()) } } From a43704ab43f035278f723158cc3485cbf660d8f0 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 8 Dec 2021 15:35:55 +0100 Subject: [PATCH 3/6] C#: Update dataflow/global tests based on synthetic fields. --- .../dataflow/global/DataFlowPath.expected | 18 +++++++++--------- .../dataflow/global/TaintTrackingPath.expected | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index 318455f45fc..e6d08065fee 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -253,11 +253,11 @@ edges | GlobalDataFlow.cs:438:22:438:35 | "taint source" : String | GlobalDataFlow.cs:201:22:201:32 | access to property OutProperty : String | | GlobalDataFlow.cs:474:20:474:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | | GlobalDataFlow.cs:474:35:474:48 | "taint source" : String | GlobalDataFlow.cs:474:20:474:49 | call to method Run [property Result] : String | -| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | -| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | +| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | GlobalDataFlow.cs:478:15:478:20 | access to local variable sink45 | | GlobalDataFlow.cs:483:53:483:55 | arg : String | GlobalDataFlow.cs:487:15:487:17 | access to parameter arg : String | | GlobalDataFlow.cs:486:21:486:21 | s : String | GlobalDataFlow.cs:486:32:486:32 | access to parameter s | @@ -513,10 +513,10 @@ nodes | GlobalDataFlow.cs:474:20:474:49 | call to method Run [property Result] : String | semmle.label | call to method Run [property Result] : String | | GlobalDataFlow.cs:474:35:474:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | -| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | semmle.label | call to method GetAwaiter [field m_task, property Result] : String | -| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | semmle.label | access to local variable awaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | semmle.label | call to method GetResult : String | | GlobalDataFlow.cs:478:15:478:20 | access to local variable sink45 | semmle.label | access to local variable sink45 | | GlobalDataFlow.cs:483:53:483:55 | arg : String | semmle.label | arg : String | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index a2ce54ced96..88837707bec 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -279,11 +279,11 @@ edges | GlobalDataFlow.cs:465:51:465:64 | "taint source" : String | GlobalDataFlow.cs:465:22:465:65 | call to method Join : String | | GlobalDataFlow.cs:474:20:474:49 | call to method Run [property Result] : String | GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | | GlobalDataFlow.cs:474:35:474:48 | "taint source" : String | GlobalDataFlow.cs:474:20:474:49 | call to method Run [property Result] : String | -| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | -| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | +| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | GlobalDataFlow.cs:478:15:478:20 | access to local variable sink45 | | GlobalDataFlow.cs:483:53:483:55 | arg : String | GlobalDataFlow.cs:487:15:487:17 | access to parameter arg : String | | GlobalDataFlow.cs:486:21:486:21 | s : String | GlobalDataFlow.cs:486:32:486:32 | access to parameter s | @@ -567,10 +567,10 @@ nodes | GlobalDataFlow.cs:474:20:474:49 | call to method Run [property Result] : String | semmle.label | call to method Run [property Result] : String | | GlobalDataFlow.cs:474:35:474:48 | "taint source" : String | semmle.label | "taint source" : String | | GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String | -| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | -| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | semmle.label | call to method GetAwaiter [field m_task, property Result] : String | -| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | semmle.label | access to local variable awaiter [field m_task, property Result] : String | +| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | +| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | semmle.label | call to method GetResult : String | | GlobalDataFlow.cs:478:15:478:20 | access to local variable sink45 | semmle.label | access to local variable sink45 | | GlobalDataFlow.cs:483:53:483:55 | arg : String | semmle.label | arg : String | From d70d1fbf81c7f68a35eb93d7e6e97c60e5cc3fdd Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 8 Dec 2021 16:01:48 +0100 Subject: [PATCH 4/6] C#: Add support for the use of synthetic fields in flow summary CSV. --- .../csharp/dataflow/internal/FlowSummaryImplSpecific.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll index 84ded304e2f..29d50a1389c 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll @@ -136,6 +136,11 @@ SummaryComponent interpretComponentSpecific(string c) { c.regexpCapture("Property\\[(.+)\\]", 1) = p.getQualifiedName() and result = SummaryComponent::content(any(PropertyContent pc | pc.getProperty() = p)) ) + or + exists(SyntheticField f | + c.regexpCapture("SyntheticField\\[(.+)\\]", 1) = f and + result = SummaryComponent::content(any(SyntheticFieldContent sfc | sfc.getField() = f)) + ) } /** Gets the textual representation of the content in the format used for flow summaries. */ @@ -145,6 +150,8 @@ private string getContentSpecificCsv(Content c) { exists(Field f | c = TFieldContent(f) and result = "Field[" + f.getQualifiedName() + "]") or exists(Property p | c = TPropertyContent(p) and result = "Property[" + p.getQualifiedName() + "]") + or + exists(SyntheticField f | c = TSyntheticFieldContent(f) and result = "SyntheticField[" + f + "]") } /** Gets the textual representation of a summary component in the format used for flow summaries. */ From 9f4b9652020976d9e854484b60121e8911b40c44 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 8 Dec 2021 16:03:18 +0100 Subject: [PATCH 5/6] C#: Update the flow summaries produced for Task<> after introduction of synthetic fields. --- .../library-tests/dataflow/library/FlowSummaries.expected | 5 +++++ .../dataflow/library/FlowSummariesFiltered.expected | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index d49111c3f1b..42006a06785 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -1851,6 +1851,8 @@ | System.Resources;ResourceSet;false;GetEnumerator;();;Element of Argument[-1];Property[System.Collections.IEnumerator.Current] of ReturnValue;value | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetEnumerator;();;Element of Argument[-1];Property[System.Collections.Generic.IEnumerator<>.Current] of ReturnValue;value | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetEnumerator;();;Element of Argument[-1];Property[System.Collections.IEnumerator.Current] of ReturnValue;value | +| System.Runtime.CompilerServices;ConfiguredTaskAwaitable<>+ConfiguredTaskAwaiter;false;GetResult;();;Property[System.Threading.Tasks.Task<>.Result] of SyntheticField[m_task_configured_task_awaitable] of Argument[-1];ReturnValue;value | +| System.Runtime.CompilerServices;ConfiguredTaskAwaitable<>;false;GetAwaiter;();;SyntheticField[m_configuredTaskAwaiter] of Argument[-1];ReturnValue;value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;Add;(System.Object);;Argument[0];Element of Argument[-1];value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;Add;(T);;Argument[0];Element of Argument[-1];value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;CopyTo;(System.Array,System.Int32);;Element of Argument[-1];Element of Argument[0];value | @@ -1864,6 +1866,7 @@ | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;get_Item;(System.Int32);;Element of Argument[-1];ReturnValue;value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;set_Item;(System.Int32,System.Object);;Argument[1];Element of Argument[-1];value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;set_Item;(System.Int32,T);;Argument[1];Element of Argument[-1];value | +| System.Runtime.CompilerServices;TaskAwaiter<>;false;GetResult;();;Property[System.Threading.Tasks.Task<>.Result] of SyntheticField[m_task_task_awaiter] of Argument[-1];ReturnValue;value | | System.Security.Cryptography.X509Certificates;X509Certificate2Collection;false;Add;(System.Security.Cryptography.X509Certificates.X509Certificate2);;Argument[0];Element of Argument[-1];value | | System.Security.Cryptography.X509Certificates;X509Certificate2Collection;false;AddRange;(System.Security.Cryptography.X509Certificates.X509Certificate2Collection);;Element of Argument[0];Element of Argument[-1];value | | System.Security.Cryptography.X509Certificates;X509Certificate2Collection;false;AddRange;(System.Security.Cryptography.X509Certificates.X509Certificate2[]);;Element of Argument[0];Element of Argument[-1];value | @@ -2075,6 +2078,7 @@ | System.Threading.Tasks;Task;false;WhenAny<>;(System.Threading.Tasks.Task,System.Threading.Tasks.Task);;Property[System.Threading.Tasks.Task<>.Result] of Element of Argument[0];Element of Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task;false;WhenAny<>;(System.Threading.Tasks.Task,System.Threading.Tasks.Task);;Property[System.Threading.Tasks.Task<>.Result] of Element of Argument[1];Element of Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task;false;WhenAny<>;(System.Threading.Tasks.Task[]);;Property[System.Threading.Tasks.Task<>.Result] of Element of Argument[0];Element of Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | +| System.Threading.Tasks;Task<>;false;ConfigureAwait;(System.Boolean);;Argument[-1];SyntheticField[m_task_configured_task_awaitable] of SyntheticField[m_configuredTaskAwaiter] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;ContinueWith;(System.Action,System.Object>,System.Object);;Argument[1];Parameter[1] of Argument[0];value | | System.Threading.Tasks;Task<>;false;ContinueWith;(System.Action,System.Object>,System.Object);;Argument[-1];Parameter[0] of Argument[0];value | | System.Threading.Tasks;Task<>;false;ContinueWith;(System.Action,System.Object>,System.Object,System.Threading.CancellationToken);;Argument[1];Parameter[1] of Argument[0];value | @@ -2115,6 +2119,7 @@ | System.Threading.Tasks;Task<>;false;ContinueWith<>;(System.Func,TNewResult>,System.Threading.Tasks.TaskContinuationOptions);;ReturnValue of Argument[0];Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;ContinueWith<>;(System.Func,TNewResult>,System.Threading.Tasks.TaskScheduler);;Argument[-1];Parameter[0] of Argument[0];value | | System.Threading.Tasks;Task<>;false;ContinueWith<>;(System.Func,TNewResult>,System.Threading.Tasks.TaskScheduler);;ReturnValue of Argument[0];Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | +| System.Threading.Tasks;Task<>;false;GetAwaiter;();;Argument[-1];SyntheticField[m_task_task_awaiter] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;Task;(System.Func,System.Object);;Argument[1];Parameter[0] of Argument[0];value | | System.Threading.Tasks;Task<>;false;Task;(System.Func,System.Object);;ReturnValue of Argument[0];Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;Task;(System.Func,System.Object,System.Threading.CancellationToken);;Argument[1];Parameter[0] of Argument[0];value | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected index 9352857fb2a..e24b3273fa2 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected @@ -1566,6 +1566,8 @@ | System.Net;WebUtility;false;HtmlEncode;(System.String,System.IO.TextWriter);;Argument[0];ReturnValue;taint | | System.Net;WebUtility;false;UrlEncode;(System.String);;Argument[0];ReturnValue;taint | | System.Runtime.CompilerServices;ConditionalWeakTable<,>;false;GetEnumerator;();;Element of Argument[-1];Property[System.Collections.Generic.IEnumerator<>.Current] of ReturnValue;value | +| System.Runtime.CompilerServices;ConfiguredTaskAwaitable<>+ConfiguredTaskAwaiter;false;GetResult;();;Property[System.Threading.Tasks.Task<>.Result] of SyntheticField[m_task_configured_task_awaitable] of Argument[-1];ReturnValue;value | +| System.Runtime.CompilerServices;ConfiguredTaskAwaitable<>;false;GetAwaiter;();;SyntheticField[m_configuredTaskAwaiter] of Argument[-1];ReturnValue;value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;Add;(T);;Argument[0];Element of Argument[-1];value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;CopyTo;(T[],System.Int32);;Element of Argument[-1];Element of Argument[0];value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;GetEnumerator;();;Element of Argument[-1];Property[System.Collections.Generic.IEnumerator<>.Current] of ReturnValue;value | @@ -1575,6 +1577,7 @@ | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;get_Item;(System.Int32);;Element of Argument[-1];ReturnValue;value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;set_Item;(System.Int32,System.Object);;Argument[1];Element of Argument[-1];value | | System.Runtime.CompilerServices;ReadOnlyCollectionBuilder<>;false;set_Item;(System.Int32,T);;Argument[1];Element of Argument[-1];value | +| System.Runtime.CompilerServices;TaskAwaiter<>;false;GetResult;();;Property[System.Threading.Tasks.Task<>.Result] of SyntheticField[m_task_task_awaiter] of Argument[-1];ReturnValue;value | | System.Security.Cryptography.X509Certificates;X509Certificate2Collection;false;Add;(System.Security.Cryptography.X509Certificates.X509Certificate2);;Argument[0];Element of Argument[-1];value | | System.Security.Cryptography.X509Certificates;X509Certificate2Collection;false;AddRange;(System.Security.Cryptography.X509Certificates.X509Certificate2Collection);;Element of Argument[0];Element of Argument[-1];value | | System.Security.Cryptography.X509Certificates;X509Certificate2Collection;false;AddRange;(System.Security.Cryptography.X509Certificates.X509Certificate2[]);;Element of Argument[0];Element of Argument[-1];value | @@ -1760,6 +1763,7 @@ | System.Threading.Tasks;Task;false;WhenAny<>;(System.Threading.Tasks.Task,System.Threading.Tasks.Task);;Property[System.Threading.Tasks.Task<>.Result] of Element of Argument[0];Element of Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task;false;WhenAny<>;(System.Threading.Tasks.Task,System.Threading.Tasks.Task);;Property[System.Threading.Tasks.Task<>.Result] of Element of Argument[1];Element of Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task;false;WhenAny<>;(System.Threading.Tasks.Task[]);;Property[System.Threading.Tasks.Task<>.Result] of Element of Argument[0];Element of Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | +| System.Threading.Tasks;Task<>;false;ConfigureAwait;(System.Boolean);;Argument[-1];SyntheticField[m_task_configured_task_awaitable] of SyntheticField[m_configuredTaskAwaiter] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;ContinueWith;(System.Action,System.Object>,System.Object);;Argument[1];Parameter[1] of Argument[0];value | | System.Threading.Tasks;Task<>;false;ContinueWith;(System.Action,System.Object>,System.Object);;Argument[-1];Parameter[0] of Argument[0];value | | System.Threading.Tasks;Task<>;false;ContinueWith;(System.Action,System.Object>,System.Object,System.Threading.CancellationToken);;Argument[1];Parameter[1] of Argument[0];value | @@ -1800,6 +1804,7 @@ | System.Threading.Tasks;Task<>;false;ContinueWith<>;(System.Func,TNewResult>,System.Threading.Tasks.TaskContinuationOptions);;ReturnValue of Argument[0];Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;ContinueWith<>;(System.Func,TNewResult>,System.Threading.Tasks.TaskScheduler);;Argument[-1];Parameter[0] of Argument[0];value | | System.Threading.Tasks;Task<>;false;ContinueWith<>;(System.Func,TNewResult>,System.Threading.Tasks.TaskScheduler);;ReturnValue of Argument[0];Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | +| System.Threading.Tasks;Task<>;false;GetAwaiter;();;Argument[-1];SyntheticField[m_task_task_awaiter] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;Task;(System.Func,System.Object);;Argument[1];Parameter[0] of Argument[0];value | | System.Threading.Tasks;Task<>;false;Task;(System.Func,System.Object);;ReturnValue of Argument[0];Property[System.Threading.Tasks.Task<>.Result] of ReturnValue;value | | System.Threading.Tasks;Task<>;false;Task;(System.Func,System.Object,System.Threading.CancellationToken);;Argument[1];Parameter[0] of Argument[0];value | From 13347cd102751a840d294a7c2f6d434559bc1a6f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 9 Dec 2021 10:34:31 +0100 Subject: [PATCH 6/6] C#: Add Ql docs to synthetic fields. --- .../semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll | 2 ++ .../lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll | 2 ++ 2 files changed, 4 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 4521fe64247..db3bc61063f 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -2040,9 +2040,11 @@ predicate allowParameterReturnInSelf(ParameterNode p) { FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p) } +/** A synthetic field. */ abstract class SyntheticField extends string { bindingset[this] SyntheticField() { any() } + /** Gets the type of this synthetic field. */ Type getType() { result instanceof ObjectType } } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index c554c86be40..3b7e0dc0596 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -224,11 +224,13 @@ class FieldContent extends Content, TFieldContent { deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(f.getType()) } } +/** A reference to a synthetic field. */ class SyntheticFieldContent extends Content, TSyntheticFieldContent { private SyntheticField f; SyntheticFieldContent() { this = TSyntheticFieldContent(f) } + /** Gets the underlying synthetic field. */ SyntheticField getField() { result = f } override string toString() { result = "synthetic " + f.toString() }