Author: pauls
Date: Fri Jun 15 14:02:50 2018
New Revision: 1833597

URL: http://svn.apache.org/viewvc?rev=1833597&view=rev
Log:
FELIX-5870: Don't allow relative path instructions in bundleclasspath to 
prevent access outside the bundle cache.

Modified:
    
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
    
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
    
felix/trunk/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java

Modified: 
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java?rev=1833597&r1=1833596&r2=1833597&view=diff
==============================================================================
--- 
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
 (original)
+++ 
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/DirectoryContent.java
 Fri Jun 15 14:02:50 2018
@@ -29,12 +29,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
@@ -183,6 +179,14 @@ public class DirectoryContent implements
         // entries are relative to the root of the bundle.
         entryName = (entryName.startsWith("/")) ? entryName.substring(1) : 
entryName;
 
+        if (entryName.trim().startsWith(".." + File.separatorChar) ||
+            entryName.contains(File.separator + ".." + File.separatorChar) ||
+            entryName.trim().endsWith(File.separator + "..") ||
+            entryName.trim().equals(".."))
+        {
+            return null;
+        }
+
         // Any embedded JAR files will be extracted to the embedded directory.
         File embedDir = new File(m_rootDir, m_dir.getName() + 
EMBEDDED_DIRECTORY);
 
@@ -202,18 +206,7 @@ public class DirectoryContent implements
                 (entryName.lastIndexOf('/') >= 0)
                     ? entryName.substring(0, entryName.lastIndexOf('/'))
                     : entryName);
-            synchronized (m_revisionLock)
-            {
-                if (!BundleCache.getSecureAction().fileExists(extractDir))
-                {
-                    if (!BundleCache.getSecureAction().mkdirs(extractDir))
-                    {
-                        m_logger.log(
-                            Logger.LOG_ERROR,
-                            "Unable to extract embedded directory.");
-                    }
-                }
-            }
+
             return new JarContent(
                 m_logger, m_configMap, m_zipFactory, m_revisionLock,
                 extractDir, file, null);
@@ -233,6 +226,14 @@ public class DirectoryContent implements
         // entries are relative to the root of the bundle.
         entryName = (entryName.startsWith("/")) ? entryName.substring(1) : 
entryName;
 
+        if (entryName.trim().startsWith(".." + File.separatorChar) ||
+            entryName.contains(File.separator + ".." + File.separatorChar) ||
+            entryName.trim().endsWith(File.separator + "..") ||
+            entryName.trim().equals(".."))
+        {
+            return null;
+        }
+
         // Any embedded native library files will be extracted to the lib 
directory.
         File libDir = new File(m_rootDir, m_dir.getName() + LIBRARY_DIRECTORY);
 

Modified: 
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java?rev=1833597&r1=1833596&r2=1833597&view=diff
==============================================================================
--- 
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
 (original)
+++ 
felix/trunk/framework/src/main/java/org/apache/felix/framework/cache/JarContent.java
 Fri Jun 15 14:02:50 2018
@@ -208,6 +208,13 @@ public class JarContent implements Conte
         // Remove any leading slash.
         entryName = (entryName.startsWith("/")) ? entryName.substring(1) : 
entryName;
 
+        if (entryName.trim().startsWith(".." + File.separatorChar) ||
+            entryName.contains(File.separator + ".." + File.separatorChar) ||
+            entryName.trim().endsWith(File.separator + "..") ||
+            entryName.trim().equals(".."))
+        {
+            return null;
+        }
         // Any embedded JAR files will be extracted to the embedded directory.
         // Since embedded JAR file names may clash when extracting from 
multiple
         // embedded JAR files, the embedded directory is per embedded JAR file.
@@ -220,52 +227,50 @@ public class JarContent implements Conte
         // directory in the bundle JAR file. Ignore any entries
         // that do not exist per the spec.
         ZipEntry ze = m_zipFile.getEntry(entryName);
+
         if ((ze != null) && ze.isDirectory())
         {
-            File extractDir = new File(embedDir, entryName);
-
-            // Extracting an embedded directory file impacts all other existing
-            // contents for this revision, so we have to grab the revision
-            // lock first before trying to create a directory for an embedded
-            // directory to avoid a race condition.
-            synchronized (m_revisionLock)
-            {
-                if (!BundleCache.getSecureAction().fileExists(extractDir))
-                {
-                    if (!BundleCache.getSecureAction().mkdirs(extractDir))
-                    {
-                        m_logger.log(
-                            Logger.LOG_ERROR,
-                            "Unable to extract embedded directory.");
-                    }
-                }
-            }
             return new ContentDirectoryContent(this, entryName);
         }
         else if ((ze != null) && ze.getName().endsWith(".jar"))
         {
             File extractJar = new File(embedDir, entryName);
 
-            // Extracting the embedded JAR file impacts all other existing
-            // contents for this revision, so we have to grab the revision
-            // lock first before trying to extract the embedded JAR file
-            // to avoid a race condition.
-            synchronized (m_revisionLock)
+            try
             {
-                try
-                {
-                    extractEmbeddedJar(entryName);
-                }
-                catch (Exception ex)
+                if (!BundleCache.getSecureAction().fileExists(extractJar))
                 {
-                    m_logger.log(
-                        Logger.LOG_ERROR,
-                        "Unable to extract embedded JAR file.", ex);
+                    // Extracting the embedded JAR file impacts all other 
existing
+                    // contents for this revision, so we have to grab the 
revision
+                    // lock first before trying to extract the embedded JAR 
file
+                    // to avoid a race condition.
+                    synchronized (m_revisionLock)
+                    {
+                        if 
(!BundleCache.getSecureAction().fileExists(extractJar))
+                        {
+                            // Make sure that the embedded JAR's parent 
directory exists;
+                            // it may be in a sub-directory.
+                            File jarDir = extractJar.getParentFile();
+                            if 
(!BundleCache.getSecureAction().fileExists(jarDir) && 
!BundleCache.getSecureAction().mkdirs(jarDir))
+                            {
+                                throw new IOException("Unable to create 
embedded JAR directory.");
+                            }
+
+                            // Extract embedded JAR into its directory.
+                            
BundleCache.copyStreamToFile(m_zipFile.getInputStream(ze), extractJar);
+                        }
+                    }
                 }
+                return new JarContent(
+                    m_logger, m_configMap, m_zipFactory, m_revisionLock,
+                    extractJar.getParentFile(), extractJar, null);
+            }
+            catch (Exception ex)
+            {
+                m_logger.log(
+                    Logger.LOG_ERROR,
+                    "Unable to extract embedded JAR file.", ex);
             }
-            return new JarContent(
-                m_logger, m_configMap, m_zipFactory, m_revisionLock,
-                extractJar.getParentFile(), extractJar, null);
         }
 
         // The entry could not be found, so return null.
@@ -281,6 +286,14 @@ public class JarContent implements Conte
         // Remove any leading slash.
         entryName = (entryName.startsWith("/")) ? entryName.substring(1) : 
entryName;
 
+        if (entryName.trim().startsWith(".." + File.separatorChar) ||
+            entryName.contains(File.separator + ".." + File.separatorChar) ||
+            entryName.trim().endsWith(File.separator + "..") ||
+            entryName.trim().equals(".."))
+        {
+            return null;
+        }
+
         // Any embedded native libraries will be extracted to the lib 
directory.
         // Since embedded library file names may clash when extracting from 
multiple
         // embedded JAR files, the embedded lib directory is per embedded JAR 
file.
@@ -385,54 +398,6 @@ public class JarContent implements Conte
         return m_file;
     }
 
-    /**
-     * This method extracts an embedded JAR file from the bundle's
-     * JAR file.
-     * @param jarPath the path to the embedded JAR file inside the bundle JAR 
file.
-    **/
-    private void extractEmbeddedJar(String jarPath)
-        throws Exception
-    {
-        // Remove leading slash if present.
-        jarPath = (jarPath.length() > 0) && (jarPath.charAt(0) == '/')
-            ? jarPath.substring(1) : jarPath;
-
-        // Any embedded JAR files will be extracted to the embedded directory.
-        // Since embedded JAR file names may clash when extracting from 
multiple
-        // embedded JAR files, the embedded directory is per embedded JAR file.
-        File embedDir = new File(m_rootDir, m_file.getName() + 
EMBEDDED_DIRECTORY);
-        File jarFile = new File(embedDir, jarPath);
-
-        if (!BundleCache.getSecureAction().fileExists(jarFile))
-        {
-            // Make sure class path entry is a JAR file.
-            ZipEntry ze = m_zipFile.getEntry(jarPath);
-            if (ze == null)
-            {
-                return;
-            }
-            // If the zip entry is a directory, then ignore it since
-            // we don't need to extact it; otherwise, it points to an
-            // embedded JAR file, so extract it.
-            else if (!ze.isDirectory())
-            {
-                // Make sure that the embedded JAR's parent directory exists;
-                // it may be in a sub-directory.
-                File jarDir = jarFile.getParentFile();
-                if (!BundleCache.getSecureAction().fileExists(jarDir))
-                {
-                    if (!BundleCache.getSecureAction().mkdirs(jarDir))
-                    {
-                        throw new IOException("Unable to create embedded JAR 
directory.");
-                    }
-                }
-
-                // Extract embedded JAR into its directory.
-                BundleCache.copyStreamToFile(m_zipFile.getInputStream(ze), 
jarFile);
-            }
-        }
-    }
-
     private static class DevNullRunnable implements Runnable
     {
         private final InputStream m_in;

Modified: 
felix/trunk/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java?rev=1833597&r1=1833596&r2=1833597&view=diff
==============================================================================
--- 
felix/trunk/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java
 (original)
+++ 
felix/trunk/framework/src/test/java/org/apache/felix/framework/cache/BundleCacheTest.java
 Fri Jun 15 14:02:50 2018
@@ -96,6 +96,60 @@ public class BundleCacheTest extends Tes
         createJar(archiveFile, jarFile);
     }
 
+    public void testNoZipSlip() throws Exception
+    {
+        File bundle = new File(filesDir, "slip");
+        Manifest manifest = new Manifest();
+        manifest.getMainAttributes().putValue("Manifest-Version", "v1");
+        
manifest.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+        manifest.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, 
"slip");
+
+        JarOutputStream output = new JarOutputStream(new 
FileOutputStream(bundle),manifest);
+
+        output.putNextEntry(new ZipEntry("../../bar.jar"));
+
+        output.write(BundleCache.read(new FileInputStream(jarFile), 
jarFile.length()));
+
+        output.closeEntry();
+
+        output.close();
+
+        BundleArchive archive = cache.create(1, 1, "slip", new 
FileInputStream(bundle));
+
+        testNoZipSlip(archive);
+
+        archive = cache.create(1, 1, bundle.toURI().toURL().toString(), null);
+
+        testNoZipSlip(archive);
+
+        archive = cache.create(1, 1, "reference:" + 
bundle.toURI().toURL().toString(), null);
+
+        testNoZipSlip(archive);
+
+        File dir = new File(filesDir, "exploded");
+
+        dir.mkdirs();
+
+        File test = new File(dir, "../../bar.jar");
+        test.createNewFile();
+        test.deleteOnExit();
+
+        archive = cache.create(1, 1, "reference:" + 
dir.toURI().toURL().toString(), null);
+
+        testNoZipSlip(archive);
+    }
+
+    public void testNoZipSlip(BundleArchive archive) throws Exception
+    {
+        Content content = 
archive.getCurrentRevision().getContent().getEntryAsContent("../../bar.jar");
+
+        assertNull(content);
+
+        String lib = 
archive.getCurrentRevision().getContent().getEntryAsNativeLibrary("../../bar.jar");
+
+        assertNull(lib);
+    }
+
     public void testDirectoryReference() throws Exception
     {
         testBundle("reference:" + archiveFile.toURI().toURL(), null);


Reply via email to