@@ -411,7 +411,7 @@ module API {
411
411
any ( Type t ) .hasUnderlyingType ( moduleName , exportName )
412
412
} or
413
413
MkSyntheticCallbackArg ( DataFlow:: Node src , int bound , DataFlow:: InvokeNode nd ) {
414
- trackUseNode ( src , true , bound ) .flowsTo ( nd .getCalleeNode ( ) )
414
+ trackUseNode ( src , true , bound , "" ) .flowsTo ( nd .getCalleeNode ( ) )
415
415
}
416
416
417
417
class TDef = MkModuleDef or TNonModuleDef ;
@@ -528,7 +528,7 @@ module API {
528
528
*/
529
529
private predicate argumentPassing ( TApiNode base , int i , DataFlow:: Node arg ) {
530
530
exists ( DataFlow:: Node use , DataFlow:: SourceNode pred , int bound |
531
- use ( base , use ) and pred = trackUseNode ( use , _, bound )
531
+ use ( base , use ) and pred = trackUseNode ( use , _, bound , "" )
532
532
|
533
533
arg = pred .getAnInvocation ( ) .getArgument ( i - bound )
534
534
or
@@ -567,26 +567,37 @@ module API {
567
567
base = MkRoot ( ) and
568
568
ref = lbl .( EntryPoint ) .getAUse ( )
569
569
or
570
- exists ( DataFlow:: SourceNode src , DataFlow:: SourceNode pred |
571
- use ( base , src ) and pred = trackUseNode ( src )
570
+ exists ( DataFlow:: SourceNode src , DataFlow:: SourceNode pred , string prop |
571
+ use ( base , src ) and pred = trackUseNode ( src , false , 0 , prop )
572
572
|
573
573
// `module.exports` is special: it is a use of a def-node, not a use-node,
574
574
// so we want to exclude it here
575
575
( base instanceof TNonModuleDef or base instanceof TUse ) and
576
576
lbl = Label:: memberFromRef ( ref ) and
577
+ (
578
+ lbl = Label:: member ( prop )
579
+ or
580
+ prop = ""
581
+ ) and
577
582
ref = pred .getAPropertyRead ( )
578
583
or
579
584
lbl = Label:: instance ( ) and
585
+ prop = "" and
580
586
ref = pred .getAnInstantiation ( )
581
587
or
582
588
lbl = Label:: return ( ) and
589
+ prop = "" and
583
590
ref = pred .getAnInvocation ( )
584
591
or
585
- lbl = Label:: promised ( ) and
586
- PromiseFlow:: loadStep ( pred .getALocalUse ( ) , ref , Promises:: valueProp ( ) )
587
- or
588
- lbl = Label:: promisedError ( ) and
589
- PromiseFlow:: loadStep ( pred .getALocalUse ( ) , ref , Promises:: errorProp ( ) )
592
+ (
593
+ lbl = Label:: promised ( ) and
594
+ ( prop = Promises:: valueProp ( ) or prop = "" ) and
595
+ PromiseFlow:: loadStep ( pred .getALocalUse ( ) , ref , Promises:: valueProp ( ) )
596
+ or
597
+ lbl = Label:: promisedError ( ) and
598
+ ( prop = Promises:: errorProp ( ) or prop = "" ) and
599
+ PromiseFlow:: loadStep ( pred .getALocalUse ( ) , ref , Promises:: errorProp ( ) )
600
+ )
590
601
)
591
602
or
592
603
exists ( DataFlow:: Node def , DataFlow:: FunctionNode fn |
@@ -680,36 +691,58 @@ module API {
680
691
)
681
692
}
682
693
694
+ private import semmle.javascript.dataflow.TypeTracking
695
+
683
696
/**
684
697
* Gets a data-flow node to which `nd`, which is a use of an API-graph node, flows.
685
698
*
686
- * The flow from `nd` to that node may be inter-procedural. If `promisified` is `true`, the
687
- * flow goes through a promisification, and `boundArgs` indicates how many arguments have been
688
- * bound throughout the flow. (To ensure termination, we somewhat arbitrarily constrain the
689
- * number of bound arguments to be at most ten.)
699
+ * The flow from `nd` to that node may be inter-procedural, and is further described by three
700
+ * flags:
701
+ *
702
+ * - `promisified`: if true `true`, the flow goes through a promisification;
703
+ * - `boundArgs`: for function values, tracks how many arguments have been bound throughout
704
+ * the flow. To ensure termination, we somewhat arbitrarily constrain the number of bound
705
+ * arguments to be at most ten.
706
+ * - `prop`: if non-empty, the flow is only guaranteed to preserve the value of this property,
707
+ * and not necessarily the entire object.
690
708
*/
691
709
private DataFlow:: SourceNode trackUseNode (
692
- DataFlow:: SourceNode nd , boolean promisified , int boundArgs , DataFlow:: TypeTracker t
710
+ DataFlow:: SourceNode nd , boolean promisified , int boundArgs , string prop ,
711
+ DataFlow:: TypeTracker t
693
712
) {
694
713
t .start ( ) and
695
714
use ( _, nd ) and
696
715
result = nd and
697
716
promisified = false and
698
- boundArgs = 0
717
+ boundArgs = 0 and
718
+ prop = ""
699
719
or
700
720
exists ( Promisify:: PromisifyCall promisify |
701
- trackUseNode ( nd , false , boundArgs , t .continue ( ) ) .flowsTo ( promisify .getArgument ( 0 ) ) and
721
+ trackUseNode ( nd , false , boundArgs , prop , t .continue ( ) ) .flowsTo ( promisify .getArgument ( 0 ) ) and
702
722
promisified = true and
723
+ prop = "" and
703
724
result = promisify
704
725
)
705
726
or
706
727
exists ( DataFlow:: PartialInvokeNode pin , DataFlow:: Node pred , int predBoundArgs |
707
- trackUseNode ( nd , promisified , predBoundArgs , t .continue ( ) ) .flowsTo ( pred ) and
728
+ trackUseNode ( nd , promisified , predBoundArgs , prop , t .continue ( ) ) .flowsTo ( pred ) and
729
+ prop = "" and
708
730
result = pin .getBoundFunction ( pred , boundArgs - predBoundArgs ) and
709
731
boundArgs in [ 0 .. 10 ]
710
732
)
711
733
or
712
- t = useStep ( nd , promisified , boundArgs , result )
734
+ exists ( DataFlow:: Node pred , string preprop |
735
+ trackUseNode ( nd , promisified , boundArgs , preprop , t .continue ( ) ) .flowsTo ( pred ) and
736
+ promisified = false and
737
+ boundArgs = 0 and
738
+ SharedTypeTrackingStep:: loadStoreStep ( pred , result , prop )
739
+ |
740
+ prop = preprop
741
+ or
742
+ preprop = ""
743
+ )
744
+ or
745
+ t = useStep ( nd , promisified , boundArgs , prop , result )
713
746
}
714
747
715
748
private import semmle.javascript.dataflow.internal.StepSummary
@@ -723,27 +756,27 @@ module API {
723
756
*/
724
757
pragma [ noopt]
725
758
private DataFlow:: TypeTracker useStep (
726
- DataFlow:: Node nd , boolean promisified , int boundArgs , DataFlow:: Node res
759
+ DataFlow:: Node nd , boolean promisified , int boundArgs , string prop , DataFlow:: Node res
727
760
) {
728
761
exists ( DataFlow:: TypeTracker t , StepSummary summary , DataFlow:: SourceNode prev |
729
- prev = trackUseNode ( nd , promisified , boundArgs , t ) and
762
+ prev = trackUseNode ( nd , promisified , boundArgs , prop , t ) and
730
763
StepSummary:: step ( prev , res , summary ) and
731
764
result = t .append ( summary )
732
765
)
733
766
}
734
767
735
768
private DataFlow:: SourceNode trackUseNode (
736
- DataFlow:: SourceNode nd , boolean promisified , int boundArgs
769
+ DataFlow:: SourceNode nd , boolean promisified , int boundArgs , string prop
737
770
) {
738
- result = trackUseNode ( nd , promisified , boundArgs , DataFlow:: TypeTracker:: end ( ) )
771
+ result = trackUseNode ( nd , promisified , boundArgs , prop , DataFlow:: TypeTracker:: end ( ) )
739
772
}
740
773
741
774
/**
742
775
* Gets a node that is inter-procedurally reachable from `nd`, which is a use of some node.
743
776
*/
744
777
cached
745
778
DataFlow:: SourceNode trackUseNode ( DataFlow:: SourceNode nd ) {
746
- result = trackUseNode ( nd , false , 0 )
779
+ result = trackUseNode ( nd , false , 0 , "" )
747
780
}
748
781
749
782
private DataFlow:: SourceNode trackDefNode ( DataFlow:: Node nd , DataFlow:: TypeBackTracker t ) {
0 commit comments