river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: Towards Internet Jini Services (dos attacks) Smart Proxy Isolation
Date Sun, 03 Oct 2010 09:00:32 GMT
I've got some thoughts about how to isolate a smart proxy, please tell 
me yours:

   1. Implement an InvocationHandler for java.lang.reflect.Proxy,
      perhaps called SmartProxyIsolate
   2. SmartProxyIsolate has it's own Thread with a custom
      UncaughtExceptionHandler, it deals with any Errors the thread
      might have, such as StackOverflowError.  In the event of a
      StackOverflowError, the smart proxy reference and thread reference
      and method call queue, would be set to null immediately, leaving
      the SmartProxyIsolate in a known state, all method in the isolate
      would then return an IOException.
   3. All method invocations are passed to the smart proxy contained by
      the SmartProxyIsolate, only the SmartProxyIsolate holds a strong
      reference to the smart proxy.  The SmartProxyIsolate would expect
      a MarshalledInstance of the proxy in it's constructor.
   4. All  methods on the smart proxy are only called from the
      SmartProxyIsolate thread, trapping and handling any errors.
   5. A java.lang.reflect.Proxy ( created with the SmartProxyIsolate
      InvocationHandler ) is referenced by the client.
   6. SmartProxyIsolate needs a method to return the ProtectionDomain,
      to enable dynamic grants be granted to the smart proxy's PD by the
      DynamicPolicy, rather than the PD of the SmartProxyIsolate.
   7. To be completely sure, the Service API method returns shouldn't be
      subclasses, unless the smart proxy is trusted, we could create a
      new Permission class for this purpose. (lest a subclass be
      returned containing a reference to the smart proxy).

This structure could be used to isolate any proxy that requires a 
downloaded codebase, we would also need to place a limit on the size of 
the downloaded codebase, to prevent DOS that way too (I'll explain later).

We might also provide a method that allows the calling class to set an 
event handler, all method calls would return null immediately, and an 
Event later generated containing the result of the method call.  This 
means the client thread isn't delayed in a wait state, but the default 
behaviour would be for client threads to wait.

Note that this requires JAVA 5, since each thread must have it's own 
UncaughtExceptionHandler that knows the specific SmartProxyIsolate.

The smart proxy would be isolated in it's own thread, any objects it 
creates will be in a thread local stack, it would unlikely be able to 
cause an OutOfMemoryError, unless the JVM is configured incorrectly.   
By giving the thread a lower priority, it couldn't freeze a single core 
client either.



Peter Firmstone wrote:
> I'm wondering, what can be done about DOS recursion with threads and 
> memory?
> A Thread has it's own private memory stack, the downloaded proxy will 
> only have thread local objects, until they're passed to another thread.
> What if we use a new thread to unmarshall and interact with the proxy?
> A deliberate infinitely recursive loop in a Thread will throw a 
> StackOverflowError, it may also cause problems with the available 
> memory for all threads, so it needs to be tuned correctly with JVM 
> memory options.
> >From java.lang.Thread (the discussion is interesting, not the 
> stackSize constructor), also note the UncaughtExceptionHandler method 
> that follows.
>   /**
>     * Allocates a new <code>Thread</code> object so that it has
>     * <code>target</code> as its run object, has the specified
>     * <code>name</code> as its name, belongs to the thread group 
> referred to
>     * by <code>group</code>, and has the specified <i>stack size</i>.
>     *
>     * <p>This constructor is identical to {@link
>     * #Thread(ThreadGroup,Runnable,String)} with the exception of the 
> fact
>     * that it allows the thread stack size to be specified.  The stack 
> size
>     * is the approximate number of bytes of address space that the 
> virtual
>     * machine is to allocate for this thread's stack.  <b>The effect 
> of the
>     * <tt>stackSize</tt> parameter, if any, is highly platform 
> dependent.</b>
>     *
>     * <p>On some platforms, specifying a higher value for the
>     * <tt>stackSize</tt> parameter may allow a thread to achieve greater
>     * recursion depth before throwing a {@link StackOverflowError}.
>     * Similarly, specifying a lower value may allow a greater number of
>     * threads to exist concurrently without throwing an {@link
>     * OutOfMemoryError} (or other internal error).  The details of
>     * the relationship between the value of the <tt>stackSize</tt> 
> parameter
>     * and the maximum recursion depth and concurrency level are
>     * platform-dependent.  <b>On some platforms, the value of the
>     * <tt>stackSize</tt> parameter may have no effect whatsoever.</b>
>     *
>     * <p>The virtual machine is free to treat the <tt>stackSize</tt>
>     * parameter as a suggestion.  If the specified value is 
> unreasonably low
>     * for the platform, the virtual machine may instead use some
>     * platform-specific minimum value; if the specified value is 
> unreasonably
>     * high, the virtual machine may instead use some platform-specific
>     * maximum.  Likewise, the virtual machine is free to round the 
> specified
>     * value up or down as it sees fit (or to ignore it completely).
>     *
>     * <p>Specifying a value of zero for the <tt>stackSize</tt> 
> parameter will
>     * cause this constructor to behave exactly like the
>     * <tt>Thread(ThreadGroup, Runnable, String)</tt> constructor.
>     *
>     * <p><i>Due to the platform-dependent nature of the behavior of this
>     * constructor, extreme care should be exercised in its use.
>     * The thread stack size necessary to perform a given computation will
>     * likely vary from one JRE implementation to another.  In light of 
> this
>     * variation, careful tuning of the stack size parameter may be 
> required,
>     * and the tuning may need to be repeated for each JRE 
> implementation on
>     * which an application is to run.</i>
>     *
>     * <p>Implementation note: Java platform implementers are 
> encouraged to
>     * document their implementation's behavior with respect to the
>     * <tt>stackSize parameter</tt>.
>     *
>     * @param      group    the thread group.
>     * @param      target   the object whose <code>run</code> method is 
> called.
>     * @param      name     the name of the new thread.
>     * @param      stackSize the desired stack size for the new thread, or
>     *             zero to indicate that this parameter is to be ignored.
>     * @exception  SecurityException  if the current thread cannot 
> create a
>     *               thread in the specified thread group.
>     * @since 1.4
>     */
>    public Thread(ThreadGroup group, Runnable target, String name,
>                  long stackSize)
>   /**
>     * Set the handler invoked when this thread abruptly terminates
>     * due to an uncaught exception.
>     * <p>A thread can take full control of how it responds to uncaught
>     * exceptions by having its uncaught exception handler explicitly set.
>     * If no such handler is set then the thread's <tt>ThreadGroup</tt>
>     * object acts as its handler.
>     * @param eh the object to use as this thread's uncaught exception
>     * handler. If <tt>null</tt> then this thread has no explicit handler.
>     * @throws  SecurityException  if the current thread is not allowed to
>     *          modify this thread.
>     * @see #setDefaultUncaughtExceptionHandler
>     * @see ThreadGroup#uncaughtException
>     * @since 1.5
>     */
>    public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
> If we catch the StackOverflowError, null out all references to the 
> proxy and terminate the thread, we free the memory, the trick is not 
> creating any new objects during recovery and making sure that the 
> Thread running out of local memory doesn't threaten the memory the 
> other threads have.
> We can also set the proxy's unmarshalling thread with a low priority 
> on Single processor machines, so other higher priority threads get 
> some cpu time slices.
> Once proxy unmarshalling is complete, it's still not safe to return 
> the proxy to the calling thread, the trouble is, the proxy's methods 
> could still contain infinitely recursive loops.
> Any ideas for how to best  invoke methods on the proxy,  via the proxy 
> thread, originating from the application thread?
> Cheers,
> Peter.
> Peter Firmstone wrote:
>> Perhaps Oracle might have the money to complete the MVM Isolates API 
>> for Java SE and EE.
>> Isolates present the opportunity to restrict resources, which could 
>> fix the issues with excess resource consumption as DOS.
>> Until then the remaining ways to combat the memory consumption problem.
>> Reboot, report and be careful who you trust.
>> N.B. They can't do this with a reflective proxy, so don't grant their 
>> Principal DownloadPermission if you don't trust them.
>> Cheers,
>> Peter.
>> Christopher Dolan wrote:
>>> Just for the record, Peter is right. I just looked at the JDK 1.5 
>>> source
>>> code for java.lang.Thread. The security permission you need to create a
>>> thread or a thread group is
>>> java.lang.RuntimePermission("modifyThreadGroup"). I hadn't known about
>>> that. The "modifyThread" permission does not affect one's ability to
>>> create and start threads.
>>> So, that would argue for a tightened security context during
>>> deserialization.  That would at least revert us to Peter's original
>>> statement that only one core could be smacked with 100% load.  The RAM
>>> usage would not be controllable, though.
>>> Chris
>>> -----Original Message-----
>>> From: Peter Firmstone [mailto:jini@zeus.net.au] Sent: Thursday, 
>>> September 30, 2010 2:41 AM
>>> To: river-dev@incubator.apache.org
>>> Subject: Re: Towards Internet Jini Services (dos attacks)
>>> Yes, it certainly can.
>>> Regards,
>>> Peter.
>>> Christopher Dolan wrote:
>>>> private void readObject(ObjectInputStream in) {
>>>>     new Runnable() {
>>>>         public void run() {
>>>>             while (true)
>>>>                 new Thread(this).start();
>>>>         }
>>>>     }.run();
>>>> }
>>>> At 1MB of stack RAM per thread, this will thrash most machines in no
>>>> time.  Can a SecurityManager block thread creation?
>>>> Chris
>>>> -----Original Message-----
>>>> From: Peter Firmstone [mailto:jini@zeus.net.au] Sent: Wednesday, 
>>>> September 29, 2010 3:58 PM
>>>> To: river-dev@incubator.apache.org
>>>> Subject: Re: Towards Internet Jini Services (dos attacks)
>>>> Zoltan Juhasz wrote:
>>>>> Sim,
>>>>> I think the important danger in Jini is the use of objects. In simple
>>>>> messaging communication (especially if non-binary), you don't have to
>>>> worry
>>>>> about objects. In Jini, any method can take and object as a parameter
>>>> that
>>>>> results in serialisation and unmarshalling at the receiver end. When
>>>> an
>>>>> object has something nasty executing during within the readObject()
>>>> method,
>>>>> it's too late to do anything.
>>>> This was a big problem in the days of single core, not as bad now. 
>>>> Perhaps we need a software watchdog?  Or an easy way to kill and 
>>>> quarantine a misbehaving service?  Or an unmarshalling executor thread
>>>> pool, which passes the object after it has been deserialized.

View raw message