From 0f27b1a65e2a4f7cd3a608dd05c26995b96598bc Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 21 Feb 2019 09:12:03 +0000 Subject: [PATCH] Verify entry output location when extracting zip Closes gh-16028 --- .../boot/cli/command/init/ProjectGenerator.java | 11 ++++++++++- .../boot/cli/command/init/InitCommandTests.java | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java index e4c43b038a7..84fc1bd1596 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -122,8 +122,17 @@ class ProjectGenerator { private void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputFolder) throws IOException { ZipEntry entry = zipStream.getNextEntry(); + String canonicalOutputPath = outputFolder.getCanonicalPath() + File.separator; while (entry != null) { File file = new File(outputFolder, entry.getName()); + String canonicalEntryPath = file.getCanonicalPath(); + if (!canonicalEntryPath.startsWith(canonicalOutputPath)) { + throw new ReportableException("Entry '" + entry.getName() + + "' would be written to '" + canonicalEntryPath + + "'. This is outside the output location of '" + + canonicalOutputPath + + "'. Verify your target server configuration."); + } if (file.exists() && !overwrite) { throw new ReportableException((file.isDirectory() ? "Directory" : "File") + " '" + file.getName() diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitCommandTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitCommandTests.java index 1edfb6e93c0..3aaefd6621f 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitCommandTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitCommandTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -125,6 +125,20 @@ public class InitCommandTests extends AbstractHttpClientMockTests { assertThat(archiveFile).exists(); } + @Test + public void generateProjectAndExtractWillNotWriteEntriesOutsideOutputLocation() + throws Exception { + File folder = this.temporaryFolder.newFolder(); + byte[] archive = createFakeZipArchive("../outside.txt", "Fake content"); + MockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest( + "application/zip", "demo.zip", archive); + mockSuccessfulProjectGeneration(request); + assertThat(this.command.run("--extract", folder.getAbsolutePath())) + .isEqualTo(ExitStatus.ERROR); + File archiveFile = new File(folder.getParentFile(), "outside.txt"); + assertThat(archiveFile).doesNotExist(); + } + @Test public void generateProjectAndExtractWithConvention() throws Exception { File folder = this.temporaryFolder.newFolder();