From df12f255ac90599d0ee7c164f5a2aec5685d42fc Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 12 Nov 2024 13:49:11 +0100 Subject: [PATCH 1/9] JS: Rename propagatesFlowExt -> propagatesFlow --- .../javascript/dataflow/FlowSummary.qll | 5 +- .../flow_summaries/AmbiguousCoreMethods.qll | 14 +++--- .../internal/flow_summaries/Arrays.qll | 50 +++++++++---------- .../internal/flow_summaries/ExceptionFlow.qll | 2 +- .../internal/flow_summaries/Iterators.qll | 2 +- .../internal/flow_summaries/JsonStringify.qll | 2 +- .../internal/flow_summaries/Maps.qll | 6 +-- .../internal/flow_summaries/Promises.qll | 30 +++++------ .../internal/flow_summaries/Sets.qll | 4 +- .../internal/flow_summaries/Strings.qll | 8 +-- 10 files changed, 61 insertions(+), 62 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/FlowSummary.qll b/javascript/ql/lib/semmle/javascript/dataflow/FlowSummary.qll index 9f619a3058e..1520ff22f88 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/FlowSummary.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/FlowSummary.qll @@ -11,19 +11,18 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari bindingset[this] SummarizedCallable() { any() } - // TODO: rename 'propagatesFlowExt' and/or override 'propagatesFlow' directly /** * Holds if data may flow from `input` to `output` through this callable. * * `preservesValue` indicates whether this is a value-preserving step or a taint-step. */ pragma[nomagic] - predicate propagatesFlowExt(string input, string output, boolean preservesValue) { none() } + predicate propagatesFlow(string input, string output, boolean preservesValue) { none() } override predicate propagatesFlow( string input, string output, boolean preservesValue, string model ) { - this.propagatesFlowExt(input, output, preservesValue) and model = this + this.propagatesFlow(input, output, preservesValue) and model = this } /** diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/AmbiguousCoreMethods.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/AmbiguousCoreMethods.qll index 9c74cc7e33f..95981a6fb95 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/AmbiguousCoreMethods.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/AmbiguousCoreMethods.qll @@ -31,7 +31,7 @@ class At extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "at" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].ArrayElement" and output = "ReturnValue" @@ -45,7 +45,7 @@ class Concat extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "concat" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this,0..].ArrayElement" and output = "ReturnValue.ArrayElement" @@ -61,7 +61,7 @@ class Slice extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "slice" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].ArrayElement" and output = "ReturnValue.ArrayElement" @@ -80,7 +80,7 @@ class Entries extends SummarizedCallable { result.getNumArgument() = 0 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this]." + ["MapKey", "SetElement"] and @@ -97,7 +97,7 @@ class ForEach extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "forEach" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and /* * array.forEach(callbackfn, thisArg) @@ -128,7 +128,7 @@ class Keys extends SummarizedCallable { result.getNumArgument() = 0 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this]." + ["MapKey", "SetElement"] and output = "ReturnValue.IteratorElement" @@ -143,7 +143,7 @@ class Values extends SummarizedCallable { result.getNumArgument() = 0 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this]." + ["ArrayElement", "SetElement", "MapValue"] and output = "ReturnValue.IteratorElement" diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll index 9381ca98dd7..702936b46c3 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Arrays.qll @@ -99,7 +99,7 @@ class ArrayConstructorSummary extends SummarizedCallable { result = arrayConstructorRef().getAnInvocation() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0..]" and output = "ReturnValue.ArrayElement" @@ -123,7 +123,7 @@ class Join extends SummarizedCallable { result.getNumArgument() = [0, 1] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = false and input = "Argument[this].ArrayElement" and output = "ReturnValue" @@ -135,7 +135,7 @@ class CopyWithin extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "copyWithin" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].WithArrayElement" and output = "ReturnValue" @@ -154,7 +154,7 @@ class FlowIntoCallback extends SummarizedCallable { result.getMethodName() = ["every", "findIndex", "findLastIndex", "some"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -171,7 +171,7 @@ class Filter extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "filter" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -198,7 +198,7 @@ class Fill extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "fill" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0..]" and output = ["ReturnValue.ArrayElement", "Argument[this].ArrayElement"] @@ -210,7 +210,7 @@ class FindLike extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = ["find", "findLast"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -229,7 +229,7 @@ class FindLibrary extends SummarizedCallable { result = DataFlow::moduleImport(["array.prototype.find", "array-find"]).getACall() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].ArrayElement" and @@ -257,7 +257,7 @@ class Flat extends SummarizedCallable { ) } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this]" + concat(int n | n in [0 .. depth] | ".ArrayElement") @@ -277,7 +277,7 @@ class FlatMap extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "flatMap" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -309,7 +309,7 @@ class From1Arg extends SummarizedCallable { result = arrayFromCall() and result.getNumArgument() = 1 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].WithArrayElement" and @@ -346,7 +346,7 @@ class FromManyArg extends SummarizedCallable { result.getNumArgument() > 1 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0]." + ["ArrayElement", "SetElement", "IteratorElement"] and @@ -380,7 +380,7 @@ class Map extends SummarizedCallable { result.getMethodName() = "map" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -405,7 +405,7 @@ class Of extends SummarizedCallable { result = arrayConstructorRef().getAMemberCall("of") } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0..]" and output = "ReturnValue.ArrayElement" @@ -417,7 +417,7 @@ class Pop extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "pop" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].ArrayElement" and output = "ReturnValue" @@ -429,7 +429,7 @@ class PushLike extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = ["push", "unshift"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0..]" and output = "Argument[this].ArrayElement" @@ -441,7 +441,7 @@ class ReduceLike extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = ["reduce", "reduceRight"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and /* * Signatures: @@ -470,7 +470,7 @@ class Reverse extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = ["reverse", "toReversed"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].ArrayElement" and output = "ReturnValue.ArrayElement" @@ -482,7 +482,7 @@ class Shift extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "shift" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].ArrayElement[0]" and output = "ReturnValue" @@ -500,7 +500,7 @@ class Sort extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = ["sort", "toSorted"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -517,7 +517,7 @@ class Splice extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "splice" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -534,7 +534,7 @@ class ToSpliced extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "toSpliced" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].ArrayElement" and @@ -551,7 +551,7 @@ class ArrayCoercionPackage extends FunctionalPackageSummary { override string getAPackageName() { result = ["arrify", "array-ify"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].WithArrayElement" and @@ -573,7 +573,7 @@ class ArrayCopyingPackage extends FunctionalPackageSummary { override string getAPackageName() { result = ["array-union", "array-uniq", "uniq"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0..].ArrayElement" and output = "ReturnValue.ArrayElement" @@ -587,7 +587,7 @@ class ArrayFlatteningPackage extends FunctionalPackageSummary { result = ["array-flatten", "arr-flatten", "flatten", "array.prototype.flat"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { // TODO: properly support these. For the moment we're just adding parity with the old model preservesValue = false and input = "Argument[0..]" and diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ExceptionFlow.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ExceptionFlow.qll index c81dadadfb6..252baab207b 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ExceptionFlow.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ExceptionFlow.qll @@ -40,7 +40,7 @@ private class ExceptionFlowSummary extends SummarizedCallable, LibraryCallableIn isCallback(result.getAnArgument().getALocalSource()) } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0..].ReturnValue[exception]" and output = "ReturnValue[exception]" diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Iterators.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Iterators.qll index 94afac52787..e9937363c01 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Iterators.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Iterators.qll @@ -16,7 +16,7 @@ class IteratorNext extends SummarizedCallable { result.getNumArgument() = 0 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[this].IteratorElement" and diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/JsonStringify.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/JsonStringify.qll index 86779b8e7ec..ecd2dcdfc79 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/JsonStringify.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/JsonStringify.qll @@ -12,7 +12,7 @@ private class JsonStringifySummary extends SummarizedCallable { override DataFlow::InvokeNode getACall() { result instanceof JsonStringifyCall } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = false and input = ["Argument[0]", "Argument[0].AnyMemberDeep"] and output = "ReturnValue" diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Maps.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Maps.qll index c80bee19aaa..3adc145d1a1 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Maps.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Maps.qll @@ -15,7 +15,7 @@ class MapConstructor extends SummarizedCallable { result = mapConstructorRef().getAnInstantiation() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0]." + ["ArrayElement", "SetElement", "IteratorElement"] + ".Member[0]" and @@ -87,7 +87,7 @@ class MapGet extends SummarizedCallable { result.getNumArgument() = 1 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[this].MapValue" and output = "ReturnValue" @@ -102,7 +102,7 @@ class MapSet extends SummarizedCallable { result.getNumArgument() = 2 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = ["Argument[this].WithMapKey", "Argument[this].WithMapValue"] and output = "ReturnValue" diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Promises.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Promises.qll index aa9398f14bb..33299a3f5c0 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Promises.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Promises.qll @@ -29,7 +29,7 @@ private class PromiseConstructor extends SummarizedCallable { none() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( // TODO: when FlowSummaryImpl.qll supports these summaries, remove the workaround in PromiseConstructorWorkaround @@ -58,7 +58,7 @@ module PromiseConstructorWorkaround { promiseConstructorRef().getAnInstantiation().getCallback(0).getParameter(0).getACall() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0]" and output = "Argument[function].Member[resolve-value]" @@ -73,7 +73,7 @@ module PromiseConstructorWorkaround { promiseConstructorRef().getAnInstantiation().getCallback(0).getParameter(1).getACall() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0]" and output = "Argument[function].Member[reject-value]" @@ -87,7 +87,7 @@ module PromiseConstructorWorkaround { result = promiseConstructorRef().getAnInstantiation() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].Parameter[0].Member[resolve-value]" and @@ -111,7 +111,7 @@ private class PromiseThen2Arguments extends SummarizedCallable { result.getNumArgument() = 2 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0,1].ReturnValue" and output = "ReturnValue.Awaited" @@ -133,7 +133,7 @@ private class PromiseThen1Argument extends SummarizedCallable { result.getNumArgument() = 1 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].ReturnValue" and output = "ReturnValue.Awaited" @@ -152,7 +152,7 @@ private class PromiseCatch extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "catch" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].ReturnValue" and output = "ReturnValue.Awaited" @@ -171,7 +171,7 @@ private class PromiseFinally extends SummarizedCallable { override InstanceCall getACallSimple() { result.getMethodName() = "finally" } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].ReturnValue.Awaited[error]" and output = "ReturnValue.Awaited[error]" @@ -190,7 +190,7 @@ private class PromiseResolve extends SummarizedCallable { result = promiseConstructorRef().getAMemberCall("resolve") } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0]" and output = "ReturnValue.Awaited" @@ -204,7 +204,7 @@ private class PromiseReject extends SummarizedCallable { result = promiseConstructorRef().getAMemberCall("reject") } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0]" and output = "ReturnValue.Awaited[error]" @@ -218,7 +218,7 @@ private class PromiseAll extends SummarizedCallable { result = promiseConstructorRef().getAMemberCall("all") } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and exists(string content | content = getAnArrayContent() | input = "Argument[0]." + content + ".Awaited" and @@ -242,7 +242,7 @@ private class PromiseAnyLike extends SummarizedCallable { result = promiseConstructorRef().getAMemberCall(["any", "race", "firstFulfilled"]) } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0].ArrayElement" and output = "ReturnValue.Awaited" @@ -258,7 +258,7 @@ private class PromiseAllSettled extends SummarizedCallable { result = DataFlow::moduleImport("promise.allsettled").getACall() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and exists(string content | content = getAnArrayContent() | input = "Argument[0]." + content + ".Awaited" and @@ -277,7 +277,7 @@ private class BluebirdMapSeries extends SummarizedCallable { result = promiseConstructorRef().getAMemberCall("mapSeries") } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0].Awaited.ArrayElement.Awaited" and @@ -310,7 +310,7 @@ private class PromiseWithResolversLike extends SummarizedCallable { result = promiseConstructorRef().getAMemberCall(["withResolver", "withResolvers", "defer"]) } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( // TODO: not currently supported by FlowSummaryImpl.qll diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Sets.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Sets.qll index 1880eb569bf..34f7d222df8 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Sets.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Sets.qll @@ -15,7 +15,7 @@ class SetConstructor extends SummarizedCallable { result = setConstructorRef().getAnInstantiation() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( input = "Argument[0]." + ["ArrayElement", "SetElement", "IteratorElement"] and @@ -38,7 +38,7 @@ class SetAdd extends SummarizedCallable { result.getNumArgument() = 1 } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and input = "Argument[0]" and output = "Argument[this].SetElement" diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll index 9267ab598fb..154668cde08 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/Strings.qll @@ -15,7 +15,7 @@ private class StringReplaceNoWildcard extends SummarizedCallable { override StringReplaceCall getACall() { not result.hasRegExpContainingWildcard() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = false and ( input = "Argument[this]" and @@ -39,7 +39,7 @@ private class StringReplaceWithWildcard extends SummarizedCallable { override StringReplaceCall getACall() { result.hasRegExpContainingWildcard() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = false and ( input = "Argument[this]" and @@ -60,7 +60,7 @@ class StringSplit extends SummarizedCallable { not result.getArgument(0).getStringValue() = ["#", "?"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = false and input = "Argument[this]" and output = "ReturnValue.ArrayElement" @@ -85,7 +85,7 @@ class StringSplitHashOrQuestionMark extends SummarizedCallable { result.getArgument(0).getStringValue() = ["#", "?"] } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = false and ( input = "Argument[this].OptionalBarrier[split-url-suffix]" and From e34064e3b541b43c7259b541c124772826bb4ffb Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Nov 2024 14:43:18 +0100 Subject: [PATCH 2/9] JS: Initial instantiation of sumamry type tracking Instantiates the library without using it yet. --- javascript/ql/lib/qlpack.yml | 1 + .../internal/sharedlib/SummaryTypeTracker.qll | 73 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index a7baed0056b..78f26bc9870 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -12,6 +12,7 @@ dependencies: codeql/ssa: ${workspace} codeql/threat-models: ${workspace} codeql/tutorial: ${workspace} + codeql/typetracking: ${workspace} codeql/util: ${workspace} codeql/xml: ${workspace} codeql/yaml: ${workspace} diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll new file mode 100644 index 00000000000..09d992dcea7 --- /dev/null +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll @@ -0,0 +1,73 @@ +private import semmle.javascript.Locations +private import codeql.typetracking.internal.SummaryTypeTracker +private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate +private import semmle.javascript.dataflow.FlowSummary as FlowSummary +private import FlowSummaryImpl as FlowSummaryImpl +private import DataFlowArg + +private module SummaryFlowConfig implements Input { + import JSDataFlow + import FlowSummaryImpl::Public + import FlowSummaryImpl::Private + import FlowSummaryImpl::Private::SummaryComponent + + class Content = DataFlow::ContentSet; + + class ContentFilter extends Unit { + ContentFilter() { none() } + } + + ContentFilter getFilterFromWithoutContentStep(Content content) { none() } + + ContentFilter getFilterFromWithContentStep(Content content) { none() } + + predicate singleton = SummaryComponentStack::singleton/1; + + predicate push = SummaryComponentStack::push/2; + + SummaryComponent return() { + result = SummaryComponent::return(DataFlowPrivate::MkNormalReturnKind()) + } + + Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate) { + exists(ArgumentPosition apos, ParameterPosition ppos, Node argNode | + arg = argument(ppos) and + parameterMatch(ppos, apos) and + isArgumentNode(argNode, any(DataFlowCall c | c.asOrdinaryCall() = call), apos) + | + isPostUpdate = true and result = argNode.getPostUpdateNode() + or + isPostUpdate = false and result = argNode + ) + } + + Node parameterOf(Node callable, SummaryComponent param) { + exists(ArgumentPosition apos, ParameterPosition ppos, Function function | + param = parameter(apos) and + parameterMatch(ppos, apos) and + callable = function.flow() and + isParameterNode(result, any(DataFlowCallable c | c.asSourceCallable() = function), ppos) + ) + } + + Node returnOf(Node callable, SummaryComponent return) { + return = return() and + result = callable.(DataFlow::FunctionNode).getReturnNode() + } + + class SummarizedCallable instanceof SummarizedCallableImpl { + predicate propagatesFlow( + SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue + ) { + super.propagatesFlow(input, output, preservesValue, _) + } + + string toString() { result = super.toString() } + } + + Node callTo(SummarizedCallable callable) { + result = callable.(FlowSummary::SummarizedCallable).getACallSimple() + } +} + +import SummaryFlow From 6349903110238106549b8911bb6ee334474adcef Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Nov 2024 14:57:59 +0100 Subject: [PATCH 3/9] JS: Move FlowSummary/Summaries.qll into testUtilities --- javascript/ql/test/library-tests/FlowSummary/test.ql | 2 +- .../Summaries.qll => testUtilities/InlineSummaries.qll} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename javascript/ql/test/{library-tests/FlowSummary/Summaries.qll => testUtilities/InlineSummaries.qll} (86%) diff --git a/javascript/ql/test/library-tests/FlowSummary/test.ql b/javascript/ql/test/library-tests/FlowSummary/test.ql index 3b300bbe19b..7d0d0db7ee2 100644 --- a/javascript/ql/test/library-tests/FlowSummary/test.ql +++ b/javascript/ql/test/library-tests/FlowSummary/test.ql @@ -1,6 +1,6 @@ import javascript import testUtilities.ConsistencyChecking -import Summaries +import testUtilities.InlineSummaries DataFlow::CallNode getACall(string name) { result.getCalleeName() = name diff --git a/javascript/ql/test/library-tests/FlowSummary/Summaries.qll b/javascript/ql/test/testUtilities/InlineSummaries.qll similarity index 86% rename from javascript/ql/test/library-tests/FlowSummary/Summaries.qll rename to javascript/ql/test/testUtilities/InlineSummaries.qll index e6037cb814b..559f1360977 100644 --- a/javascript/ql/test/library-tests/FlowSummary/Summaries.qll +++ b/javascript/ql/test/testUtilities/InlineSummaries.qll @@ -11,11 +11,11 @@ class MkSummary extends SummarizedCallable { mkSummary.getLocation().getStartLine() } - override DataFlow::InvokeNode getACall() { + override DataFlow::InvokeNode getACallSimple() { result = mkSummary.flow().(DataFlow::CallNode).getAnInvocation() } - override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + override predicate propagatesFlow(string input, string output, boolean preservesValue) { preservesValue = true and ( // mkSummary(input, output) From 440cbb7f0aed6b373917c2efad61bb86a7c83abb Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Nov 2024 15:16:53 +0100 Subject: [PATCH 4/9] JS: Add inline-expectation test for type tracking --- .../library-tests/TypeTracking2/summaries.js | 45 +++++++++++++++++++ .../library-tests/TypeTracking2/test.expected | 2 + .../test/library-tests/TypeTracking2/test.ql | 39 ++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeTracking2/summaries.js create mode 100644 javascript/ql/test/library-tests/TypeTracking2/test.expected create mode 100644 javascript/ql/test/library-tests/TypeTracking2/test.ql diff --git a/javascript/ql/test/library-tests/TypeTracking2/summaries.js b/javascript/ql/test/library-tests/TypeTracking2/summaries.js new file mode 100644 index 00000000000..0223801fbaf --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking2/summaries.js @@ -0,0 +1,45 @@ +function m0() { + const x = source("m0.1"); + sink(x); // $ track=m0.1 +} + +function m1() { + const fn = mkSummary("Argument[0]", "ReturnValue"); + const obj = source("m1.1"); + sink(fn(obj)); // $ MISSING: track=m1.1 + sink(fn(obj.p)); + sink(fn(obj).p); + sink(fn({ p: obj })); + sink(fn({ p: obj }).q); +} + +function m2() { + const fn = mkSummary("Argument[0].Member[p]", "ReturnValue"); + const obj = source("m2.1"); + sink(fn(obj)); + sink(fn(obj.p)); + sink(fn(obj).p); + sink(fn({ p: obj })); // $ MISSING: track=m2.1 + sink(fn({ p: obj }).q); +} + +function m3() { + const fn = mkSummary("Argument[0]", "ReturnValue.Member[p]"); + const obj = source("m3.1"); + sink(fn(obj)); + sink(fn(obj.p)); + sink(fn(obj).p); // $ MISSING: track=m3.1 + sink(fn({ p: obj })); + sink(fn({ p: obj }).q); +} + + +function m4() { + const fn = mkSummary("Argument[0].Member[p]", "ReturnValue.Member[q]"); + const obj = source("m4.1"); + sink(fn(obj)); + sink(fn(obj.p)); + sink(fn(obj).p); + sink(fn({ p: obj })); + sink(fn({ p: obj }).q); // $ MISSING: track=m4.1 +} diff --git a/javascript/ql/test/library-tests/TypeTracking2/test.expected b/javascript/ql/test/library-tests/TypeTracking2/test.expected new file mode 100644 index 00000000000..8ec8033d086 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking2/test.expected @@ -0,0 +1,2 @@ +testFailures +failures diff --git a/javascript/ql/test/library-tests/TypeTracking2/test.ql b/javascript/ql/test/library-tests/TypeTracking2/test.ql new file mode 100644 index 00000000000..dcc3ff1b57b --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking2/test.ql @@ -0,0 +1,39 @@ +import javascript +import testUtilities.InlineSummaries +import testUtilities.InlineExpectationsTest + +private DataFlow::SourceNode typeTrack(DataFlow::TypeTracker t, string name) { + t.start() and + exists(DataFlow::CallNode call | + call.getCalleeName() = "source" and + name = call.getArgument(0).getStringValue() and + result = call + ) + or + exists(DataFlow::TypeTracker t2 | result = typeTrack(t2, name).track(t2, t)) +} + +DataFlow::SourceNode typeTrack(string name) { + result = typeTrack(DataFlow::TypeTracker::end(), name) +} + +module TestConfig implements TestSig { + string getARelevantTag() { result = "track" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + element = "" and + tag = "track" and + exists(DataFlow::CallNode call, DataFlow::Node arg | + call.getCalleeName() = "sink" and + arg = call.getArgument(0) and + typeTrack(value).flowsTo(arg) and + location = arg.getLocation() + ) + } + + predicate hasOptionalResult(Location location, string element, string tag, string value) { + none() + } +} + +import MakeTest From 2f0c80a98bb658ecb98b07e9f6a935dcc75f8ea0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Nov 2024 22:18:01 +0100 Subject: [PATCH 5/9] JS: Include summary steps in type tracking --- .../dataflow/internal/StepSummary.qll | 22 +++++++++++++++++++ .../library-tests/TypeTracking2/summaries.js | 8 +++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll index 435d4d82ed5..792fbbcc927 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll @@ -1,6 +1,7 @@ import javascript private import semmle.javascript.dataflow.TypeTracking private import semmle.javascript.internal.CachedStages +private import sharedlib.SummaryTypeTracker as SummaryTypeTracker private import FlowSteps cached @@ -46,6 +47,12 @@ private module Cached { LoadStoreStep(PropertyName fromProp, PropertyName toProp) { SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp) or + exists(DataFlow::ContentSet loadContent, DataFlow::ContentSet storeContent | + SummaryTypeTracker::basicLoadStoreStep(_, _, loadContent, storeContent) and + fromProp = loadContent.asPropertyName() and + toProp = storeContent.asPropertyName() + ) + or summarizedLoadStoreStep(_, _, fromProp, toProp) } or WithoutPropStep(PropertySet props) { SharedTypeTrackingStep::withoutPropStep(_, _, props) } @@ -205,6 +212,21 @@ private module Cached { succ = getACallbackSource(parameter).getParameter(i) and summary = ReturnStep() ) + or + SummaryTypeTracker::levelStepNoCall(pred, succ) and summary = LevelStep() + or + exists(DataFlow::ContentSet content | + SummaryTypeTracker::basicLoadStep(pred, succ, content) and + summary = LoadStep(content.asPropertyName()) + or + SummaryTypeTracker::basicStoreStep(pred, succ, content) and + summary = StoreStep(content.asPropertyName()) + ) + or + exists(DataFlow::ContentSet loadContent, DataFlow::ContentSet storeContent | + SummaryTypeTracker::basicLoadStoreStep(pred, succ, loadContent, storeContent) and + summary = LoadStoreStep(loadContent.asPropertyName(), storeContent.asPropertyName()) + ) } } diff --git a/javascript/ql/test/library-tests/TypeTracking2/summaries.js b/javascript/ql/test/library-tests/TypeTracking2/summaries.js index 0223801fbaf..416495a167e 100644 --- a/javascript/ql/test/library-tests/TypeTracking2/summaries.js +++ b/javascript/ql/test/library-tests/TypeTracking2/summaries.js @@ -6,7 +6,7 @@ function m0() { function m1() { const fn = mkSummary("Argument[0]", "ReturnValue"); const obj = source("m1.1"); - sink(fn(obj)); // $ MISSING: track=m1.1 + sink(fn(obj)); // $ track=m1.1 sink(fn(obj.p)); sink(fn(obj).p); sink(fn({ p: obj })); @@ -19,7 +19,7 @@ function m2() { sink(fn(obj)); sink(fn(obj.p)); sink(fn(obj).p); - sink(fn({ p: obj })); // $ MISSING: track=m2.1 + sink(fn({ p: obj })); // $ track=m2.1 sink(fn({ p: obj }).q); } @@ -28,7 +28,7 @@ function m3() { const obj = source("m3.1"); sink(fn(obj)); sink(fn(obj.p)); - sink(fn(obj).p); // $ MISSING: track=m3.1 + sink(fn(obj).p); // $ track=m3.1 sink(fn({ p: obj })); sink(fn({ p: obj }).q); } @@ -41,5 +41,5 @@ function m4() { sink(fn(obj.p)); sink(fn(obj).p); sink(fn({ p: obj })); - sink(fn({ p: obj }).q); // $ MISSING: track=m4.1 + sink(fn({ p: obj }).q); // $ track=m4.1 } From 9c6b6981e2722673d516a55297ac5c248a85bd5f Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 29 Nov 2024 10:45:10 +0100 Subject: [PATCH 6/9] JS: Add test to restrict dependencies --- .../DependencyRestriction.expected | 1 + .../TypeTracking2/DependencyRestriction.ql | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.expected create mode 100644 javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.ql diff --git a/javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.expected b/javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.expected new file mode 100644 index 00000000000..e1481d55a80 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.expected @@ -0,0 +1 @@ +| pass | diff --git a/javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.ql b/javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.ql new file mode 100644 index 00000000000..51ed46ac655 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeTracking2/DependencyRestriction.ql @@ -0,0 +1,19 @@ +/** + * Test that fails with a compilation error if `getACallSimple` depends on the call graph. + * To do this, we add a negative dependency from the call graph to `getACallSimple`. + */ + +import javascript +import semmle.javascript.dataflow.internal.StepSummary +import semmle.javascript.dataflow.FlowSummary + +class NegativeDependency extends DataFlow::SharedTypeTrackingStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { + exists(SummarizedCallable callable | + not exists(callable.getACallSimple()) and + node1 = node2 + ) + } +} + +select "pass" From cab8a40d004ae5750e8dea397638b5b03c7a5d23 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 29 Nov 2024 11:01:19 +0100 Subject: [PATCH 7/9] JS: Fix accidental recursion --- .../internal/sharedlib/SummaryTypeTracker.qll | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll index 09d992dcea7..c9acd77db1a 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/SummaryTypeTracker.qll @@ -30,10 +30,16 @@ private module SummaryFlowConfig implements Input { } Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate) { + // Note: we cannot rely on DataFlowPrivate::DataFlowCall here because that depends on the call graph. exists(ArgumentPosition apos, ParameterPosition ppos, Node argNode | arg = argument(ppos) and parameterMatch(ppos, apos) and - isArgumentNode(argNode, any(DataFlowCall c | c.asOrdinaryCall() = call), apos) + ( + argNode = call.(DataFlow::InvokeNode).getArgument(apos.asPositional()) + or + apos.isThis() and + argNode = call.(DataFlow::CallNode).getReceiver() + ) | isPostUpdate = true and result = argNode.getPostUpdateNode() or @@ -42,11 +48,15 @@ private module SummaryFlowConfig implements Input { } Node parameterOf(Node callable, SummaryComponent param) { - exists(ArgumentPosition apos, ParameterPosition ppos, Function function | + exists(ArgumentPosition apos, ParameterPosition ppos, DataFlow::FunctionNode function | param = parameter(apos) and parameterMatch(ppos, apos) and - callable = function.flow() and - isParameterNode(result, any(DataFlowCallable c | c.asSourceCallable() = function), ppos) + callable = function + | + result = function.getParameter(ppos.asPositional()) + or + ppos.isThis() and + result = function.getReceiver() ) } From 8bca66493f0c0bd95450ca788f8d65315c2c52d3 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 3 Dec 2024 09:57:02 +0100 Subject: [PATCH 8/9] JS: Add test showing lack of inclusion in PropertyName --- .../ql/test/library-tests/TypeTracking2/summaries.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeTracking2/summaries.js b/javascript/ql/test/library-tests/TypeTracking2/summaries.js index 416495a167e..7c0f31e3607 100644 --- a/javascript/ql/test/library-tests/TypeTracking2/summaries.js +++ b/javascript/ql/test/library-tests/TypeTracking2/summaries.js @@ -43,3 +43,13 @@ function m4() { sink(fn({ p: obj })); sink(fn({ p: obj }).q); // $ track=m4.1 } + +function m5() { + // Store and read to a property that isn't mentioned anywhere in the source code. + const store = mkSummary("Argument[0]", "ReturnValue.Member[propOnlyMentionedInSummary]"); + const read = mkSummary("Argument[0].Member[propOnlyMentionedInSummary]", "ReturnValue"); + sink(read(store(source("m5.1")))); // $ MISSING: track=m5.1 + sink(read(source("m5.1"))); + sink(store(source("m5.1"))); + sink(store(read(source("m5.1")))); +} From 054558d7b564515bc479ea7a5596681308bf725a Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 3 Dec 2024 09:58:54 +0100 Subject: [PATCH 9/9] JS: Include content properties in type-tracker properties Reminder: we have two PropertyName classes because the one in Contents.qll can't depend on DataFlow::Node. --- .../ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll | 3 +++ javascript/ql/test/library-tests/TypeTracking2/summaries.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll index 792fbbcc927..2bcd89130a9 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/StepSummary.qll @@ -1,6 +1,7 @@ import javascript private import semmle.javascript.dataflow.TypeTracking private import semmle.javascript.internal.CachedStages +private import semmle.javascript.dataflow.internal.Contents as Contents private import sharedlib.SummaryTypeTracker as SummaryTypeTracker private import FlowSteps @@ -30,6 +31,8 @@ private module Cached { SharedTypeTrackingStep::loadStoreStep(_, _, _, this) or this = DataFlow::PseudoProperties::arrayLikeElement() + or + this instanceof Contents::Private::PropertyName } } diff --git a/javascript/ql/test/library-tests/TypeTracking2/summaries.js b/javascript/ql/test/library-tests/TypeTracking2/summaries.js index 7c0f31e3607..1550ded19f4 100644 --- a/javascript/ql/test/library-tests/TypeTracking2/summaries.js +++ b/javascript/ql/test/library-tests/TypeTracking2/summaries.js @@ -48,7 +48,7 @@ function m5() { // Store and read to a property that isn't mentioned anywhere in the source code. const store = mkSummary("Argument[0]", "ReturnValue.Member[propOnlyMentionedInSummary]"); const read = mkSummary("Argument[0].Member[propOnlyMentionedInSummary]", "ReturnValue"); - sink(read(store(source("m5.1")))); // $ MISSING: track=m5.1 + sink(read(store(source("m5.1")))); // $ track=m5.1 sink(read(source("m5.1"))); sink(store(source("m5.1"))); sink(store(read(source("m5.1"))));