Skip to content

Commit 5e6f042

Browse files
committed
Python: Model pickle.Unpickler
1 parent 75b06d8 commit 5e6f042

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

python/ql/lib/semmle/python/frameworks/Stdlib.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,22 @@ private module StdlibPrivate {
498498
override string getFormat() { result = "pickle" }
499499
}
500500

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+
501517
// ---------------------------------------------------------------------------
502518
// shelve
503519
// ---------------------------------------------------------------------------

python/ql/test/library-tests/frameworks/stdlib/Decoding.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
# using this keyword argument is disallowed from Python 3.9
1010
pickle.loads(data=payload) # $ decodeInput=payload decodeOutput=pickle.loads(..) decodeFormat=pickle decodeMayExecuteInput
1111

12+
# We don't really have a good way to model a decode happening over multiple statements
13+
# like this. Since the important bit for `py/unsafe-deserialization` is the input, that
14+
# is the main focus. We do a best effort to model the output though (but that will only
15+
# work in local scope).
16+
unpickler = pickle.Unpickler(file_) # $ decodeInput=file_ decodeFormat=pickle decodeMayExecuteInput
17+
unpickler.load() # $ decodeOutput=unpickler.load()
18+
unpickler = pickle.Unpickler(file=file_) # $ decodeInput=file_ decodeFormat=pickle decodeMayExecuteInput
19+
1220
marshal.load(file_) # $ decodeInput=file_ decodeOutput=marshal.load(..) decodeFormat=marshal decodeMayExecuteInput
1321
marshal.loads(payload) # $ decodeInput=payload decodeOutput=marshal.loads(..) decodeFormat=marshal decodeMayExecuteInput
1422

0 commit comments

Comments
 (0)