Skip to content

Commit

Permalink
[api] fix issue in Tar/Zip Utils that resulted in incorrect artifact …
Browse files Browse the repository at this point in the history
…extraction
  • Loading branch information
siddvenk committed Nov 26, 2024
1 parent 73f7cb0 commit 2ce8065
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 15 deletions.
1 change: 1 addition & 0 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {
exclude("junit", "junit")
}
testImplementation(libs.slf4j.simple)
testImplementation(project(":testing"))
testRuntimeOnly(project(":engines:pytorch:pytorch-model-zoo"))
testRuntimeOnly(project(":engines:pytorch:pytorch-jni"))
}
Expand Down
5 changes: 1 addition & 4 deletions api/src/main/java/ai/djl/util/TarUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ public static void untar(InputStream is, Path dir, boolean gzip) throws IOExcept
try (TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {
TarArchiveEntry entry;
while ((entry = tis.getNextEntry()) != null) {
String entryName = ZipUtils.removeLeadingFileSeparator(entry.getName());
if (entryName.contains("..")) {
throw new IOException("Malicious zip entry: " + entryName);
}
String entryName = ZipUtils.sanitizeAndValidateArchiveEntry(entry.getName(), dir);
Path file = dir.resolve(entryName).toAbsolutePath();
if (entry.isDirectory()) {
Files.createDirectories(file);
Expand Down
28 changes: 21 additions & 7 deletions api/src/main/java/ai/djl/util/ZipUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package ai.djl.util;

import org.apache.commons.io.FilenameUtils;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
Expand Down Expand Up @@ -52,10 +54,7 @@ public static void unzip(InputStream is, Path dest) throws IOException {
ZipEntry entry;
Set<String> set = new HashSet<>();
while ((entry = zis.getNextEntry()) != null) {
String name = removeLeadingFileSeparator(entry.getName());
if (name.contains("..")) {
throw new IOException("Malicious zip entry: " + name);
}
String name = sanitizeAndValidateArchiveEntry(entry.getName(), dest);
set.add(name);
Path file = dest.resolve(name).toAbsolutePath();
if (entry.isDirectory()) {
Expand Down Expand Up @@ -121,14 +120,29 @@ private static void addToZip(Path root, Path file, ZipOutputStream zos) throws I
}
}

static String sanitizeAndValidateArchiveEntry(String name, Path destination)
throws IOException {
String sanitizedName = removeLeadingFileSeparator(name);
Path expectedOutputPath = destination.resolve(sanitizedName).normalize();
if (!expectedOutputPath.startsWith(destination.normalize())) {
throw new IOException(
"Bad archive entry "
+ name
+ ". Attempted write outside destination "
+ destination);
}
return sanitizedName;
}

static String removeLeadingFileSeparator(String name) {
String osAwareArchiveEntryName = FilenameUtils.separatorsToSystem(name);
int index = 0;
for (; index < name.length(); index++) {
if (name.charAt(index) != File.separatorChar) {
for (; index < osAwareArchiveEntryName.length(); index++) {
if (osAwareArchiveEntryName.charAt(index) != File.separatorChar) {
break;
}
}
return name.substring(index);
return osAwareArchiveEntryName.substring(index);
}

private static final class ValidationInputStream extends FilterInputStream {
Expand Down
21 changes: 18 additions & 3 deletions api/src/test/java/ai/djl/util/ZipUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package ai.djl.util;

import ai.djl.testing.TestRequirements;

import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
Expand Down Expand Up @@ -49,13 +51,26 @@ public void testEmptyZipFile() throws IOException {
public void testOffendingTar() throws IOException {
Path path = Paths.get("src/test/resources/offending.tar");
Path output = Paths.get("build/output");
Path file = output.resolve("tmp/empty.txt");
Utils.deleteQuietly(file);
Files.createDirectories(output);
Path outputFile = output.resolve("tmp/empty.txt");
Utils.deleteQuietly(outputFile);
try (InputStream is = Files.newInputStream(path)) {
TarUtils.untar(is, output, false);
}
Assert.assertTrue(Files.exists(file));
Assert.assertTrue(Files.exists(outputFile));
}

@Test
public void testLinuxCreatedWindowsUsedOffendingTar() throws IOException {
TestRequirements.windows();
Path tarPath = Paths.get("src/test/resources/linux_create_windows_use.tar");
Path output = Paths.get("build/output");
Files.createDirectories(output);
Path outputFile = output.resolve("Windows/System32/drivers/etc/dummy.txt");
try (InputStream is = Files.newInputStream(tarPath)) {
TarUtils.untar(is, output, false);
}
Assert.assertTrue(Files.exists(outputFile));
}

@Test
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void runIntegrationTests() {
// TODO: windows CPU build is having OOM issue if 3 engines are loaded and running tests
// together
if (System.getProperty("os.name").startsWith("Win")) {
engines.add("MXNet");
engines.add("PyTorch");
} else if ("aarch64".equals(System.getProperty("os.arch"))) {
engines.add("PyTorch");
} else {
Expand Down
7 changes: 7 additions & 0 deletions testing/src/main/java/ai/djl/testing/TestRequirements.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ public static void notWindows() {
}
}

/** Requires that the test runs on windows, not OSX or linux. */
public static void windows() {
if (!System.getProperty("os.name").toLowerCase().startsWith("win")) {
throw new SkipException("This test requires windows");
}
}

/** Requires that the test runs on x86_64 arch. */
public static void notArm() {
if ("aarch64".equals(System.getProperty("os.arch"))) {
Expand Down

0 comments on commit 2ce8065

Please sign in to comment.