From 63f561fac2eb6ec57f860af71cd6deebb9027aaf Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 31 Aug 2023 21:14:22 +0000 Subject: [PATCH] 8306882: (fs) Path.toRealPath(LinkOption.NOFOLLOW_LINKS) fails when "../../" follows a link Reviewed-by: alanb --- .../unix/classes/sun/nio/fs/UnixPath.java | 16 ++++-- test/jdk/ProblemList.txt | 6 ++- test/jdk/java/nio/file/Path/ToRealPath.java | 52 ++++++++++++++++++- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index a9c63dac923..5e3a80b6063 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -888,8 +888,15 @@ class UnixPath implements Path { } // if not resolving links then eliminate "." and also ".." - // where the previous element is not a link. + // where the previous element is neither a link nor "..". + // if there is a preceding "..", then it might have followed + // a link or a link followed by a sequence of two or more "..". + // if for example one has the path "link/../../file", + // then if a preceding ".." were eliminated, then the result + // would be "/link/file" instead of the correct + // "/link/../../file". UnixPath result = fs.rootDirectory(); + boolean parentIsDotDot = false; for (int i = 0; i < absolute.getNameCount(); i++) { UnixPath element = absolute.getName(i); @@ -898,7 +905,7 @@ class UnixPath implements Path { (element.asByteArray()[0] == '.')) continue; - // cannot eliminate ".." if previous element is a link + // cannot eliminate ".." if previous element is a link or ".." if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') && (element.asByteArray()[1] == '.')) @@ -909,13 +916,16 @@ class UnixPath implements Path { } catch (UnixException x) { x.rethrowAsIOException(result); } - if (!attrs.isSymbolicLink()) { + if (!attrs.isSymbolicLink() && !parentIsDotDot) { result = result.getParent(); if (result == null) { result = fs.rootDirectory(); } continue; } + parentIsDotDot = true; + } else { + parentIsDotDot = false; } result = result.resolve(element); } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 31546524178..5bf9284e3bb 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -543,13 +543,15 @@ java/net/MulticastSocket/SetOutgoingIf.java 8308807 aix-ppc6 java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 +java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 + java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 java/nio/channels/DatagramChannel/Unref.java 8233437 generic-all -jdk/nio/zipfs/TestLocOffsetFromZip64EF.java 8301183 linux-all +java/nio/file/Path/ToRealPath.java 8315273 windows-all -java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 +jdk/nio/zipfs/TestLocOffsetFromZip64EF.java 8301183 linux-all ############################################################################ diff --git a/test/jdk/java/nio/file/Path/ToRealPath.java b/test/jdk/java/nio/file/Path/ToRealPath.java index bbf7973b4ff..46e267e956a 100644 --- a/test/jdk/java/nio/file/Path/ToRealPath.java +++ b/test/jdk/java/nio/file/Path/ToRealPath.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 8295753 + * @bug 8295753 8306882 * @summary Verify correct operation of Path.toRealPath * @library .. /test/lib * @build ToRealPath jdk.test.lib.Platform @@ -142,6 +142,52 @@ public class ToRealPath { DIR.toRealPath(NOFOLLOW_LINKS)); } + @Test + @EnabledIf("supportsLinks") + public void noCollapseDots1() throws IOException { + Path subPath = DIR.resolve(Path.of("dir", "subdir")); + Path sub = Files.createDirectories(subPath); + System.out.println("sub: " + sub); + Files.createSymbolicLink(LINK, sub); + System.out.println("LINK: " + LINK + " -> " + sub); + Path p = Path.of("..", "..", FILE.getFileName().toString()); + System.out.println("p: " + p); + Path path = LINK.resolve(p); + System.out.println("path: " + path); + System.out.println("no follow: " + path.toRealPath(NOFOLLOW_LINKS)); + assertEquals(path.toRealPath(NOFOLLOW_LINKS), path); + + Files.delete(sub); + Files.delete(sub.getParent()); + Files.delete(LINK); + } + + @Test + @EnabledIf("supportsLinks") + public void noCollapseDots2() throws IOException { + Path subPath = DIR.resolve(Path.of("dir", "subdir")); + Path sub = Files.createDirectories(subPath); + Path out = Files.createFile(DIR.resolve(Path.of("out.txt"))); + Path aaa = DIR.resolve(Path.of("aaa")); + Files.createSymbolicLink(aaa, sub); + System.out.println("aaa: " + aaa + " -> " + sub); + Path bbb = DIR.resolve(Path.of("bbb")); + Files.createSymbolicLink(bbb, sub); + System.out.println("bbb: " + bbb + " -> " + sub); + Path p = Path.of("aaa", "..", "..", "bbb", "..", "..", "out.txt"); + Path path = DIR.resolve(p); + System.out.println("path: " + path); + System.out.println("no follow: " + path.toRealPath(NOFOLLOW_LINKS)); + assertEquals(path.toRealPath(NOFOLLOW_LINKS), path); + System.out.println(path.toRealPath()); + + Files.delete(sub); + Files.delete(sub.getParent()); + Files.delete(out); + Files.delete(aaa); + Files.delete(bbb); + } + @Test @EnabledOnOs(OS.MAC) public final void macOSTests() throws IOException { @@ -180,12 +226,14 @@ public class ToRealPath { assertEquals(noFollow.getName(nc - 4), Path.of("theLink")); assertEquals(noFollow.getName(nc - 1), Path.of("theTarget")); + Files.delete(theLink); Files.delete(theTarget); } @AfterAll public static void cleanup() throws IOException { - Files.delete(SUBDIR); Files.delete(FILE); + Files.delete(SUBDIR); + Files.delete(DIR); } }