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 2020/01/28 00:46:47 UTC

svn commit: r1873234 - in /felix/sandbox/pauls/connect: ./ src/main/java/org/apache/felix/framework/ext/ src/main/java/org/apache/felix/framework/util/ src/main/resources/org/apache/felix/framework/util/

Author: pauls
Date: Tue Jan 28 00:46:47 2020
New Revision: 1873234

URL: http://svn.apache.org/viewvc?rev=1873234&view=rev
Log:
Use unsave to work around reflection restrictions.

Added:
    felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/
    felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.bytes   (with props)
    felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.src
Modified:
    felix/sandbox/pauls/connect/pom.xml
    felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java
    felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/util/SecureAction.java

Modified: felix/sandbox/pauls/connect/pom.xml
URL: http://svn.apache.org/viewvc/felix/sandbox/pauls/connect/pom.xml?rev=1873234&r1=1873233&r2=1873234&view=diff
==============================================================================
--- felix/sandbox/pauls/connect/pom.xml (original)
+++ felix/sandbox/pauls/connect/pom.xml Tue Jan 28 00:46:47 2020
@@ -118,6 +118,16 @@
       <resource>
         <directory>src/main/resources</directory>
         <filtering>true</filtering>
+        <excludes>
+        <exclude>**/*.bytes</exclude>
+        </excludes>
+      </resource>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+        <includes>
+          <include>**/*.bytes</include>
+        </includes>
       </resource>
     </resources>
   </build>

Modified: felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java?rev=1873234&r1=1873233&r2=1873234&view=diff
==============================================================================
--- felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java (original)
+++ felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/ext/ClassPathExtenderFactory.java Tue Jan 28 00:46:47 2020
@@ -23,6 +23,8 @@ import java.lang.reflect.Method;
 import java.net.URL;
 import java.net.URLClassLoader;
 
+import org.apache.felix.framework.util.SecureAction;
+
 public interface ClassPathExtenderFactory
 {
     interface ClassPathExtender
@@ -50,7 +52,7 @@ public interface ClassPathExtenderFactor
                 try
                 {
                     append = app.getClass().getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
-                    append.setAccessible(true);
+                    new SecureAction().setAccesssible(append);
                     break;
                 }
                 catch (Exception e)
@@ -74,7 +76,7 @@ public interface ClassPathExtenderFactor
             try
             {
                 addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
-                addURL.setAccessible(true);
+                new SecureAction().setAccesssible(addURL);
             }
             catch (Exception e)
             {

Modified: felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/util/SecureAction.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/util/SecureAction.java?rev=1873234&r1=1873233&r2=1873234&view=diff
==============================================================================
--- felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/util/SecureAction.java (original)
+++ felix/sandbox/pauls/connect/src/main/java/org/apache/felix/framework/util/SecureAction.java Tue Jan 28 00:46:47 2020
@@ -23,11 +23,15 @@ import java.lang.reflect.*;
 import java.lang.reflect.Proxy;
 import java.net.*;
 import java.security.*;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
 import java.util.jar.JarFile;
+import java.util.stream.Stream;
 import java.util.zip.ZipFile;
 
 import org.osgi.framework.Bundle;
@@ -56,6 +60,29 @@ import org.osgi.framework.wiring.BundleR
 **/
 public class SecureAction
 {
+    private static final byte[] accessor;
+
+    static {
+        byte[] result;
+
+        try (ByteArrayOutputStream output = new ByteArrayOutputStream();
+             InputStream input = SecureAction.class.getResourceAsStream("accessor.bytes"))
+        {
+
+            byte[] buffer = new byte[input.available() > 0 ? input.available() : 1024];
+            for (int i = input.read(buffer); i != -1; i = input.read(buffer))
+            {
+                output.write(buffer, 0, i);
+            }
+            result = output.toByteArray();
+        }
+        catch (Throwable t) {
+            t.printStackTrace();
+            result = new byte[0];
+        }
+        accessor = result;
+    }
+
     private static final ThreadLocal m_actions = new ThreadLocal()
     {
         public Object initialValue()
@@ -762,7 +789,7 @@ public class SecureAction
             Method addURL =
                 URLClassLoader.class.getDeclaredMethod("addURL",
                 new Class[] {URL.class});
-            addURL.setAccessible(true);
+            getAccessor(URLClassLoader.class).accept(new AccessibleObject[]{addURL});
             addURL.invoke(loader, new Object[]{extension});
         }
     }
@@ -851,7 +878,7 @@ public class SecureAction
         }
     }
 
-    public void setAccesssible(AccessibleObject ao)
+    public void setAccesssible(Executable ao)
     {
         if (System.getSecurityManager() != null)
         {
@@ -868,7 +895,7 @@ public class SecureAction
         }
         else
         {
-            ao.setAccessible(true);
+            getAccessor(ao.getDeclaringClass()).accept(new AccessibleObject[]{ao});
         }
     }
 
@@ -889,7 +916,8 @@ public class SecureAction
         }
         else
         {
-            method.setAccessible(true);
+            getAccessor(method.getDeclaringClass()).accept(new AccessibleObject[]{method});
+
             return method.invoke(target, params);
         }
     }
@@ -955,8 +983,7 @@ public class SecureAction
         else
         {
             Field field = targetClass.getDeclaredField(name);
-            field.setAccessible(true);
-
+            getAccessor(targetClass).accept(new AccessibleObject[]{field});
             return field.get(target);
         }
     }
@@ -985,9 +1012,49 @@ public class SecureAction
         }
     }
 
+    private static ConcurrentHashMap<Class, Object> m_accessorCache = new ConcurrentHashMap<>();
+
+    @SuppressWarnings("unchecked")
+    private static Consumer<AccessibleObject[]> getAccessor(Class clazz) {
+        String packageName = clazz.getPackage().getName();
+        if ("java.net".equals(packageName) || "jdk.internal.loader".equals(packageName))
+        {
+            return (Consumer<AccessibleObject[]>) m_accessorCache.computeIfAbsent(clazz, target ->
+            {
+                try
+                {
+                    // Use reflection on Unsafe to avoid having to compile against it
+                    Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); //$NON-NLS-1$
+                    Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe"); //$NON-NLS-1$
+                    // NOTE: deep reflection is allowed on sun.misc package for java 9.
+                    theUnsafe.setAccessible(true);
+                    Object unsafe = theUnsafe.get(null);
+                    // using defineAnonymousClass here because it seems more simple to get what we need
+                    Method defineAnonymousClass = unsafeClass.getMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class); //$NON-NLS-1$
+                    // The bytes stored in a resource to avoid real loading of it (see accessible.src for source).
+
+                    Class<Consumer<AccessibleObject[]>> result =
+                        (Class<Consumer<AccessibleObject[]>>)
+                            defineAnonymousClass.invoke(unsafe, packageName.equals("java.net") ? clazz : URL.class, accessor , null);
+                    return result.getConstructor().newInstance();
+
+                }
+                catch (Throwable t)
+                {
+                    t.printStackTrace();
+                    return (Consumer<AccessibleObject[]>) objects -> AccessibleObject.setAccessible(objects, true);
+                }
+            });
+        }
+        else {
+            return objects -> AccessibleObject.setAccessible(objects, true);
+        }
+    }
+
     private static Object _swapStaticFieldIfNotClass(Class targetClazz,
         Class targetType, Class condition, String lockName) throws Exception
     {
+
         Object lock = null;
         if (lockName != null)
         {
@@ -995,7 +1062,7 @@ public class SecureAction
             {
                 Field lockField =
                     targetClazz.getDeclaredField(lockName);
-                lockField.setAccessible(true);
+                getAccessor(targetClazz).accept(new AccessibleObject[]{lockField});
                 lock = lockField.get(null);
             }
             catch (NoSuchFieldException ex)
@@ -1010,14 +1077,14 @@ public class SecureAction
         {
             Field[] fields = targetClazz.getDeclaredFields();
 
+            getAccessor(targetClazz).accept(fields);
+
             Object result = null;
             for (int i = 0; (i < fields.length) && (result == null); i++)
             {
                 if (Modifier.isStatic(fields[i].getModifiers()) &&
                     (fields[i].getType() == targetType))
                 {
-                    fields[i].setAccessible(true);
-
                     result = fields[i].get(null);
 
                     if (result != null)
@@ -1040,7 +1107,6 @@ public class SecureAction
                         if (Modifier.isStatic(fields[i].getModifiers()) &&
                             (fields[i].getType() == Hashtable.class))
                         {
-                            fields[i].setAccessible(true);
                             Hashtable cache = (Hashtable) fields[i].get(null);
                             if (cache != null)
                             {
@@ -1081,13 +1147,13 @@ public class SecureAction
         synchronized (lock)
         {
             Field[] fields = targetClazz.getDeclaredFields();
+            getAccessor(targetClazz).accept(fields);
             // reset cache
             for (int i = 0; i < fields.length; i++)
             {
                 if (Modifier.isStatic(fields[i].getModifiers()) &&
                     ((fields[i].getType() == Hashtable.class) || (fields[i].getType() == HashMap.class)))
                 {
-                    fields[i].setAccessible(true);
                     if (fields[i].getType() == Hashtable.class)
                     {
                         Hashtable cache = (Hashtable) fields[i].get(null);
@@ -1708,7 +1774,7 @@ public class SecureAction
                     Method addURL =
                         URLClassLoader.class.getDeclaredMethod("addURL",
                         new Class[] {URL.class});
-                    addURL.setAccessible(true);
+                    getAccessor(URLClassLoader.class).accept(new AccessibleObject[]{addURL});
                     addURL.invoke(arg2, new Object[]{arg1});
                     return null;
                 case CREATE_TMPFILE_ACTION:
@@ -1740,7 +1806,7 @@ public class SecureAction
                     return ((Class) arg1).getDeclaredMethod((String) arg2, (Class[]) arg3);
                 case GET_FIELD_ACTION:
                     Field field = ((Class) arg1).getDeclaredField((String) arg2);
-                    field.setAccessible(true);
+                    getAccessor((Class) arg1).accept(new AccessibleObject[]{field});
                     return field.get(arg3);
                 case GET_FILE_INPUT_ACTION:
                     return new FileInputStream((File) arg1);
@@ -1765,7 +1831,7 @@ public class SecureAction
                 case INVOKE_DIRECTMETHOD_ACTION:
                     return ((Method) arg1).invoke(arg2, (Object[]) arg3);
                 case INVOKE_METHOD_ACTION:
-                    ((Method) arg1).setAccessible(true);
+                    getAccessor(((Method) arg1).getDeclaringClass()).accept(new AccessibleObject[]{(Method) arg1});
                     return ((Method) arg1).invoke(arg2, (Object[]) arg3);
                 case LIST_DIRECTORY_ACTION:
                     return ((File) arg1).listFiles();
@@ -1780,7 +1846,7 @@ public class SecureAction
                 case RENAME_FILE_ACTION:
                     return ((File) arg1).renameTo((File) arg2) ? Boolean.TRUE : Boolean.FALSE;
                 case SET_ACCESSIBLE_ACTION:
-                    ((AccessibleObject) arg1).setAccessible(true);
+                    getAccessor(((Executable) arg1).getDeclaringClass()).accept(new AccessibleObject[]{(Executable) arg1});
                     return null;
                 case START_ACTIVATOR_ACTION:
                     ((BundleActivator) arg1).start((BundleContext) arg2);

Added: felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.bytes
URL: http://svn.apache.org/viewvc/felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.bytes?rev=1873234&view=auto
==============================================================================
Binary file - no diff available.

Propchange: felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.bytes
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.src
URL: http://svn.apache.org/viewvc/felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.src?rev=1873234&view=auto
==============================================================================
--- felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.src (added)
+++ felix/sandbox/pauls/connect/src/main/resources/org/apache/felix/framework/util/accessor.src Tue Jan 28 00:46:47 2020
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package java.net;
+
+import java.lang.reflect.AccessibleObject;
+import java.util.function.Consumer;
+
+public class Accessor implements Consumer<AccessibleObject[]>
+{
+    @Override
+    public void accept(AccessibleObject[] accessibleObjectStream)
+    {
+        AccessibleObject.setAccessible(accessibleObjectStream, true);
+    }
+}