@@ -339,4 +339,78 @@ private module Stdlib {
339339 )
340340 }
341341 }
342+
343+ // ---------------------------------------------------------------------------
344+ // popen2
345+ // ---------------------------------------------------------------------------
346+ /** Gets a reference to the `popen2` module (only available in Python 2). */
347+ private DataFlow:: Node popen2 ( DataFlow:: TypeTracker t ) {
348+ t .start ( ) and
349+ result = DataFlow:: importModule ( "popen2" )
350+ or
351+ exists ( DataFlow:: TypeTracker t2 | result = popen2 ( t2 ) .track ( t2 , t ) )
352+ }
353+
354+ /** Gets a reference to the `popen2` module. */
355+ DataFlow:: Node popen2 ( ) { result = popen2 ( DataFlow:: TypeTracker:: end ( ) ) }
356+
357+ /**
358+ * Gets a reference to the attribute `attr_name` of the `popen2` module.
359+ * WARNING: Only holds for a few predefined attributes.
360+ */
361+ private DataFlow:: Node popen2_attr ( DataFlow:: TypeTracker t , string attr_name ) {
362+ attr_name in [ "popen2" , "popen3" , "popen4" ,
363+ // classes
364+ "Popen3" , "Popen4" ] and
365+ (
366+ t .start ( ) and
367+ result = DataFlow:: importMember ( "popen2" , attr_name )
368+ or
369+ t .startInAttr ( attr_name ) and
370+ result = DataFlow:: importModule ( "popen2" )
371+ )
372+ or
373+ // Due to bad performance when using normal setup with `popen2_attr(t2, attr_name).track(t2, t)`
374+ // we have inlined that code and forced a join
375+ exists ( DataFlow:: TypeTracker t2 |
376+ exists ( DataFlow:: StepSummary summary |
377+ popen2_attr_first_join ( t2 , attr_name , result , summary ) and
378+ t = t2 .append ( summary )
379+ )
380+ )
381+ }
382+
383+ pragma [ nomagic]
384+ private predicate popen2_attr_first_join (
385+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res , DataFlow:: StepSummary summary
386+ ) {
387+ DataFlow:: StepSummary:: step ( popen2_attr ( t2 , attr_name ) , res , summary )
388+ }
389+
390+ /**
391+ * Gets a reference to the attribute `attr_name` of the `popen2` module.
392+ * WARNING: Only holds for a few predefined attributes.
393+ */
394+ private DataFlow:: Node popen2_attr ( string attr_name ) {
395+ result = popen2_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
396+ }
397+
398+ /**
399+ * A call to any of the `popen.popen*` functions, or instantiation of a `popen.Popen*` class.
400+ * See https://docs.python.org/2.7/library/popen2.html
401+ */
402+ private class Popen2PopenCall extends SystemCommandExecution:: Range {
403+ Popen2PopenCall ( ) {
404+ exists ( string name |
405+ name in [ "popen2" , "popen3" , "popen4" , "Popen3" , "Popen4" ] and
406+ this .asCfgNode ( ) .( CallNode ) .getFunction ( ) = popen2_attr ( name ) .asCfgNode ( )
407+ )
408+ }
409+
410+ override DataFlow:: Node getCommand ( ) {
411+ result .asCfgNode ( ) = this .asCfgNode ( ) .( CallNode ) .getArg ( 0 )
412+ or
413+ result .asCfgNode ( ) = this .asCfgNode ( ) .( CallNode ) .getArgByName ( "cmd" )
414+ }
415+ }
342416}
0 commit comments