You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2018/11/08 21:23:52 UTC

svn commit: r1846198 - in /felix/trunk/framework/src: main/java/org/apache/felix/framework/ main/java/org/apache/felix/framework/util/ test/java/org/apache/felix/framework/

Author: pauls
Date: Thu Nov  8 21:23:52 2018
New Revision: 1846198

URL: http://svn.apache.org/viewvc?rev=1846198&view=rev
Log:
FELIX-5978: Ensure getClassLoader() is called in a safe way when security is enabled - patched provided by Tim Ward - thanks! (This closes #160)

Modified:
    felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
    felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
    felix/trunk/framework/src/test/java/org/apache/felix/framework/URLHandlersTest.java

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java?rev=1846198&r1=1846197&r2=1846198&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/BundleProtectionDomain.java Thu Nov  8 21:23:52 2018
@@ -26,6 +26,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
 import java.net.JarURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -53,6 +54,7 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.PackagePermission;
 
 import org.osgi.framework.wiring.BundleRevision;
+import sun.net.www.protocol.file.FileURLConnection;
 
 public class BundleProtectionDomain extends ProtectionDomain
 {
@@ -210,8 +212,6 @@ public class BundleProtectionDomain exte
             }
 
             m_output.closeEntry();
-
-            m_output.flush();
         }
     }
 
@@ -238,100 +238,91 @@ public class BundleProtectionDomain exte
     private static final class RevisionAsJarURL extends URLStreamHandler
     {
         private final WeakReference m_revision;
+        private volatile URL url;
 
         private RevisionAsJarURL(BundleRevisionImpl revision)
         {
             m_revision = new WeakReference(revision);
         }
 
-
         @Override
         protected URLConnection openConnection(URL u) throws IOException
         {
-            return new JarURLConnection(u)
+            if (url != null) {
+                return url.openConnection();
+            }
+            BundleRevisionImpl revision = (BundleRevisionImpl) m_revision.get();
+
+            if (revision != null)
             {
-                @Override
-                public JarFile getJarFile() throws IOException
+                File target;
+                Content content = revision.getContent();
+                if (content instanceof JarContent)
                 {
-                    BundleRevisionImpl revision = (BundleRevisionImpl) m_revision.get();
-
-                    if (revision != null)
+                    target = ((JarContent) content).getFile();
+                }
+                else
+                {
+                    target = Felix.m_secureAction.createTempFile("jar", null, null);
+                    Felix.m_secureAction.deleteFileOnExit(target);
+                    FileOutputStream output = null;
+                    InputStream input = null;
+                    IOException rethrow = null;
+                    try
                     {
-                        Content content = revision.getContent();
-                        if (content instanceof JarContent)
+                        output = new FileOutputStream(target);
+                        input = new BundleInputStream(content);
+                        byte[] buffer = new byte[64 * 1024];
+                        for (int i = input.read(buffer);i != -1; i = input.read(buffer))
                         {
-                            return Felix.m_secureAction.openJarFile(((JarContent) content).getFile());
+                            output.write(buffer,0, i);
                         }
-                        else
+                    }
+                    catch (IOException ex)
+                    {
+                        rethrow = ex;
+                    }
+                    finally
+                    {
+                        if (output != null)
                         {
-                            File target = Felix.m_secureAction.createTempFile("jar", null, null);
-                            Felix.m_secureAction.deleteFileOnExit(target);
-                            FileOutputStream output = null;
-                            InputStream input = null;
-                            IOException rethrow = null;
                             try
                             {
-                                output = new FileOutputStream(target);
-                                input = new BundleInputStream(content);
-                                byte[] buffer = new byte[64 * 1024];
-                                for (int i = input.read(buffer);i != -1; i = input.read(buffer))
-                                {
-                                    output.write(buffer,0, i);
-                                }
+                                output.close();
                             }
                             catch (IOException ex)
                             {
-                                rethrow = ex;
-                            }
-                            finally
-                            {
-                                if (output != null)
+                                if (rethrow == null)
                                 {
-                                    try
-                                    {
-                                        output.close();
-                                    }
-                                    catch (IOException ex)
-                                    {
-                                        if (rethrow == null)
-                                        {
-                                            rethrow = ex;
-                                        }
-                                    }
-                                }
-
-                                if (input != null)
-                                {
-                                    try
-                                    {
-                                        input.close();
-                                    }
-                                    catch (IOException ex)
-                                    {
-                                        if (rethrow == null)
-                                        {
-                                            rethrow = ex;
-                                        }
-                                    }
+                                    rethrow = ex;
                                 }
+                            }
+                        }
 
-                                if (rethrow != null)
+                        if (input != null)
+                        {
+                            try
+                            {
+                                input.close();
+                            }
+                            catch (IOException ex)
+                            {
+                                if (rethrow == null)
                                 {
-                                    throw rethrow;
+                                    rethrow = ex;
                                 }
                             }
-                            return Felix.m_secureAction.openJarFile(target);
                         }
-                    }
-                    throw new IOException("Unable to access bundle revision.");
-                }
-
-                @Override
-                public void connect() throws IOException
-                {
 
+                        if (rethrow != null)
+                        {
+                            throw rethrow;
+                        }
+                    }
                 }
-            };
+                return (url = new URL("jar:" + target.toURI().toURL() + "!/")).openConnection();
+            }
+            throw new IOException("Unable to access bundle revision.");
         }
 
         private static boolean getUseCachedURL(final BundleRevisionImpl revision)
@@ -382,31 +373,25 @@ public class BundleProtectionDomain exte
             {
                 location = location.substring("reference:".length());
             }
-            URL url;
+
             try
             {
-                url = Felix.m_secureAction.createURL(
-                    Felix.m_secureAction.createURL(null, "jar:", handler), location, null);
+                return Felix.m_secureAction.createURL(
+                    Felix.m_secureAction.createURL(null, "jar:", handler),
+                    location,
+                    handler
+                );
             }
             catch (MalformedURLException ex)
             {
-                url = null;
-            }
+                location =  "jar:" + revision.getEntry("/") + "!/";
 
-            if (url != null && !url.getProtocol().equalsIgnoreCase("jar"))
-            {
-                return url;
-            }
-            else if (url == null)
-            {
-                location = "jar:" + revision.getEntry("/") + "!/";
+                return Felix.m_secureAction.createURL(
+                    Felix.m_secureAction.createURL(null, "jar:", handler),
+                    location,
+                    handler
+                );
             }
-
-            return Felix.m_secureAction.createURL(
-                Felix.m_secureAction.createURL(null, "jar:", handler),
-                location,
-                handler
-            );
         }
     }
 

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=1846198&r1=1846197&r2=1846198&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Thu Nov  8 21:23:52 2018
@@ -4023,10 +4023,12 @@ public class Felix extends BundleImpl im
     {
         // If the class comes from bundle class loader, then return
         // associated bundle if it is from this framework instance.
-        if (clazz.getClassLoader() instanceof BundleReference)
+        ClassLoader classLoader = m_secureAction.getClassLoader(clazz);
+        
+        if (classLoader instanceof BundleReference)
         {
             // Only return the bundle if it is from this framework.
-            BundleReference br = (BundleReference) clazz.getClassLoader();
+            BundleReference br = (BundleReference) classLoader;
             return ((br.getBundle() instanceof BundleImpl)
                 && (((BundleImpl) br.getBundle()).getFramework() == this))
                     ? br.getBundle() : null;

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java?rev=1846198&r1=1846197&r2=1846198&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlers.java Thu Nov  8 21:23:52 2018
@@ -685,16 +685,19 @@ class URLHandlers implements URLStreamHa
         Class[] stack = m_sm.getClassContext();
         // Find the first class that is loaded from a bundle.
         Class targetClass = null;
+        ClassLoader targetClassLoader = null;
         for (int i = 0; i < stack.length; i++)
         {
-            if (stack[i].getClassLoader() != null)
+            ClassLoader classLoader = m_secureAction.getClassLoader(stack[i]);
+			if (classLoader != null)
             {
-                String name = stack[i].getClassLoader().getClass().getName();
+                String name = classLoader.getClass().getName();
                 if (name.startsWith("org.apache.felix.framework.ModuleImpl$ModuleClassLoader")
                     || name.equals("org.apache.felix.framework.searchpolicy.ContentClassLoader")
                     || name.startsWith("org.apache.felix.framework.BundleWiringImpl$BundleClassLoader"))
                 {
                     targetClass = stack[i];
+                    targetClassLoader = classLoader;
                     break;
                 }
             }
@@ -705,7 +708,7 @@ class URLHandlers implements URLStreamHa
         // the bundle that loaded the class.
         if (targetClass != null)
         {
-            ClassLoader index = targetClass.getClassLoader().getClass().getClassLoader();
+            ClassLoader index = m_secureAction.getClassLoader(targetClassLoader.getClass());
 
             List frameworks = (List) m_classloaderToFrameworkLists.get(index);
 

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java?rev=1846198&r1=1846197&r2=1846198&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/URLHandlersStreamHandlerProxy.java Thu Nov  8 21:23:52 2018
@@ -28,6 +28,7 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
+import java.security.PrivilegedAction;
 
 import org.apache.felix.framework.util.SecureAction;
 import org.osgi.service.url.URLStreamHandlerService;
@@ -599,10 +600,11 @@ public class URLHandlersStreamHandlerPro
             {
                 return (URLStreamHandlerService) service;
             }
-            return (URLStreamHandlerService) Proxy.newProxyInstance(
-                URLStreamHandlerService.class.getClassLoader(),
-                new Class[]{URLStreamHandlerService.class},
-                new URLHandlersStreamHandlerProxy(service, m_action));
+            
+            return m_action.createProxy(
+                    m_action.getClassLoader(URLStreamHandlerService.class), 
+                    new Class[]{URLStreamHandlerService.class},
+                    new URLHandlersStreamHandlerProxy(service, m_action));
         }
         catch (ThreadDeath td)
         {
@@ -631,11 +633,10 @@ public class URLHandlersStreamHandlerPro
         }
         if ("parseURL".equals(method.getName()))
         {
-            types[0] = m_service.getClass().getClassLoader().loadClass(
-                URLStreamHandlerSetter.class.getName());
-            params[0] = Proxy.newProxyInstance(
-                m_service.getClass().getClassLoader(), new Class[]{types[0]},
-                (URLHandlersStreamHandlerProxy) params[0]);
+            ClassLoader loader = m_action.getClassLoader(m_service.getClass());
+            types[0] = loader.loadClass(URLStreamHandlerSetter.class.getName());
+            params[0] = m_action.createProxy(loader, new Class[]{types[0]}, 
+                    (URLHandlersStreamHandlerProxy) params[0]);
         }
         return m_action.invokeDirect(m_action.getDeclaredMethod(m_service.getClass(),
             method.getName(), types), m_service, params);

Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java?rev=1846198&r1=1846197&r2=1846198&view=diff
==============================================================================
--- felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java (original)
+++ felix/trunk/framework/src/main/java/org/apache/felix/framework/util/SecureAction.java Thu Nov  8 21:23:52 2018
@@ -20,6 +20,7 @@ package org.apache.felix.framework.util;
 
 import java.io.*;
 import java.lang.reflect.*;
+import java.lang.reflect.Proxy;
 import java.net.*;
 import java.security.*;
 import java.util.Collection;
@@ -1525,6 +1526,28 @@ public class SecureAction
         }
     }
 
+    public Object createProxy(ClassLoader classLoader, 
+            Class<?>[] interfaces, InvocationHandler handler)
+    {
+        if (System.getSecurityManager() != null)
+        {
+            Actions actions = (Actions) m_actions.get();
+            actions.set(Actions.CREATE_PROXY, classLoader, interfaces, handler);
+            try
+            {
+                return AccessController.doPrivileged(actions, m_acc);
+            }
+            catch (PrivilegedActionException e)
+            {
+            	throw (RuntimeException) e.getException();
+            }
+        }
+        else
+        {
+            return Proxy.newProxyInstance(classLoader, interfaces, handler);
+        }
+    }
+
     private static class Actions implements PrivilegedExceptionAction
     {
         public static final int INITIALIZE_CONTEXT_ACTION = 0;
@@ -1585,6 +1608,7 @@ public class SecureAction
         public static final int DELETE_FILEONEXIT_ACTION = 55;
         public static final int INVOKE_WOVEN_CLASS_LISTENER = 56;
         public static final int GET_CANONICAL_PATH = 57;
+        public static final int CREATE_PROXY = 58;
 
         private int m_action = -1;
         private Object m_arg1 = null;
@@ -1845,6 +1869,9 @@ public class SecureAction
                     return null;
                 case GET_CANONICAL_PATH:
                     return ((File) arg1).getCanonicalPath();
+                case CREATE_PROXY:
+                    return Proxy.newProxyInstance((ClassLoader)arg1, (Class<?>[])arg2,
+                            (InvocationHandler) arg3);
             }
 
             return null;

Modified: felix/trunk/framework/src/test/java/org/apache/felix/framework/URLHandlersTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/URLHandlersTest.java?rev=1846198&r1=1846197&r2=1846198&view=diff
==============================================================================
--- felix/trunk/framework/src/test/java/org/apache/felix/framework/URLHandlersTest.java (original)
+++ felix/trunk/framework/src/test/java/org/apache/felix/framework/URLHandlersTest.java Thu Nov  8 21:23:52 2018
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.ContentHandler;
 import java.net.InetAddress;
+import java.net.JarURLConnection;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.net.URLConnection;
@@ -300,7 +301,9 @@ public class URLHandlersTest extends Tes
 
             new URL("test" + System.identityHashCode(TestURLHandlersActivator.this) + ":").openConnection();
 
-
+            if (!(getClass().getProtectionDomain().getCodeSource().getLocation().openConnection() instanceof JarURLConnection)) {
+                throw new Exception("Unexpted Code Source");
+            }
 
             try
             {
@@ -349,14 +352,19 @@ public class URLHandlersTest extends Tes
                 reg.unregister();
             }
 
+            boolean fail;
             try
             {
                 new URL("test" + System.identityHashCode(TestURLHandlersActivator.this) + ":").openConnection();
-                throw new Exception("Unexpected url resolve");
+                fail = true;
             }
             catch (Exception ex)
             {
                 // pass
+                fail = false;
+            }
+            if (fail) {
+                throw new Exception("Unexpected url resolve");
             }
 
             Bundle bundle2 = null;
@@ -376,36 +384,48 @@ public class URLHandlersTest extends Tes
             }
             if (bundle2 != null)
             {
+                fail = false;
                 try
                 {
                     new URL("test" + System.identityHashCode(bundle2) + ":").openConnection();
-                    throw new Exception("Unexpected url2 resolve");
+                    fail = true;
                 }
                 catch (Exception ex)
                 {
                 }
+                if (fail) {
+                    throw new Exception("Unexpected url resolve");
+                }
                 bundle2.start();
                 new URL("test" + System.identityHashCode(bundle2) + ":").openConnection();
                 bundle2.stop();
+                fail = false;
                 try
                 {
                     new URL("test" + System.identityHashCode(bundle2) + ":").openConnection();
-                    throw new Exception("Unexpected url2 resolve");
+                    fail = true;
                 }
                 catch (Exception ex)
                 {
                 }
+                if (fail) {
+                    throw new Exception("Unexpected url resolve");
+                }
             }
             else
             {
+                fail = false;
                 try
                 {
                     new URL("test" + System.identityHashCode(context.getBundle()) + ":").openConnection();
-                    throw new Exception("Unexpected url2 resolve");
+                    fail = true;
                 }
                 catch (Exception ex)
                 {
                 }
+                if (fail) {
+                    throw new Exception("Unexpected url2 resolve");
+                }
                 props = new Hashtable();
                 props.put(URLConstants.URL_HANDLER_PROTOCOL, "test" + System.identityHashCode(context.getBundle()));
                 m_reg = context.registerService(URLStreamHandlerService.class, this, props);