@@ -428,6 +428,22 @@ private module StdlibPrivate {
428
428
// ---------------------------------------------------------------------------
429
429
// marshal
430
430
// ---------------------------------------------------------------------------
431
+ /**
432
+ * A call to `marshal.load`
433
+ * See https://docs.python.org/3/library/marshal.html#marshal.load
434
+ */
435
+ private class MarshalLoadCall extends Decoding:: Range , DataFlow:: CallCfgNode {
436
+ MarshalLoadCall ( ) { this = API:: moduleImport ( "marshal" ) .getMember ( "load" ) .getACall ( ) }
437
+
438
+ override predicate mayExecuteInput ( ) { any ( ) }
439
+
440
+ override DataFlow:: Node getAnInput ( ) { result = this .getArg ( 0 ) }
441
+
442
+ override DataFlow:: Node getOutput ( ) { result = this }
443
+
444
+ override string getFormat ( ) { result = "marshal" }
445
+ }
446
+
431
447
/**
432
448
* A call to `marshal.loads`
433
449
* See https://docs.python.org/3/library/marshal.html#marshal.loads
@@ -447,27 +463,87 @@ private module StdlibPrivate {
447
463
// ---------------------------------------------------------------------------
448
464
// pickle
449
465
// ---------------------------------------------------------------------------
450
- /** Gets a reference to the `pickle` module. */
451
- DataFlow:: Node pickle ( ) { result = API:: moduleImport ( [ "pickle" , "cPickle" , "_pickle" ] ) .getAUse ( ) }
452
-
453
- /** Provides models for the `pickle` module. */
454
- module pickle {
455
- /** Gets a reference to the `pickle.loads` function. */
456
- DataFlow:: Node loads ( ) {
457
- result = API:: moduleImport ( [ "pickle" , "cPickle" , "_pickle" ] ) .getMember ( "loads" ) .getAUse ( )
458
- }
466
+ /** Gets a reference to any of the `pickle` modules. */
467
+ API:: Node pickle ( ) { result = API:: moduleImport ( [ "pickle" , "cPickle" , "_pickle" ] ) }
468
+
469
+ /**
470
+ * A call to `pickle.load`
471
+ * See https://docs.python.org/3/library/pickle.html#pickle.load
472
+ */
473
+ private class PickleLoadCall extends Decoding:: Range , DataFlow:: CallCfgNode {
474
+ PickleLoadCall ( ) { this = pickle ( ) .getMember ( "load" ) .getACall ( ) }
475
+
476
+ override predicate mayExecuteInput ( ) { any ( ) }
477
+
478
+ override DataFlow:: Node getAnInput ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "file" ) ] }
479
+
480
+ override DataFlow:: Node getOutput ( ) { result = this }
481
+
482
+ override string getFormat ( ) { result = "pickle" }
459
483
}
460
484
461
485
/**
462
486
* A call to `pickle.loads`
463
487
* See https://docs.python.org/3/library/pickle.html#pickle.loads
464
488
*/
465
489
private class PickleLoadsCall extends Decoding:: Range , DataFlow:: CallCfgNode {
466
- PickleLoadsCall ( ) { this . getFunction ( ) = pickle:: loads ( ) }
490
+ PickleLoadsCall ( ) { this = pickle ( ) . getMember ( " loads" ) . getACall ( ) }
467
491
468
492
override predicate mayExecuteInput ( ) { any ( ) }
469
493
470
- override DataFlow:: Node getAnInput ( ) { result = this .getArg ( 0 ) }
494
+ override DataFlow:: Node getAnInput ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "data" ) ] }
495
+
496
+ override DataFlow:: Node getOutput ( ) { result = this }
497
+
498
+ override string getFormat ( ) { result = "pickle" }
499
+ }
500
+
501
+ /**
502
+ * A construction of a `pickle.Unpickler`
503
+ * See https://docs.python.org/3/library/pickle.html#pickle.Unpickler
504
+ */
505
+ private class PickleUnpicklerCall extends Decoding:: Range , DataFlow:: CallCfgNode {
506
+ PickleUnpicklerCall ( ) { this = pickle ( ) .getMember ( "Unpickler" ) .getACall ( ) }
507
+
508
+ override predicate mayExecuteInput ( ) { any ( ) }
509
+
510
+ override DataFlow:: Node getAnInput ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "file" ) ] }
511
+
512
+ override DataFlow:: Node getOutput ( ) { result = this .getAMethodCall ( "load" ) }
513
+
514
+ override string getFormat ( ) { result = "pickle" }
515
+ }
516
+
517
+ // ---------------------------------------------------------------------------
518
+ // shelve
519
+ // ---------------------------------------------------------------------------
520
+ /**
521
+ * A call to `shelve.open`
522
+ * See https://docs.python.org/3/library/shelve.html#shelve.open
523
+ *
524
+ * Claiming there is decoding of the input to `shelve.open` is a bit questionable, since
525
+ * it's not the filename, but the contents of the file that is decoded.
526
+ *
527
+ * However, we definitely want to be able to alert if a user is able to control what
528
+ * file is used, since that can lead to code execution (even if that file is free of
529
+ * path injection).
530
+ *
531
+ * So right now the best way we have of modeling this seems to be to treat the filename
532
+ * argument as being deserialized...
533
+ */
534
+ private class ShelveOpenCall extends Decoding:: Range , FileSystemAccess:: Range ,
535
+ DataFlow:: CallCfgNode {
536
+ ShelveOpenCall ( ) { this = API:: moduleImport ( "shelve" ) .getMember ( "open" ) .getACall ( ) }
537
+
538
+ override predicate mayExecuteInput ( ) { any ( ) }
539
+
540
+ override DataFlow:: Node getAnInput ( ) {
541
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "filename" ) ]
542
+ }
543
+
544
+ override DataFlow:: Node getAPathArgument ( ) {
545
+ result in [ this .getArg ( 0 ) , this .getArgByName ( "filename" ) ]
546
+ }
471
547
472
548
override DataFlow:: Node getOutput ( ) { result = this }
473
549
0 commit comments