@@ -6,6 +6,8 @@ private import python
66private import experimental.dataflow.DataFlow
77private import experimental.dataflow.TaintTracking
88
9+ // for old impl see
10+ // https://github.com/github/codeql/blob/9f95212e103c68d0c1dfa4b6f30fb5d53954ccef/python/ql/src/semmle/python/libraries/Werkzeug.qll
911module Werkzeug {
1012 module Datastructures {
1113 // ---------------------------------------------------------------------- //
@@ -18,94 +20,26 @@ module Werkzeug {
1820 */
1921 abstract class MultiDict extends DataFlow:: Node { }
2022
21- private DataFlow:: Node multiDictTrack ( MultiDict multiDict , DataFlow:: TypeTracker t ) {
22- t .start ( ) and
23- result instanceof MultiDict
24- or
25- exists ( DataFlow:: TypeTracker t2 | result = multiDictTrack ( multiDict , t2 ) .track ( t2 , t ) )
26- }
27-
28- /** Gets a reference to the MultiDict attributes of `flask.request`. */
29- private DataFlow:: Node multiDictTrack ( MultiDict multiDict ) {
30- result = multiDictTrack ( multiDict , DataFlow:: TypeTracker:: end ( ) )
31- }
32-
33- class MultiDictTracked extends DataFlow:: Node , DataFlow:: DictLike {
34- MultiDict multiDict ;
35-
36- MultiDictTracked ( ) { this = multiDictTrack ( multiDict ) }
37-
38- MultiDict getMultiDict ( ) { result = multiDict }
39-
40- override DataFlow:: Node getElementAccess ( ) {
41- result = DataFlow:: DictLike .super .getElementAccess ( )
23+ private module MultiDictTracking {
24+ private DataFlow:: Node getlist ( DataFlow:: TypeTracker t ) {
25+ t .startInAttr ( "getlist" ) and
26+ result instanceof MultiDict
4227 or
43- exists ( MultiDictGetListCallResultTracked tracked_call_result |
44- tracked_call_result .getCall ( ) .getMultiDict ( ) = this and
45- result = tracked_call_result .getElementAccess ( )
46- )
47- }
48- }
49-
50- private DataFlow:: Node multiDictGetListTrack ( MultiDictTracked multiDict , DataFlow:: TypeTracker t ) {
51- /*
52- * using t.startInAttr("getlist") was not good solution
53- * ```py
54- * a = request.args
55- * b = a
56- * a.getlist("key")
57- * b.getlist("key")
58- * ```
59- * would give `request.args` -> `b.getlist` -- this is correct, but not helpful in a taint-path explanation,
60- * we REALLY WANT it to be `request.args -> a -> b -> b.getlist`
61- * This requirement means that we do need the predicate `multiDictTrack`, which could be spared otherwise.
62- */
63-
64- t .start ( ) and
65- result .asCfgNode ( ) .( AttrNode ) .getObject ( "getlist" ) = multiDict .asCfgNode ( )
66- or
67- exists ( DataFlow:: TypeTracker t2 | result = multiDictGetListTrack ( multiDict , t2 ) .track ( t2 , t ) )
68- }
69-
70- private DataFlow:: Node multiDictGetListTrack ( MultiDictTracked multiDict ) {
71- result = multiDictGetListTrack ( multiDict , DataFlow:: TypeTracker:: end ( ) )
72- }
73-
74- private class MultiDictGetListCall extends DataFlow:: Node {
75- MultiDictTracked multiDict ;
76-
77- MultiDictGetListCall ( ) {
78- this .asCfgNode ( ) .( CallNode ) .getFunction ( ) = multiDictGetListTrack ( multiDict ) .asCfgNode ( )
28+ exists ( DataFlow:: TypeTracker t2 | result = getlist ( t2 ) .track ( t2 , t ) )
7929 }
8030
81- MultiDictTracked getMultiDict ( ) { result = multiDict }
82- }
83-
84- private DataFlow:: Node multiDictGetListCallTrack (
85- MultiDictGetListCall call , DataFlow:: TypeTracker t
86- ) {
87- t .start ( ) and
88- result = call
89- or
90- exists ( DataFlow:: TypeTracker t2 | result = multiDictGetListCallTrack ( call , t2 ) .track ( t2 , t ) )
91- }
92-
93- /** Gets a reference to the MultiDict attributes of `flask.request`. */
94- private DataFlow:: Node multiDictGetListCallTrack ( MultiDictGetListCall call ) {
95- result = multiDictGetListCallTrack ( call , DataFlow:: TypeTracker:: end ( ) )
96- }
97-
98- private class MultiDictGetListCallResultTracked extends DataFlow:: Node , DataFlow:: ListLike {
99- MultiDictGetListCall call ;
100-
101- MultiDictGetListCallResultTracked ( ) { this = multiDictGetListCallTrack ( call ) }
102-
103- MultiDictGetListCall getCall ( ) { result = call }
31+ DataFlow:: Node getlist ( ) { result = getlist ( DataFlow:: TypeTracker:: end ( ) ) }
10432 }
10533
10634 private class MultiDictAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
10735 override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
108- nodeTo .( MultiDictGetListCall ) .getMultiDict ( ) = nodeFrom .( MultiDictTracked )
36+ // obj -> obj.getlist
37+ nodeTo .asCfgNode ( ) .( AttrNode ) .getObject ( "getlist" ) = nodeFrom .asCfgNode ( ) and
38+ nodeTo = MultiDictTracking:: getlist ( )
39+ or
40+ // getlist -> getlist()
41+ nodeFrom = MultiDictTracking:: getlist ( ) and
42+ nodeTo .asCfgNode ( ) .( CallNode ) .getFunction ( ) = nodeFrom .asCfgNode ( )
10943 }
11044 }
11145
@@ -121,6 +55,7 @@ module Werkzeug {
12155
12256 private class FileStorageAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
12357 override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
58+ // TODO: should be `nodeFrom = tracked(any(FileStorage fs))`
12459 nodeFrom instanceof FileStorage and
12560 exists ( string name |
12661 name in [ "filename" ,
0 commit comments