Files
codeql/java/ql/lib/semmle/code/java/os/OSCheck.qll

165 lines
6.2 KiB
Plaintext

/**
* Provides classes and predicates for guards that check for the current OS.
*/
import java
import semmle.code.java.controlflow.Guards
private import semmle.code.java.environment.SystemProperty
private import semmle.code.java.frameworks.apache.Lang
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.TaintTracking
/**
* A guard that checks if the current OS is Windows.
* When True, the OS is Windows.
* When False, the OS is not Windows.
*/
abstract class IsWindowsGuard extends Guard { }
/**
* A guard that checks if the current OS is a specific Windows variant.
* When True, the OS is Windows.
* When False, the OS *may* still be Windows.
*/
abstract class IsSpecificWindowsVariant extends Guard { }
/**
* A guard that checks if the current OS is unix or unix-like.
* When True, the OS is unix or unix-like.
* When False, the OS is not unix or unix-like.
*/
abstract class IsUnixGuard extends Guard { }
/**
* A guard that checks if the current OS is a specific unix or unix-like variant.
* When True, the OS is unix or unix-like.
* When False, the OS *may* still be unix or unix-like.
*/
abstract class IsSpecificUnixVariant extends Guard { }
/**
* Holds when `ma` compares the current OS against the string constant `osString`.
*/
private predicate isOsFromSystemProp(MethodAccess ma, string osString) {
TaintTracking::localExprTaint(getSystemProperty("os.name"), ma.getQualifier()) and // Call from System.getProperty (or equivalent) to some partial match method
exists(StringPartialMatchMethod m, CompileTimeConstantExpr matchedStringConstant |
m = ma.getMethod() and
matchedStringConstant.getStringValue().toLowerCase() = osString
|
DataFlow::localExprFlow(matchedStringConstant, ma.getArgument(m.getMatchParameterIndex()))
)
}
private class IsWindowsFromSystemProp extends IsWindowsGuard instanceof MethodAccess {
IsWindowsFromSystemProp() { isOsFromSystemProp(this, any(string s | s.regexpMatch("windows?"))) }
}
/**
* Holds when the Guard is an equality check between the system property with the name `propertyName`
* and the string or char constant `compareToLiteral`, and the branch evaluates to `branch`.
*/
private Guard isOsFromSystemPropertyEqualityCheck(
string propertyName, string compareToLiteral, boolean branch
) {
result
.isEquality(getSystemProperty(propertyName),
any(Literal literal |
(literal instanceof CharacterLiteral or literal instanceof StringLiteral) and
literal.getValue() = compareToLiteral
), branch)
}
private class IsWindowsFromPathSeparator extends IsWindowsGuard {
IsWindowsFromPathSeparator() {
this = isOsFromSystemPropertyEqualityCheck("path.separator", ";", true) or
this = isOsFromSystemPropertyEqualityCheck("path.separator", ":", false)
}
}
private class IsWindowsFromFileSeparator extends IsWindowsGuard {
IsWindowsFromFileSeparator() {
this = isOsFromSystemPropertyEqualityCheck("file.separator", "\\", true) or
this = isOsFromSystemPropertyEqualityCheck("file.separator", "/", false)
}
}
private class IsUnixFromPathSeparator extends IsUnixGuard {
IsUnixFromPathSeparator() {
this = isOsFromSystemPropertyEqualityCheck("path.separator", ":", true) or
this = isOsFromSystemPropertyEqualityCheck("path.separator", ";", false)
}
}
private class IsUnixFromFileSeparator extends IsUnixGuard {
IsUnixFromFileSeparator() {
this = isOsFromSystemPropertyEqualityCheck("file.separator", "/", true) or
this = isOsFromSystemPropertyEqualityCheck("file.separator", "\\", false)
}
}
private class IsUnixFromSystemProp extends IsSpecificUnixVariant instanceof MethodAccess {
IsUnixFromSystemProp() {
isOsFromSystemProp(this, any(string s | s.regexpMatch(["mac.*", "linux.*"])))
}
}
bindingset[fieldNamePattern]
private predicate isOsFromApacheCommons(FieldAccess fa, string fieldNamePattern) {
exists(Field f | f = fa.getField() |
f.getDeclaringType() instanceof TypeApacheSystemUtils and
f.getName().matches(fieldNamePattern)
)
}
private class IsWindowsFromApacheCommons extends IsWindowsGuard instanceof FieldAccess {
IsWindowsFromApacheCommons() { isOsFromApacheCommons(this, "IS\\_OS\\_WINDOWS") }
}
private class IsSpecificWindowsVariantFromApacheCommons extends IsSpecificWindowsVariant instanceof FieldAccess {
IsSpecificWindowsVariantFromApacheCommons() {
isOsFromApacheCommons(this, "IS\\_OS\\_WINDOWS\\_%")
}
}
private class IsUnixFromApacheCommons extends IsUnixGuard instanceof FieldAccess {
IsUnixFromApacheCommons() { isOsFromApacheCommons(this, "IS\\_OS\\_UNIX") }
}
private class IsSpecificUnixVariantFromApacheCommons extends IsSpecificUnixVariant instanceof FieldAccess {
IsSpecificUnixVariantFromApacheCommons() {
isOsFromApacheCommons(this,
[
"IS\\_OS\\_AIX", "IS\\_OS\\_HP\\_UX", "IS\\_OS\\_IRIX", "IS\\_OS\\_LINUX", "IS\\_OS\\_MAC%",
"IS\\_OS\\_FREE\\_BSD", "IS\\_OS\\_OPEN\\_BSD", "IS\\_OS\\_NET\\_BSD", "IS\\_OS\\_SOLARIS",
"IS\\_OS\\_SUN\\_OS", "IS\\_OS\\_ZOS"
])
}
}
/**
* A guard that checks if the `java.nio.file.FileSystem` supports posix file permissions.
* This is often used to infer if the OS is unix-based and can generally be considered to be true for all unix-based OSes
* ([source](https://en.wikipedia.org/wiki/POSIX#POSIX-oriented_operating_systems)).
* Looks for calls to `contains("posix")` on the `supportedFileAttributeViews()` method returned by `FileSystem`.
*/
private class IsUnixFromPosixFromFileSystem extends IsUnixGuard instanceof MethodAccess {
IsUnixFromPosixFromFileSystem() {
exists(Method m | m = this.getMethod() |
m.getDeclaringType()
.getASupertype*()
.getSourceDeclaration()
.hasQualifiedName("java.util", "Set") and
m.hasName("contains")
) and
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "posix" and
exists(Method supportedFileAttributeViewsMethod |
supportedFileAttributeViewsMethod.hasName("supportedFileAttributeViews") and
supportedFileAttributeViewsMethod.getDeclaringType() instanceof TypeFileSystem
|
DataFlow::localExprFlow(any(MethodAccess ma |
ma.getMethod() = supportedFileAttributeViewsMethod
), super.getQualifier())
)
}
}