Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 205dd1a

Browse files
authored
Merge pull request #3881 from intrigus-lgtm/more-pathcreations
Java: Centralize and model additional path creations.
2 parents 5f635ac + 1011325 commit 205dd1a

File tree

8 files changed

+285
-80
lines changed

8 files changed

+285
-80
lines changed

java/ql/src/Security/CWE/CWE-022/PathsCommon.qll

Lines changed: 0 additions & 74 deletions
This file was deleted.

java/ql/src/Security/CWE/CWE-022/TaintedPath.ql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414

1515
import java
1616
import semmle.code.java.dataflow.FlowSources
17-
import PathsCommon
17+
import semmle.code.java.security.PathCreation
1818
import DataFlow::PathGraph
19+
import TaintedPathCommon
1920

2021
class ContainsDotDotSanitizer extends DataFlow::BarrierGuard {
2122
ContainsDotDotSanitizer() {
@@ -34,7 +35,7 @@ class TaintedPathConfig extends TaintTracking::Configuration {
3435
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
3536

3637
override predicate isSink(DataFlow::Node sink) {
37-
exists(Expr e | e = sink.asExpr() | e = any(PathCreation p).getInput() and not guarded(e))
38+
exists(Expr e | e = sink.asExpr() | e = any(PathCreation p).getAnInput() and not guarded(e))
3839
}
3940

4041
override predicate isSanitizer(DataFlow::Node node) {
@@ -48,7 +49,7 @@ class TaintedPathConfig extends TaintTracking::Configuration {
4849

4950
from DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, TaintedPathConfig conf
5051
where
51-
sink.getNode().asExpr() = p.getInput() and
52+
sink.getNode().asExpr() = p.getAnInput() and
5253
conf.hasFlowPath(source, sink)
5354
select p, source, sink, "$@ flows to here and is used in a path.", source.getNode(),
5455
"User-provided value"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Models a very basic guard for the tainted path queries.
3+
*/
4+
5+
import java
6+
import semmle.code.java.controlflow.Guards
7+
import semmle.code.java.security.PathCreation
8+
9+
private predicate inWeakCheck(Expr e) {
10+
// None of these are sufficient to guarantee that a string is safe.
11+
exists(MethodAccess m, Method def | m.getQualifier() = e and m.getMethod() = def |
12+
def.getName() = "startsWith" or
13+
def.getName() = "endsWith" or
14+
def.getName() = "isEmpty" or
15+
def.getName() = "equals"
16+
)
17+
or
18+
// Checking against `null` has no bearing on path traversal.
19+
exists(EqualityTest b | b.getAnOperand() = e | b.getAnOperand() instanceof NullLiteral)
20+
}
21+
22+
// Ignore cases where the variable has been checked somehow,
23+
// but allow some particularly obviously bad cases.
24+
predicate guarded(VarAccess e) {
25+
exists(PathCreation p | e = p.getAnInput()) and
26+
exists(ConditionBlock cb, Expr c |
27+
cb.getCondition().getAChildExpr*() = c and
28+
c = e.getVariable().getAnAccess() and
29+
cb.controls(e.getBasicBlock(), true) and
30+
// Disallow a few obviously bad checks.
31+
not inWeakCheck(c)
32+
)
33+
}

java/ql/src/Security/CWE/CWE-022/TaintedPathLocal.ql

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,26 @@
1414

1515
import java
1616
import semmle.code.java.dataflow.FlowSources
17-
import PathsCommon
17+
import semmle.code.java.security.PathCreation
1818
import DataFlow::PathGraph
19+
import TaintedPathCommon
1920

2021
class TaintedPathLocalConfig extends TaintTracking::Configuration {
2122
TaintedPathLocalConfig() { this = "TaintedPathLocalConfig" }
2223

2324
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
2425

25-
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(PathCreation p).getInput() }
26+
override predicate isSink(DataFlow::Node sink) {
27+
sink.asExpr() = any(PathCreation p).getAnInput()
28+
}
2629
}
2730

2831
from
2932
DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, Expr e,
3033
TaintedPathLocalConfig conf
3134
where
3235
e = sink.getNode().asExpr() and
33-
e = p.getInput() and
36+
e = p.getAnInput() and
3437
conf.hasFlowPath(source, sink) and
3538
not guarded(e)
3639
select p, source, sink, "$@ flows to here and is used in a path.", source.getNode(),
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* Models the different ways to create paths. Either by using `java.io.File`-related APIs or `java.nio.file.Path`-related APIs.
3+
*/
4+
5+
import java
6+
7+
/** Models the creation of a path. */
8+
abstract class PathCreation extends Expr {
9+
/**
10+
* Gets an input that is used in the creation of this path.
11+
* This excludes inputs of type `File` and `Path`.
12+
*/
13+
abstract Expr getAnInput();
14+
}
15+
16+
/** Models the `java.nio.file.Paths.get` method. */
17+
private class PathsGet extends PathCreation, MethodAccess {
18+
PathsGet() {
19+
exists(Method m | m = this.getMethod() |
20+
m.getDeclaringType() instanceof TypePaths and
21+
m.getName() = "get"
22+
)
23+
}
24+
25+
override Expr getAnInput() { result = this.getAnArgument() }
26+
}
27+
28+
/** Models the `java.nio.file.FileSystem.getPath` method. */
29+
private class FileSystemGetPath extends PathCreation, MethodAccess {
30+
FileSystemGetPath() {
31+
exists(Method m | m = this.getMethod() |
32+
m.getDeclaringType() instanceof TypeFileSystem and
33+
m.getName() = "getPath"
34+
)
35+
}
36+
37+
override Expr getAnInput() { result = this.getAnArgument() }
38+
}
39+
40+
/** Models the `new java.io.File(...)` constructor. */
41+
private class FileCreation extends PathCreation, ClassInstanceExpr {
42+
FileCreation() { this.getConstructedType() instanceof TypeFile }
43+
44+
override Expr getAnInput() {
45+
result = this.getAnArgument() and
46+
// Relevant arguments include those that are not a `File`.
47+
not result.getType() instanceof TypeFile
48+
}
49+
}
50+
51+
/** Models the `java.nio.file.Path.resolveSibling` method. */
52+
private class PathResolveSiblingCreation extends PathCreation, MethodAccess {
53+
PathResolveSiblingCreation() {
54+
exists(Method m | m = this.getMethod() |
55+
m.getDeclaringType() instanceof TypePath and
56+
m.getName() = "resolveSibling"
57+
)
58+
}
59+
60+
override Expr getAnInput() {
61+
result = this.getAnArgument() and
62+
// Relevant arguments are those of type `String`.
63+
result.getType() instanceof TypeString
64+
}
65+
}
66+
67+
/** Models the `java.nio.file.Path.resolve` method. */
68+
private class PathResolveCreation extends PathCreation, MethodAccess {
69+
PathResolveCreation() {
70+
exists(Method m | m = this.getMethod() |
71+
m.getDeclaringType() instanceof TypePath and
72+
m.getName() = "resolve"
73+
)
74+
}
75+
76+
override Expr getAnInput() {
77+
result = this.getAnArgument() and
78+
// Relevant arguments are those of type `String`.
79+
result.getType() instanceof TypeString
80+
}
81+
}
82+
83+
/** Models the `java.nio.file.Path.of` method. */
84+
private class PathOfCreation extends PathCreation, MethodAccess {
85+
PathOfCreation() {
86+
exists(Method m | m = this.getMethod() |
87+
m.getDeclaringType() instanceof TypePath and
88+
m.getName() = "of"
89+
)
90+
}
91+
92+
override Expr getAnInput() { result = this.getAnArgument() }
93+
}
94+
95+
/** Models the `new java.io.FileWriter(...)` constructor. */
96+
private class FileWriterCreation extends PathCreation, ClassInstanceExpr {
97+
FileWriterCreation() { this.getConstructedType().hasQualifiedName("java.io", "FileWriter") }
98+
99+
override Expr getAnInput() {
100+
result = this.getAnArgument() and
101+
// Relevant arguments are those of type `String`.
102+
result.getType() instanceof TypeString
103+
}
104+
}
105+
106+
/** Models the `new java.io.FileReader(...)` constructor. */
107+
private class FileReaderCreation extends PathCreation, ClassInstanceExpr {
108+
FileReaderCreation() { this.getConstructedType().hasQualifiedName("java.io", "FileReader") }
109+
110+
override Expr getAnInput() {
111+
result = this.getAnArgument() and
112+
// Relevant arguments are those of type `String`.
113+
result.getType() instanceof TypeString
114+
}
115+
}
116+
117+
/** Models the `new java.io.FileInputStream(...)` constructor. */
118+
private class FileInputStreamCreation extends PathCreation, ClassInstanceExpr {
119+
FileInputStreamCreation() {
120+
this.getConstructedType().hasQualifiedName("java.io", "FileInputStream")
121+
}
122+
123+
override Expr getAnInput() {
124+
result = this.getAnArgument() and
125+
// Relevant arguments are those of type `String`.
126+
result.getType() instanceof TypeString
127+
}
128+
}
129+
130+
/** Models the `new java.io.FileOutputStream(...)` constructor. */
131+
private class FileOutputStreamCreation extends PathCreation, ClassInstanceExpr {
132+
FileOutputStreamCreation() {
133+
this.getConstructedType().hasQualifiedName("java.io", "FileOutputStream")
134+
}
135+
136+
override Expr getAnInput() {
137+
result = this.getAnArgument() and
138+
// Relevant arguments are those of type `String`.
139+
result.getType() instanceof TypeString
140+
}
141+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
| PathCreation.java:13:18:13:32 | new File(...) | PathCreation.java:13:27:13:31 | "dir" |
2+
| PathCreation.java:14:19:14:40 | new File(...) | PathCreation.java:14:28:14:32 | "dir" |
3+
| PathCreation.java:14:19:14:40 | new File(...) | PathCreation.java:14:35:14:39 | "sub" |
4+
| PathCreation.java:18:18:18:49 | new File(...) | PathCreation.java:18:44:18:48 | "sub" |
5+
| PathCreation.java:18:27:18:41 | new File(...) | PathCreation.java:18:36:18:40 | "dir" |
6+
| PathCreation.java:22:18:22:41 | new File(...) | PathCreation.java:22:27:22:40 | new URI(...) |
7+
| PathCreation.java:26:18:26:31 | of(...) | PathCreation.java:26:26:26:30 | "dir" |
8+
| PathCreation.java:27:19:27:39 | of(...) | PathCreation.java:27:27:27:31 | "dir" |
9+
| PathCreation.java:27:19:27:39 | of(...) | PathCreation.java:27:34:27:38 | "sub" |
10+
| PathCreation.java:31:18:31:40 | of(...) | PathCreation.java:31:26:31:39 | new URI(...) |
11+
| PathCreation.java:35:18:35:33 | get(...) | PathCreation.java:35:28:35:32 | "dir" |
12+
| PathCreation.java:36:19:36:41 | get(...) | PathCreation.java:36:29:36:33 | "dir" |
13+
| PathCreation.java:36:19:36:41 | get(...) | PathCreation.java:36:36:36:40 | "sub" |
14+
| PathCreation.java:40:18:40:42 | get(...) | PathCreation.java:40:28:40:41 | new URI(...) |
15+
| PathCreation.java:44:18:44:56 | getPath(...) | PathCreation.java:44:51:44:55 | "dir" |
16+
| PathCreation.java:45:19:45:64 | getPath(...) | PathCreation.java:45:52:45:56 | "dir" |
17+
| PathCreation.java:45:19:45:64 | getPath(...) | PathCreation.java:45:59:45:63 | "sub" |
18+
| PathCreation.java:49:18:49:31 | of(...) | PathCreation.java:49:26:49:30 | "dir" |
19+
| PathCreation.java:49:18:49:53 | resolveSibling(...) | PathCreation.java:49:48:49:52 | "sub" |
20+
| PathCreation.java:53:18:53:31 | of(...) | PathCreation.java:53:26:53:30 | "dir" |
21+
| PathCreation.java:53:18:53:46 | resolve(...) | PathCreation.java:53:41:53:45 | "sub" |
22+
| PathCreation.java:57:25:57:45 | new FileWriter(...) | PathCreation.java:57:40:57:44 | "dir" |
23+
| PathCreation.java:61:25:61:45 | new FileReader(...) | PathCreation.java:61:40:61:44 | "dir" |
24+
| PathCreation.java:65:32:65:58 | new FileOutputStream(...) | PathCreation.java:65:53:65:57 | "dir" |
25+
| PathCreation.java:69:31:69:56 | new FileInputStream(...) | PathCreation.java:69:51:69:55 | "dir" |

0 commit comments

Comments
 (0)