Skip to content

Commit 650d570

Browse files
committed
Python: Recognize path arguments to pathlib methods
1 parent bcaba45 commit 650d570

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2539,6 +2539,56 @@ private module StdlibPrivate {
25392539
PathLibOpenCall() { attrbuteName = "open" }
25402540
}
25412541

2542+
/**
2543+
* A call to the `link_to`, `hardlink_to`, or `symlink_to` method on a `pathlib.Path` instance.
2544+
*
2545+
* See
2546+
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.link_to
2547+
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.hardlink_to
2548+
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.symlink_to
2549+
*/
2550+
private class PathLibLinkToCall extends PathlibFileAccess, API::CallNode {
2551+
PathLibLinkToCall() { attrbuteName in ["link_to", "hardlink_to", "symlink_to"] }
2552+
2553+
override DataFlow::Node getAPathArgument() {
2554+
result = super.getAPathArgument()
2555+
or
2556+
result = this.getParameter(0, "target").getARhs()
2557+
}
2558+
}
2559+
2560+
/**
2561+
* A call to the `replace` or `rename` method on a `pathlib.Path` instance.
2562+
*
2563+
* See
2564+
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.replace
2565+
* - https://docs.python.org/3/library/pathlib.html#pathlib.Path.rename
2566+
*/
2567+
private class PathLibReplaceCall extends PathlibFileAccess, API::CallNode {
2568+
PathLibReplaceCall() { attrbuteName in ["replace", "rename"] }
2569+
2570+
override DataFlow::Node getAPathArgument() {
2571+
result = super.getAPathArgument()
2572+
or
2573+
result = this.getParameter(0, "target").getARhs()
2574+
}
2575+
}
2576+
2577+
/**
2578+
* A call to the `samefile` method on a `pathlib.Path` instance.
2579+
*
2580+
* See https://docs.python.org/3/library/pathlib.html#pathlib.Path.samefile
2581+
*/
2582+
private class PathLibSameFileCall extends PathlibFileAccess, API::CallNode {
2583+
PathLibSameFileCall() { attrbuteName = "samefile" }
2584+
2585+
override DataFlow::Node getAPathArgument() {
2586+
result = super.getAPathArgument()
2587+
or
2588+
result = this.getParameter(0, "other_path").getARhs()
2589+
}
2590+
}
2591+
25422592
/** An additional taint steps for objects of type `pathlib.Path` */
25432593
private class PathlibPathTaintStep extends TaintTracking::AdditionalTaintStep {
25442594
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {

python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
wb = p.write_bytes
2323
wb(b"hello") # $ getAPathArgument=p fileWriteData=b"hello"
2424

25-
p.link_to("target") # $ getAPathArgument=p MISSING: getAPathArgument="target"
26-
p.link_to(target="target") # $ getAPathArgument=p MISSING: getAPathArgument="target"
25+
p.link_to("target") # $ getAPathArgument=p getAPathArgument="target"
26+
p.link_to(target="target") # $ getAPathArgument=p getAPathArgument="target"
2727

28-
p.samefile("other_path") # $ getAPathArgument=p MISSING: getAPathArgument="other_path"
29-
p.samefile(other_path="other_path") # $ getAPathArgument=p MISSING: getAPathArgument="other_path"
28+
p.samefile("other_path") # $ getAPathArgument=p getAPathArgument="other_path"
29+
p.samefile(other_path="other_path") # $ getAPathArgument=p getAPathArgument="other_path"
3030

31-
p.rename("target") # $ getAPathArgument=p MISSING: getAPathArgument="target"
32-
p.rename(target="target") # $ getAPathArgument=p MISSING: getAPathArgument="target"
31+
p.rename("target") # $ getAPathArgument=p getAPathArgument="target"
32+
p.rename(target="target") # $ getAPathArgument=p getAPathArgument="target"
3333

34-
p.replace("target") # $ getAPathArgument=p MISSING: getAPathArgument="target"
35-
p.replace(target="target") # $ getAPathArgument=p MISSING: getAPathArgument="target"
34+
p.replace("target") # $ getAPathArgument=p getAPathArgument="target"
35+
p.replace(target="target") # $ getAPathArgument=p getAPathArgument="target"

0 commit comments

Comments
 (0)