Hi,
 
(didn't see this posted on the list, so here's a resend.  apologies for any duplicates).
 
As I noted earlier on this list, there was discussion in February on preventing users from accessing the classloader.  It turned out to be pretty easy to code this, inserting the check into Geir's implementation of the Uberspector.
 
I think this is a critical issue for Velocity web developers, as the ability for a template designer to create an arbitrary class and call an arbitrary method (1) breaks MVC in a big way and (2) is a major system integrity problem.  (File.delete() is only one minor example!)  The patch is straightforward, and can be turned off for developers who have a need to display class information in a template.
 
As progress on Velocity development seems to have halted in the last year or so, I offer this patch to the community, for others with a similar need.  If any committers are interested in sticking this in the code base, I'd be happy to do some more work on docs & tests.
 
From the javadocs.
 
    /**
     * Checks whether methods from a given object are
     * allowed to be called.  If property runtime.security.restrictexecute is true (default)
     * then no methods may be called on objects of these classes:
     * <UL>
     * <LI>java.lang.Class
     * <LI>java.lang.ClassLoader
     * <LI>java.lang.Compiler
     * <LI>java.lang.Package
     * <LI>java.lang.Process
     * <LI>java.lang.InheritableThreadLocal
     * <LI>java.lang.Runtime
     * <LI>java.lang.RuntimePermission
     * <LI>java.lang.SecurityManager
     * <LI>java.lang.System
     * <LI>java.lang.Thread
     * <LI>java.lang.ThreadGroup
     * <LI>java.lang.ThreadLocal
     * <LI>java.lang.reflect.*
     * </UL>
     *
     */
Will
 
_______________________________________
Forio Business Simulations
Will Glass-Husain
[EMAIL PROTECTED]
www.forio.com
cvs diff -u -b UberspectImpl.java

*****CVS exited normally with code 1*****

Index: UberspectImpl.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-velocity/src/java/org/apache/velocity/util/introspection/UberspectImpl.java,v
retrieving revision 1.2
diff -u -b -r1.2 UberspectImpl.java
--- UberspectImpl.java  21 Apr 2002 20:58:03 -0000      1.2
+++ UberspectImpl.java  28 May 2003 03:56:40 -0000
@@ -57,6 +57,8 @@
 import org.apache.velocity.util.ArrayIterator;
 import org.apache.velocity.util.EnumerationIterator;
 import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeInstance;
 import org.apache.velocity.runtime.RuntimeLogger;
 import org.apache.velocity.runtime.parser.node.AbstractExecutor;
 import org.apache.velocity.runtime.parser.node.PropertyExecutor;
@@ -75,6 +77,7 @@
  *  functionality of Velocity
  *
  * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a>
  * @version $Id: UberspectImpl.java,v 1.2 2002/04/21 20:58:03 geirm Exp $
  */
 public class UberspectImpl implements Uberspect, UberspectLoggable
@@ -116,7 +119,18 @@
     public Iterator getIterator(Object obj, Info i)
             throws Exception
     {
-        if (obj.getClass().isArray())
+
+        if (!checkObjectExecutePermission(obj))
+        {
+            rlog.warn ("Cannot retrieve iterator from object of class " + 
obj.getClass().getName() +
+                        " due to execute security restrictions. ["
+                          + i.getLine() + "," + i.getColumn() + "]"
+                          + " in template " + i.getTemplateName()
+                          + ".");
+            return null;
+
+        }
+        else if (obj.getClass().isArray())
         {
             return new ArrayIterator(obj);
         }
@@ -171,6 +185,17 @@
         if (obj == null)
             return null;
 
+        if (!checkObjectExecutePermission(obj))
+        {
+            rlog.warn ("Cannot retrieve method from object of class " + 
obj.getClass().getName() +
+                        " due to execute security restrictions. ["
+                          + i.getLine() + "," + i.getColumn() + "]"
+                          + " in template " + i.getTemplateName()
+                          + ".");
+            return null;
+
+        }
+
         Method m = introspector.getMethod(obj.getClass(), methodName, args);
 
         return (m != null) ? new VelMethodImpl(m) : null;
@@ -182,6 +207,18 @@
     public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
             throws Exception
     {
+
+        if (!checkObjectExecutePermission(obj))
+        {
+            rlog.warn ("Cannot retrieve get method from object of class " + 
obj.getClass().getName() +
+                        " due to execute security restrictions. ["
+                          + i.getLine() + "," + i.getColumn() + "]"
+                          + " in template " + i.getTemplateName()
+                          + ".");
+            return null;
+
+        }
+
         AbstractExecutor executor;
 
         Class claz = obj.getClass();
@@ -220,6 +257,17 @@
     public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, 
Info i)
             throws Exception
     {
+        if (!checkObjectExecutePermission(obj))
+        {
+            rlog.warn ("Cannot retrieve set method from object of class " + 
obj.getClass().getName() +
+                        " due to execute security restrictions. ["
+                          + i.getLine() + "," + i.getColumn() + "]"
+                          + " in template " + i.getTemplateName()
+                          + ".");
+            return null;
+
+        }
+
         Class claz = obj.getClass();
 
         VelPropertySet vs = null;
@@ -281,6 +329,84 @@
        }
 
        return (vm!=null) ?  new VelSetterImpl(vm) : null;
+    }
+
+    /**
+     * Checks whether methods from a given object are
+     * allowed to be called.  If property runtime.security.restrictexecute is true 
(default)
+     * then no methods may be called on objects of these classes:
+     * <UL>
+     * <LI>java.lang.Class
+     * <LI>java.lang.ClassLoader
+     * <LI>java.lang.Compiler
+     * <LI>java.lang.Package
+     * <LI>java.lang.Process
+     * <LI>java.lang.InheritableThreadLocal
+     * <LI>java.lang.Runtime
+     * <LI>java.lang.RuntimePermission
+     * <LI>java.lang.SecurityManager
+     * <LI>java.lang.System
+     * <LI>java.lang.Thread
+     * <LI>java.lang.ThreadGroup
+     * <LI>java.lang.ThreadLocal
+     * <LI>java.lang.reflect.*
+     * </UL>
+     *
+     * @param o object for which method is being called
+     * @param context current context
+     *
+     * @return true if method may be called on object
+     */
+    private boolean checkObjectExecutePermission(Object o)
+    {
+        // shortcut to check for most common classes - Number, Boolean and String
+        if (o instanceof java.lang.Number)
+            return true;
+
+        else if (o instanceof java.lang.Boolean)
+            return true;
+
+        else if (o instanceof java.lang.String)
+            return true;
+
+        // check for property
+        if ((rlog != null) && (rlog instanceof RuntimeInstance))
+            if (!((RuntimeInstance) rlog).getBoolean( 
RuntimeConstants.RESTRICT_EXECUTE, true ))
+                return true;
+
+        String classname = o.getClass().getName();
+
+        // remove array if applicable
+        if (classname.startsWith("[L") && classname.endsWith(";"))
+            classname = classname.substring(2,classname.length() - 1);
+
+        // non java.lang packages are all ok
+        if ( !classname.startsWith("java.lang.") )
+            return true;
+
+        // restrict all these packages
+        else if (
+                    // the two most dangerous
+                    classname.equals("java.lang.Class") ||
+                    classname.equals("java.lang.ClassLoader") ||
+
+                    // restrict these to be sure
+                    classname.startsWith("java.lang.reflect.") ||
+                    classname.equals("java.lang.Compiler") ||
+                    classname.equals("java.lang.InheritableThreadLocal") ||
+                    classname.equals("java.lang.Package") ||
+                    classname.equals("java.lang.Process") ||
+                    classname.equals("java.lang.Runtime") ||
+                    classname.equals("java.lang.RuntimePermission") ||
+                    classname.equals("java.lang.SecurityManager") ||
+                    classname.equals("java.lang.System") ||
+                    classname.equals("java.lang.Thread") ||
+                    classname.equals("java.lang.ThreadGroup") ||
+                    classname.equals("java.lang.ThreadLocal")
+                 )
+            return false;
+        else
+            return true;
     }
 
     /**
cvs diff -u -b RuntimeConstants.java

*****CVS exited normally with code 1*****

Index: RuntimeConstants.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-velocity/src/java/org/apache/velocity/runtime/RuntimeConstants.java,v
retrieving revision 1.33
diff -u -b -r1.33 RuntimeConstants.java
--- RuntimeConstants.java       29 Apr 2003 00:22:07 -0000      1.33
+++ RuntimeConstants.java       28 May 2003 03:53:08 -0000
@@ -368,6 +368,12 @@
 
     public static final String ENCODING_DEFAULT = "ISO-8859-1";
 
+    /**
+     *  key name for security checks on object classes
+     */
+    final static String RESTRICT_EXECUTE = "runtime.security.restrictexecute";
+
+
     /*
      * ----------------------------------------------------------------------
      * These constants are used internally by the Velocity runtime i.e.
@@ -405,4 +411,5 @@
      *  key name for uberspector
      */
     final static String UBERSPECT_CLASSNAME = "runtime.introspector.uberspect";
+
 }
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to