3939import java .nio .file .FileSystems ;
4040import java .nio .file .Files ;
4141import java .nio .file .LinkOption ;
42+ import java .nio .file .Paths ;
4243import java .util .ArrayList ;
4344import java .util .Enumeration ;
4445import java .util .List ;
@@ -992,6 +993,14 @@ private static void unpackEntries(TarArchiveInputStream tis,
992993 + " would create entry outside of " + outputDir );
993994 }
994995
996+ if (entry .isSymbolicLink () || entry .isLink ()) {
997+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
998+ if (!canonicalTargetPath .startsWith (targetDirPath )) {
999+ throw new IOException (
1000+ "expanding " + entry .getName () + " would create entry outside of " + outputDir );
1001+ }
1002+ }
1003+
9951004 if (entry .isDirectory ()) {
9961005 File subDir = new File (outputDir , entry .getName ());
9971006 if (!subDir .mkdirs () && !subDir .isDirectory ()) {
@@ -1007,10 +1016,12 @@ private static void unpackEntries(TarArchiveInputStream tis,
10071016 }
10081017
10091018 if (entry .isSymbolicLink ()) {
1010- // Create symbolic link relative to tar parent dir
1011- Files .createSymbolicLink (FileSystems .getDefault ()
1012- .getPath (outputDir .getPath (), entry .getName ()),
1013- FileSystems .getDefault ().getPath (entry .getLinkName ()));
1019+ // Create symlink with canonical target path to ensure that we don't extract
1020+ // outside targetDirPath
1021+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
1022+ Files .createSymbolicLink (
1023+ FileSystems .getDefault ().getPath (outputDir .getPath (), entry .getName ()),
1024+ FileSystems .getDefault ().getPath (canonicalTargetPath ));
10141025 return ;
10151026 }
10161027
@@ -1022,14 +1033,29 @@ private static void unpackEntries(TarArchiveInputStream tis,
10221033 }
10231034
10241035 if (entry .isLink ()) {
1025- File src = new File (outputDir , entry .getLinkName ());
1036+ String canonicalTargetPath = getCanonicalPath (entry .getLinkName (), outputDir );
1037+ File src = new File (canonicalTargetPath );
10261038 HardLink .createHardLink (src , outputFile );
10271039 return ;
10281040 }
10291041
10301042 org .apache .commons .io .FileUtils .copyToFile (tis , outputFile );
10311043 }
10321044
1045+ /**
1046+ * Gets the canonical path for the given path.
1047+ *
1048+ * @param path The path for which the canonical path needs to be computed.
1049+ * @param parentDir The parent directory to use if the path is a relative path.
1050+ * @return The canonical path of the given path.
1051+ */
1052+ private static String getCanonicalPath (String path , File parentDir ) throws IOException {
1053+ java .nio .file .Path targetPath = Paths .get (path );
1054+ return (targetPath .isAbsolute () ?
1055+ new File (path ) :
1056+ new File (parentDir , path )).getCanonicalPath ();
1057+ }
1058+
10331059 /**
10341060 * Class for creating hardlinks.
10351061 * Supports Unix, WindXP.
0 commit comments