Skip to content

Commit b2ce0fc

Browse files
committed
Python: Add post-update nodes to args of unresolved calls
Besides solving the problem with `setattr`, it also solved some old problems with json library modeling (yay).
1 parent 5cd08b8 commit b2ce0fc

File tree

4 files changed

+17
-12
lines changed

4 files changed

+17
-12
lines changed

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ module syntheticPostUpdateNode {
126126
* Certain arguments, such as implicit self arguments are already post-update nodes
127127
* and should not have an extra node synthesised.
128128
*/
129-
ArgumentNode argumentPreUpdateNode() {
129+
Node argumentPreUpdateNode() {
130130
result = any(FunctionCall c).getArg(_)
131131
or
132132
// Avoid argument 0 of method calls as those have read post-update nodes.
@@ -136,6 +136,11 @@ module syntheticPostUpdateNode {
136136
or
137137
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
138138
exists(ClassCall c, int n | n > 0 | result = c.getArg(n))
139+
or
140+
// any argument of any call that we have not been able to resolve
141+
exists(CallNode call | not call = any(DataFlowCall c).getNode() |
142+
result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)]
143+
)
139144
}
140145

141146
/** An object might have its value changed after a store. */

python/ql/test/experimental/dataflow/fieldflow/test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,13 @@ def test_getattr():
101101
def test_setattr():
102102
myobj = MyObj(NONSOURCE)
103103
setattr(myobj, "foo", SOURCE)
104-
SINK(myobj.foo) # $ MISSING: flow
104+
SINK(myobj.foo) # $ flow="SOURCE, l:-1 -> myobj.foo"
105105

106106

107107
def test_setattr_getattr():
108108
myobj = MyObj(NONSOURCE)
109109
setattr(myobj, "foo", SOURCE)
110-
SINK(getattr(myobj, "foo")) # $ MISSING: flow
110+
SINK(getattr(myobj, "foo")) # $ flow="SOURCE, l:-1 -> getattr(..)"
111111

112112

113113
def test_setattr_getattr_overwrite():

python/ql/test/library-tests/frameworks/simplejson/taint_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,22 @@ def test():
1717

1818
# load/dump with file-like
1919
tainted_filelike = StringIO()
20-
simplejson.dump(tainted_obj, tainted_filelike) # $ encodeFormat=JSON encodeInput=tainted_obj
20+
simplejson.dump(tainted_obj, tainted_filelike) # $ encodeFormat=JSON encodeInput=tainted_obj encodeOutput=[post]tainted_filelike
2121

2222
tainted_filelike.seek(0)
2323
ensure_tainted(
24-
tainted_filelike, # $ MISSING: tainted
25-
simplejson.load(tainted_filelike), # $ decodeOutput=simplejson.load(..) decodeFormat=JSON decodeInput=tainted_filelike MISSING: tainted
24+
tainted_filelike, # $ tainted
25+
simplejson.load(tainted_filelike), # $ tainted decodeOutput=simplejson.load(..) decodeFormat=JSON decodeInput=tainted_filelike
2626
)
2727

2828
# load/dump with file-like using keyword-args
2929
tainted_filelike = StringIO()
30-
simplejson.dump(obj=tainted_obj, fp=tainted_filelike) # $ encodeFormat=JSON encodeInput=tainted_obj
30+
simplejson.dump(obj=tainted_obj, fp=tainted_filelike) # $ encodeFormat=JSON encodeInput=tainted_obj encodeOutput=[post]tainted_filelike
3131

3232
tainted_filelike.seek(0)
3333
ensure_tainted(
34-
tainted_filelike, # $ MISSING: tainted
35-
simplejson.load(fp=tainted_filelike), # $ decodeOutput=simplejson.load(..) decodeFormat=JSON decodeInput=tainted_filelike MISSING: tainted
34+
tainted_filelike, # $ tainted
35+
simplejson.load(fp=tainted_filelike), # $ tainted decodeOutput=simplejson.load(..) decodeFormat=JSON decodeInput=tainted_filelike
3636
)
3737

3838
# To make things runable

python/ql/test/library-tests/frameworks/ujson/taint_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ def test():
2222

2323
# load/dump with file-like
2424
tainted_filelike = StringIO()
25-
ujson.dump(tainted_obj, tainted_filelike) # $ encodeFormat=JSON encodeInput=tainted_obj
25+
ujson.dump(tainted_obj, tainted_filelike) # $ encodeFormat=JSON encodeInput=tainted_obj encodeOutput=[post]tainted_filelike
2626

2727
tainted_filelike.seek(0)
2828
ensure_tainted(
29-
tainted_filelike, # $ MISSING: tainted
30-
ujson.load(tainted_filelike), # $ decodeOutput=ujson.load(..) decodeFormat=JSON decodeInput=tainted_filelike MISSING: tainted
29+
tainted_filelike, # $ tainted
30+
ujson.load(tainted_filelike), # $ tainted decodeOutput=ujson.load(..) decodeFormat=JSON decodeInput=tainted_filelike
3131
)
3232

3333
# load/dump with file-like using keyword-args does not work in `ujson`

0 commit comments

Comments
 (0)