mirror of
https://github.com/github/codeql.git
synced 2026-06-10 07:21:12 +02:00
Introduce a new Models-as-Data sink sub-kind path-injection[read] for models that only read from or inspect a path. The general java/path-injection query and its PathInjectionSanitizer barrier continue to consider both path-injection and path-injection[read] sinks, so no alerts are lost. The java/zipslip query deliberately selects only path-injection sinks, since read-only accesses such as ClassLoader.getResource or FileInputStream are outside the archive extraction threat model. Addresses https://github.com/github/codeql/issues/21606 along the lines proposed on the issue thread: prefer path-injection[read] over a [create] sub-kind so that miscategorizing a sink causes a false positive (easy to spot) rather than a false negative. - shared/mad/codeql/mad/ModelValidation.qll: allow path-injection[...] as a valid sink kind. - java/ql/lib/ext/*.model.yml: relabel the models that PR #12916 migrated from the historical read-file kind (plus the newer ClassLoader resource-lookup variants that share the same read-only semantics). - java/ql/lib/semmle/code/java/security/TaintedPathQuery.qll and PathSanitizer.qll: select both path-injection and path-injection[read] sinks/barriers. - java/ql/lib/semmle/code/java/security/ZipSlipQuery.qll: keep only path-injection, with a comment explaining why path-injection[read] is excluded. - java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java: add m7 regression covering the Dubbo-style classpath lookup from issue #21606 and assert no alert is produced. - Update TaintedPath.expected for the renamed kinds in the models list. - Add change-notes under java/ql/lib/change-notes and java/ql/src/change-notes.
76 lines
2.8 KiB
Java
76 lines
2.8 KiB
Java
import java.io.*;
|
|
import java.nio.file.*;
|
|
import java.util.zip.*;
|
|
|
|
public class ZipTest {
|
|
public void m1(ZipEntry entry, File dir) throws Exception {
|
|
String name = entry.getName();
|
|
File file = new File(dir, name);
|
|
FileOutputStream os = new FileOutputStream(file); // ZipSlip
|
|
RandomAccessFile raf = new RandomAccessFile(file, "rw"); // ZipSlip
|
|
FileWriter fw = new FileWriter(file); // ZipSlip
|
|
}
|
|
|
|
public void m2(ZipEntry entry, File dir) throws Exception {
|
|
String name = entry.getName();
|
|
File file = new File(dir, name);
|
|
File canFile = file.getCanonicalFile();
|
|
String canDir = dir.getCanonicalPath();
|
|
if (!canFile.toPath().startsWith(canDir))
|
|
throw new Exception();
|
|
FileOutputStream os = new FileOutputStream(file); // OK
|
|
}
|
|
|
|
public void m3(ZipEntry entry, File dir) throws Exception {
|
|
String name = entry.getName();
|
|
File file = new File(dir, name);
|
|
if (!file.toPath().normalize().startsWith(dir.toPath()))
|
|
throw new Exception();
|
|
FileOutputStream os = new FileOutputStream(file); // OK
|
|
}
|
|
|
|
private void validate(File tgtdir, File file) throws Exception {
|
|
File canFile = file.getCanonicalFile();
|
|
if (!canFile.toPath().startsWith(tgtdir.toPath()))
|
|
throw new Exception();
|
|
}
|
|
|
|
public void m4(ZipEntry entry, File dir) throws Exception {
|
|
String name = entry.getName();
|
|
File file = new File(dir, name);
|
|
validate(dir, file);
|
|
FileOutputStream os = new FileOutputStream(file); // OK
|
|
}
|
|
|
|
public void m5(ZipEntry entry, File dir) throws Exception {
|
|
String name = entry.getName();
|
|
File file = new File(dir, name);
|
|
Path absfile = file.toPath().toAbsolutePath().normalize();
|
|
Path absdir = dir.toPath().toAbsolutePath().normalize();
|
|
if (!absfile.startsWith(absdir))
|
|
throw new Exception();
|
|
FileOutputStream os = new FileOutputStream(file); // OK
|
|
}
|
|
|
|
public void m6(ZipEntry entry, Path dir) throws Exception {
|
|
String canonicalDest = dir.toFile().getCanonicalPath();
|
|
Path target = dir.resolve(entry.getName());
|
|
String canonicalTarget = target.toFile().getCanonicalPath();
|
|
if (!canonicalTarget.startsWith(canonicalDest + File.separator))
|
|
throw new Exception();
|
|
OutputStream os = Files.newOutputStream(target); // OK
|
|
}
|
|
|
|
// Regression for https://github.com/github/codeql/issues/21606: archive entry
|
|
// names flowing into read-only classpath/resource lookups are outside the
|
|
// Zip Slip threat model.
|
|
public void m7(ZipEntry entry) throws Exception {
|
|
String name = entry.getName();
|
|
ClassLoader.getSystemResources(name); // OK - read-only resource lookup
|
|
getClass().getResource(name); // OK - read-only resource lookup
|
|
getClass().getResourceAsStream(name); // OK - read-only resource lookup
|
|
new FileInputStream(name); // OK - read-only file open
|
|
new FileReader(name); // OK - read-only file open
|
|
}
|
|
}
|