Skip to content

Commit a31231f

Browse files
committed
Java: Add Guard Classes for checking OS
1 parent 9c79a17 commit a31231f

File tree

9 files changed

+168
-9
lines changed

9 files changed

+168
-9
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Provides classes and predicates for reasoning about checking characterizations about strings.
3+
*/
4+
5+
import java
6+
7+
/**
8+
* Holds if `ma` is a call to a method that checks a partial string match.
9+
*/
10+
predicate isStringPartialMatch(MethodAccess ma) {
11+
ma.getMethod().getDeclaringType() instanceof TypeString and
12+
ma.getMethod().getName() =
13+
["contains", "startsWith", "matches", "regionMatches", "indexOf", "lastIndexOf"]
14+
}

java/ql/lib/semmle/code/java/frameworks/apache/Lang.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,12 @@ private class ApacheStrBuilderFluentMethod extends FluentMethod {
3737
this.getReturnType().(RefType).hasQualifiedName("org.apache.commons.lang3.text", "StrBuilder")
3838
}
3939
}
40+
41+
/**
42+
* The class ``org.apache.commons.lang.SystemUtils` or `org.apache.commons.lang3.SystemUtils`.
43+
*/
44+
class ApacheSystemUtilis extends Class {
45+
ApacheSystemUtilis() {
46+
this.hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "SystemUtils")
47+
}
48+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Provides classes and predicates for guards that check for the current OS.
3+
*/
4+
5+
import java
6+
import semmle.code.java.controlflow.Guards
7+
private import semmle.code.java.frameworks.apache.Lang
8+
private import semmle.code.java.dataflow.DataFlow
9+
private import semmle.code.java.StringCheck
10+
11+
/**
12+
* A complimentatry guard that checks if the current platform is Windows.
13+
*/
14+
abstract class IsWindowsGuard extends Guard { }
15+
16+
/**
17+
* A complimentatry guard that checks if the current platform is unix or unix-like.
18+
*/
19+
abstract class IsUnixGuard extends Guard { }
20+
21+
/**
22+
* Holds when the MethodAccess is a call to check the current OS using either the upper case `osUpperCase` or lower case `osLowerCase` string constants.
23+
*/
24+
bindingset[osUpperCase, osLowerCase]
25+
private predicate isOsFromSystemProp(MethodAccess ma, string osUpperCase, string osLowerCase) {
26+
exists(MethodAccessSystemGetProperty sgpMa |
27+
sgpMa.hasCompileTimeConstantGetPropertyName("os.name")
28+
|
29+
DataFlow::localExprFlow(sgpMa, ma.getQualifier()) and // Call from System.getProperty to some partial match method
30+
ma.getAnArgument().(CompileTimeConstantExpr).getStringValue().matches(osUpperCase)
31+
or
32+
exists(MethodAccess toLowerCaseMa |
33+
toLowerCaseMa.getMethod() =
34+
any(Method m | m.getDeclaringType() instanceof TypeString and m.hasName("toLowerCase"))
35+
|
36+
DataFlow::localExprFlow(sgpMa, toLowerCaseMa.getQualifier()) and // Call from System.getProperty to toLowerCase
37+
DataFlow::localExprFlow(toLowerCaseMa, ma.getQualifier()) and // Call from toLowerCase to some partial match method
38+
ma.getAnArgument().(CompileTimeConstantExpr).getStringValue().matches(osLowerCase)
39+
)
40+
) and
41+
isStringPartialMatch(ma)
42+
}
43+
44+
private class IsWindowsFromSystemProp extends IsWindowsGuard instanceof MethodAccess {
45+
IsWindowsFromSystemProp() { isOsFromSystemProp(this, "Window%", "window%") }
46+
}
47+
48+
private class IsUnixFromSystemProp extends IsUnixGuard instanceof MethodAccess {
49+
IsUnixFromSystemProp() {
50+
isOsFromSystemProp(this, ["Mac%", "Linux%", "LINUX%"], ["mac%", "linux%"])
51+
}
52+
}
53+
54+
private predicate isOsFromApacheCommons(FieldAccess fa, string fieldName) {
55+
exists(Field f | f = fa.getField() |
56+
f.getDeclaringType() instanceof ApacheSystemUtilis and
57+
f.hasName(fieldName)
58+
)
59+
}
60+
61+
private class IsWindowsFromApacheCommons extends IsWindowsGuard instanceof FieldAccess {
62+
IsWindowsFromApacheCommons() { isOsFromApacheCommons(this, "IS_OS_WINDOWS%") }
63+
}
64+
65+
private class IsUnixFromApacheCommons extends IsUnixGuard instanceof FieldAccess {
66+
IsUnixFromApacheCommons() { isOsFromApacheCommons(this, ["IS_OS_UNIX"]) }
67+
}
68+
69+
/**
70+
* A guard that checks if the `java.nio.file.FileSystem` supports posix file permissions.
71+
* This is often used to infer if the OS is unix-based.
72+
* Looks for calls to `contains("poxix")` on the `supportedFileAttributeViews` method returned by `FileSystem`.
73+
*/
74+
private class IsUnixFromPosixFromFileSystem extends IsUnixGuard instanceof MethodAccess {
75+
IsUnixFromPosixFromFileSystem() {
76+
exists(Method m | m = this.getMethod() |
77+
m.getDeclaringType()
78+
.getASupertype*()
79+
.getSourceDeclaration()
80+
.hasQualifiedName("java.util", "Set") and
81+
m.hasName("contains")
82+
) and
83+
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "posix" and
84+
exists(Method supportedFileAttribtueViewsMethod |
85+
supportedFileAttribtueViewsMethod.hasName("supportedFileAttributeViews") and
86+
supportedFileAttribtueViewsMethod.getDeclaringType() instanceof TypeFileSystem
87+
|
88+
DataFlow::localExprFlow(any(MethodAccess ma |
89+
ma.getMethod() = supportedFileAttribtueViewsMethod
90+
), super.getQualifier())
91+
)
92+
}
93+
}

java/ql/src/experimental/Security/CWE/CWE-552/UnsafeUrlForward.qll

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import semmle.code.java.dataflow.FlowSources
55
import semmle.code.java.frameworks.Servlets
66
import semmle.code.java.frameworks.spring.SpringWeb
77
import semmle.code.java.security.RequestForgery
8+
private import semmle.code.java.StringCheck
89
private import semmle.code.java.dataflow.StringPrefixes
910

1011
/** A sink for unsafe URL forward vulnerabilities. */
@@ -167,15 +168,6 @@ private class URLEncodingBarrierGuard extends UnsafeUrlForwardBarrierGuard insta
167168
}
168169
}
169170

170-
/**
171-
* Holds if `ma` is a call to a method that checks a partial string match.
172-
*/
173-
private predicate isStringPartialMatch(MethodAccess ma) {
174-
ma.getMethod().getDeclaringType() instanceof TypeString and
175-
ma.getMethod().getName() =
176-
["contains", "startsWith", "matches", "regionMatches", "indexOf", "lastIndexOf"]
177-
}
178-
179171
/**
180172
* Holds if `ma` is a call to a method of `java.nio.file.Path` that checks a partial path match.
181173
*/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import java.nio.file.FileSystems;
2+
import java.nio.file.Path;
3+
4+
public class Test {
5+
void test() {
6+
if (System.getProperty("os.name").contains("Windows")) {
7+
8+
}
9+
10+
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
11+
12+
}
13+
14+
if (System.getProperty("os.name").contains("Linux")) {
15+
16+
}
17+
18+
if (System.getProperty("os.name").contains("Mac OS X")) {
19+
20+
}
21+
22+
if (System.getProperty("os.name").toLowerCase().contains("mac")) {
23+
24+
}
25+
26+
if (Path.of("whatever").getFileSystem().supportedFileAttributeViews().contains("posix")) {
27+
28+
}
29+
30+
if (FileSystems.getDefault().supportedFileAttributeViews().contains("posix")) {
31+
32+
}
33+
}
34+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| Test.java:14:13:14:59 | contains(...) |
2+
| Test.java:18:13:18:62 | contains(...) |
3+
| Test.java:22:13:22:71 | contains(...) |
4+
| Test.java:26:13:26:95 | contains(...) |
5+
| Test.java:30:13:30:84 | contains(...) |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import default
2+
import semmle.code.java.os.OSCheck
3+
4+
from IsUnixGuard isUnix
5+
select isUnix
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| Test.java:6:13:6:61 | contains(...) |
2+
| Test.java:10:13:10:75 | contains(...) |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import default
2+
import semmle.code.java.os.OSCheck
3+
4+
from IsWindowsGuard isWindows
5+
select isWindows

0 commit comments

Comments
 (0)