Skip to content

Commit

Permalink
Java: add FileConstructorSanitizer and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Jami Cogswell authored and Jami Cogswell committed Jan 16, 2025
1 parent 90faab4 commit 4dc7562
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
22 changes: 22 additions & 0 deletions java/ql/lib/semmle/code/java/security/PathSanitizer.qll
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,25 @@ private class FileGetNameSanitizer extends PathInjectionSanitizer {
)
}
}

/**
* A sanitizer that considers the second argument to a `File` constructor safe
* if it is checked for `..` components (`PathTraversalGuard`) or if any internal
* `..` components are removed from it (`PathNormalizeSanitizer`).
*/
class FileConstructorSanitizer extends PathInjectionSanitizer {
FileConstructorSanitizer() {
exists(ConstructorCall constrCall, Argument arg, Expr guard |
constrCall.getConstructedType() instanceof TypeFile and
arg = constrCall.getArgument(1) and
(
guard
.(PathTraversalGuard)
.controls(arg.getBasicBlock(), guard.(PathTraversalGuard).getBranch())
or
TaintTracking::localExprTaint(guard.(PathNormalizeSanitizer), arg)
) and
this.asExpr() = constrCall
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,38 @@ public void sendUserFileGood4(Socket sock, String user) throws IOException {
fileLine = fileReader.readLine();
}
}

public void sendUserFileGood5(Socket sock, String user) throws IOException {
BufferedReader filenameReader =
new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8"));
String filename = filenameReader.readLine();
File f1 = new File("safe/file.txt");
// GOOD: ensure that the path does not contain ".." and is used as the
// second argument to a `File` constructor
if (!filename.contains("..")) {
File f2 = new File(f1, filename);
f2.exists();

// Only sanitize `f2`; `filename` is still tainted
BufferedReader fileReader = new BufferedReader(new FileReader(filename)); // $ hasTaintFlow
}
}

public void sendUserFileGood6(Socket sock, String user) throws IOException {
BufferedReader filenameReader =
new BufferedReader(new InputStreamReader(sock.getInputStream(), "UTF-8"));
String filename = filenameReader.readLine();
File f1 = new File("safe/file.txt");

// GOOD: ensure that the path is normalized and is then used as the
// second argument to a `File` constructor
Path normalizedFilename = Paths.get(filename).normalize().toAbsolutePath();
String normalizedFilenameStr = normalizedFilename.toString();
File f2 = new File(f1, normalizedFilenameStr);
f2.exists();

// Only sanitize `f2`; `filename` and `normalizedFilenameStr` are still tainted
BufferedReader fileReader = new BufferedReader(new FileReader(filename)); // $ hasTaintFlow
BufferedReader fileReader2 = new BufferedReader(new FileReader(normalizedFilenameStr)); // $ hasTaintFlow
}
}

0 comments on commit 4dc7562

Please sign in to comment.