4040import java .nio .file .AccessDeniedException ;
4141import java .nio .file .FileSystems ;
4242import java .nio .file .Files ;
43+ import java .nio .file .Paths ;
4344import java .util .ArrayList ;
4445import java .util .Enumeration ;
4546import java .util .List ;
@@ -966,6 +967,14 @@ private static void unpackEntries(TarArchiveInputStream tis,
966967 + " would create entry outside of " + outputDir );
967968 }
968969
970+ if (entry .isSymbolicLink () || entry .isLink ()) {
971+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
972+ if (!canonicalTargetPath .startsWith (targetDirPath )) {
973+ throw new IOException (
974+ "expanding " + entry .getName () + " would create entry outside of " + outputDir );
975+ }
976+ }
977+
969978 if (entry .isDirectory ()) {
970979 File subDir = new File (outputDir , entry .getName ());
971980 if (!subDir .mkdirs () && !subDir .isDirectory ()) {
@@ -981,10 +990,12 @@ private static void unpackEntries(TarArchiveInputStream tis,
981990 }
982991
983992 if (entry .isSymbolicLink ()) {
984- // Create symbolic link relative to tar parent dir
985- Files .createSymbolicLink (FileSystems .getDefault ()
986- .getPath (outputDir .getPath (), entry .getName ()),
987- FileSystems .getDefault ().getPath (entry .getLinkName ()));
993+ // Create symlink with canonical target path to ensure that we don't extract
994+ // outside targetDirPath
995+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
996+ Files .createSymbolicLink (
997+ FileSystems .getDefault ().getPath (outputDir .getPath (), entry .getName ()),
998+ FileSystems .getDefault ().getPath (canonicalTargetPath ));
988999 return ;
9891000 }
9901001
@@ -996,7 +1007,8 @@ private static void unpackEntries(TarArchiveInputStream tis,
9961007 }
9971008
9981009 if (entry .isLink ()) {
999- File src = new File (outputDir , entry .getLinkName ());
1010+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
1011+ File src = new File (canonicalTargetPath );
10001012 HardLink .createHardLink (src , outputFile );
10011013 return ;
10021014 }
@@ -1014,6 +1026,20 @@ private static void unpackEntries(TarArchiveInputStream tis,
10141026 }
10151027 }
10161028
1029+ /**
1030+ * Gets the canonical path for the given path.
1031+ *
1032+ * @param path The path for which the canonical path needs to be computed.
1033+ * @param parentDir The parent directory to use if the path is a relative path.
1034+ * @return The canonical path of the given path.
1035+ */
1036+ private static String getCanonicalPath (String path , File parentDir ) throws IOException {
1037+ java .nio .file .Path targetPath = Paths .get (path );
1038+ return (targetPath .isAbsolute () ?
1039+ new File (path ) :
1040+ new File (parentDir , path )).getCanonicalPath ();
1041+ }
1042+
10171043 /**
10181044 * Class for creating hardlinks.
10191045 * Supports Unix, WindXP.
0 commit comments