@@ -10,6 +10,7 @@ private import semmle.code.powershell.dataflow.DataFlow
1010private import semmle.code.powershell.typetracking.ApiGraphShared
1111private import semmle.code.powershell.typetracking.internal.TypeTrackingImpl
1212private import semmle.code.powershell.controlflow.Cfg
13+ private import frameworks.data.internal.ApiGraphModels
1314private import frameworks.data.internal.ApiGraphModelsExtensions as Extensions
1415private import frameworks.data.internal.ApiGraphModelsSpecific as Specific
1516private import semmle.code.powershell.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -262,8 +263,7 @@ module API {
262263 this = Impl:: MkMethodAccessNode ( result ) or
263264 this = Impl:: MkBackwardNode ( result , _) or
264265 this = Impl:: MkForwardNode ( result , _) or
265- this = Impl:: MkSinkNode ( result ) or
266- this = Impl:: MkNamespaceOfTypeNameNode ( result )
266+ this = Impl:: MkSinkNode ( result )
267267 }
268268
269269 /** Gets the location of this node. */
@@ -272,6 +272,10 @@ module API {
272272 or
273273 this instanceof RootNode and
274274 result instanceof EmptyLocation
275+ or
276+ not this instanceof RootNode and
277+ not exists ( this .getInducingNode ( ) ) and
278+ result instanceof EmptyLocation
275279 }
276280
277281 /**
@@ -331,20 +335,84 @@ module API {
331335 override string toString ( ) { result = "SinkNode(" + this .getInducingNode ( ) + ")" }
332336 }
333337
334- private class UsingNode extends Node , Impl:: MkUsingNode {
335- UsingStmt using ; // TODO: This should really be the cfg node, I think
338+ abstract private class AbstractTypeNameNode extends Node {
339+ string prefix ;
340+
341+ bindingset [ prefix]
342+ AbstractTypeNameNode ( ) { any ( ) }
343+
344+ override string toString ( ) { result = "TypeNameNode(" + this .getTypeName ( ) + ")" }
345+
346+ string getComponent ( ) {
347+ exists ( int n |
348+ result = prefix .splitAt ( "." , n ) and
349+ not exists ( prefix .splitAt ( "." , n + 1 ) )
350+ )
351+ }
352+
353+ string getTypeName ( ) { result = prefix }
354+
355+ abstract Node getSuccessor ( string name ) ;
356+
357+ Node memberEdge ( string name ) { none ( ) }
358+
359+ Node methodEdge ( string name ) { none ( ) }
360+
361+ final predicate isImplicit ( ) { not this .isExplicit ( _) }
362+
363+ predicate isExplicit ( DataFlow:: TypeNameNode typeName ) { none ( ) }
364+ }
365+
366+ final class TypeNameNode = AbstractTypeNameNode ;
367+
368+ private class ExplicitTypeNameNode extends AbstractTypeNameNode , Impl:: MkExplicitTypeNameNode {
369+ ExplicitTypeNameNode ( ) { this = Impl:: MkExplicitTypeNameNode ( prefix ) }
370+
371+ final override Node getSuccessor ( string name ) {
372+ exists ( ExplicitTypeNameNode succ |
373+ succ = Impl:: MkExplicitTypeNameNode ( prefix + "." + name ) and
374+ result = succ
375+ )
376+ or
377+ exists ( DataFlow:: TypeNameNode typeName , int n , string lowerCaseName |
378+ Specific:: needsExplicitTypeNameNode ( typeName , prefix ) and
379+ lowerCaseName = typeName .getLowerCaseName ( ) and
380+ name = lowerCaseName .splitAt ( "." , n ) and
381+ not lowerCaseName .matches ( "%.%" ) and
382+ result = getForwardStartNode ( typeName )
383+ )
384+ }
385+
386+ final override predicate isExplicit ( DataFlow:: TypeNameNode typeName ) {
387+ Specific:: needsExplicitTypeNameNode ( typeName , prefix )
388+ }
389+ }
336390
337- UsingNode ( ) { this = Impl :: MkUsingNode ( using ) }
391+ private string getAnAlias ( string cmdlet ) { Specific :: aliasModel ( cmdlet , result ) }
338392
339- override string toString ( ) { result = "UsingNode(" + using + ")" }
393+ predicate implicitCmdlet ( string mod , string cmdlet ) {
394+ exists ( string cmdlet0 |
395+ Specific:: cmdletModel ( mod , cmdlet0 ) and
396+ cmdlet = [ cmdlet0 , getAnAlias ( cmdlet0 ) ]
397+ )
340398 }
341399
342- private class NamespaceOfTypeNameNode extends Node , Impl:: MkNamespaceOfTypeNameNode {
343- DataFlow:: QualifiedTypeNameNode typeName ;
400+ private class ImplicitTypeNameNode extends AbstractTypeNameNode , Impl:: MkImplicitTypeNameNode {
401+ ImplicitTypeNameNode ( ) { this = Impl:: MkImplicitTypeNameNode ( prefix ) }
402+
403+ final override Node getSuccessor ( string name ) {
404+ result = Impl:: MkImplicitTypeNameNode ( prefix + "." + name )
405+ }
344406
345- NamespaceOfTypeNameNode ( ) { this = Impl :: MkNamespaceOfTypeNameNode ( typeName ) }
407+ final override Node memberEdge ( string name ) { result = this . methodEdge ( name ) }
346408
347- override string toString ( ) { result = "NamespaceOfTypeNameNode(" + typeName + ")" }
409+ final override Node methodEdge ( string name ) {
410+ exists ( DataFlow:: CallNode call |
411+ result = Impl:: MkMethodAccessNode ( call ) and
412+ name = call .getLowerCaseName ( ) and
413+ implicitCmdlet ( prefix , name )
414+ )
415+ }
348416 }
349417
350418 /**
@@ -438,8 +506,8 @@ module API {
438506 MkRoot ( ) or
439507 /** The method accessed at `call`, synthetically treated as a separate object. */
440508 MkMethodAccessNode ( DataFlow:: CallNode call ) or
441- MkUsingNode ( UsingStmt using ) or
442- MkNamespaceOfTypeNameNode ( DataFlow :: QualifiedTypeNameNode typeName ) or
509+ MkExplicitTypeNameNode ( string prefix ) { Specific :: needsExplicitTypeNameNode ( _ , prefix ) } or
510+ MkImplicitTypeNameNode ( string prefix ) { Specific :: needsImplicitTypeNameNode ( prefix ) } or
443511 MkForwardNode ( DataFlow:: LocalSourceNode node , TypeTracker t ) { isReachable ( node , t ) } or
444512 /** Intermediate node for following backward data flow. */
445513 MkBackwardNode ( DataFlow:: LocalSourceNode node , TypeTracker t ) { isReachable ( node , t ) } or
@@ -455,27 +523,8 @@ module API {
455523 node = any ( EntryPoint e ) .getASink ( )
456524 }
457525
458- bindingset [ e]
459- pragma [ inline_late]
460- private DataFlow:: Node getNodeFromExpr ( Expr e ) { result .asExpr ( ) .getExpr ( ) = e }
461-
462526 private import frameworks.data.ModelsAsData
463527
464- cached
465- predicate namespace ( string name , Node node ) {
466- exists ( DataFlow:: QualifiedTypeNameNode typeName |
467- typeName .getNamespace ( ) = name and
468- node = MkNamespaceOfTypeNameNode ( typeName )
469- )
470- or
471- exists ( UsingStmt using |
472- using .getName ( ) .toLowerCase ( ) = name and
473- node = MkUsingNode ( using )
474- )
475- or
476- node = ModelOutput:: getATypeNode ( name )
477- }
478-
479528 cached
480529 predicate topLevelMember ( string name , Node node ) { memberEdge ( root ( ) , name , node ) }
481530
@@ -492,42 +541,51 @@ module API {
492541 predicate memberEdge ( Node pred , string name , Node succ ) {
493542 pred = API:: root ( ) and
494543 (
495- exists ( StringConstExpr read |
496- succ = getForwardStartNode ( getNodeFromExpr ( read ) ) and
497- name = read .getValueString ( )
498- )
544+ succ .( TypeNameNode ) .getTypeName ( ) = name
499545 or
500546 exists ( DataFlow:: AutomaticVariableNode automatic |
501547 automatic .getLowerCaseName ( ) = name and
502548 succ = getForwardStartNode ( automatic )
503549 )
504- or
505- succ = getAnImplicitRootMember ( name )
506550 )
507551 or
508- exists ( DataFlow :: QualifiedTypeNameNode typeName |
509- typeName .getLowerCaseName ( ) = name and
510- pred = MkNamespaceOfTypeNameNode ( typeName ) and
511- succ = getForwardStartNode ( typeName )
552+ exists ( TypeNameNode typeName | pred = typeName |
553+ typeName .getSuccessor ( name ) = succ
554+ or
555+ typeName . memberEdge ( name ) = succ
512556 )
513557 or
514- exists ( MemberExprReadAccess read |
515- read .getLowerCaseMemberName ( ) .toLowerCase ( ) = name and
516- pred = getForwardEndNode ( getALocalSourceStrict ( getNodeFromExpr ( read .getQualifier ( ) ) ) ) and
517- succ = getForwardStartNode ( getNodeFromExpr ( read ) )
558+ exists ( DataFlow:: Node qualifier | pred = getForwardEndNode ( getALocalSourceStrict ( qualifier ) ) |
559+ exists ( CfgNodes:: ExprNodes:: MemberExprReadAccessCfgNode read |
560+ read .getQualifier ( ) = qualifier .asExpr ( ) and
561+ read .getLowerCaseMemberName ( ) = name and
562+ succ = getForwardStartNode ( DataFlow:: exprNode ( read ) )
563+ )
564+ or
565+ exists ( DataFlow:: CallNode call |
566+ call .getLowerCaseName ( ) = name and
567+ call .getQualifier ( ) = qualifier and
568+ succ = MkMethodAccessNode ( call )
569+ )
518570 )
519571 }
520572
521573 cached
522574 predicate methodEdge ( Node pred , string name , Node succ ) {
523575 exists ( DataFlow:: CallNode call |
524- succ = MkMethodAccessNode ( call ) and name = call . getLowerCaseName ( )
525- |
576+ succ = MkMethodAccessNode ( call ) and
577+ name = call . getLowerCaseName ( ) and
526578 pred = getForwardEndNode ( getALocalSourceStrict ( call .getQualifier ( ) ) )
527579 )
528580 or
581+ pred .( TypeNameNode ) .methodEdge ( name ) = succ
582+ or
529583 pred = API:: root ( ) and
530- succ = getAnImplicitRootMember ( name )
584+ exists ( DataFlow:: CallNode call |
585+ not exists ( call .getQualifier ( ) ) and
586+ succ = MkMethodAccessNode ( call ) and
587+ name = call .getLowerCaseName ( )
588+ )
531589 }
532590
533591 cached
0 commit comments