3838import java .nio .file .AccessDeniedException ;
3939import java .nio .file .FileSystems ;
4040import java .nio .file .Files ;
41+ import java .nio .file .Paths ;
4142import java .util .ArrayList ;
4243import java .util .Enumeration ;
4344import java .util .List ;
@@ -970,6 +971,14 @@ private static void unpackEntries(TarArchiveInputStream tis,
970971 + " would create entry outside of " + outputDir );
971972 }
972973
974+ if (entry .isSymbolicLink () || entry .isLink ()) {
975+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
976+ if (!canonicalTargetPath .startsWith (targetDirPath )) {
977+ throw new IOException (
978+ "expanding " + entry .getName () + " would create entry outside of " + outputDir );
979+ }
980+ }
981+
973982 if (entry .isDirectory ()) {
974983 File subDir = new File (outputDir , entry .getName ());
975984 if (!subDir .mkdirs () && !subDir .isDirectory ()) {
@@ -985,10 +994,12 @@ private static void unpackEntries(TarArchiveInputStream tis,
985994 }
986995
987996 if (entry .isSymbolicLink ()) {
988- // Create symbolic link relative to tar parent dir
989- Files .createSymbolicLink (FileSystems .getDefault ()
990- .getPath (outputDir .getPath (), entry .getName ()),
991- FileSystems .getDefault ().getPath (entry .getLinkName ()));
997+ // Create symlink with canonical target path to ensure that we don't extract
998+ // outside targetDirPath
999+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
1000+ Files .createSymbolicLink (
1001+ FileSystems .getDefault ().getPath (outputDir .getPath (), entry .getName ()),
1002+ FileSystems .getDefault ().getPath (canonicalTargetPath ));
9921003 return ;
9931004 }
9941005
@@ -1000,14 +1011,29 @@ private static void unpackEntries(TarArchiveInputStream tis,
10001011 }
10011012
10021013 if (entry .isLink ()) {
1003- File src = new File (outputDir , entry .getLinkName ());
1014+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
1015+ File src = new File (canonicalTargetPath );
10041016 HardLink .createHardLink (src , outputFile );
10051017 return ;
10061018 }
10071019
10081020 org .apache .commons .io .FileUtils .copyToFile (tis , outputFile );
10091021 }
10101022
1023+ /**
1024+ * Gets the canonical path for the given path.
1025+ *
1026+ * @param path The path for which the canonical path needs to be computed.
1027+ * @param parentDir The parent directory to use if the path is a relative path.
1028+ * @return The canonical path of the given path.
1029+ */
1030+ private static String getCanonicalPath (String path , File parentDir ) throws IOException {
1031+ java .nio .file .Path targetPath = Paths .get (path );
1032+ return (targetPath .isAbsolute () ?
1033+ new File (path ) :
1034+ new File (parentDir , path )).getCanonicalPath ();
1035+ }
1036+
10111037 /**
10121038 * Class for creating hardlinks.
10131039 * Supports Unix, WindXP.
0 commit comments