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) perhaps solvable
Date Sat, 02 Oct 2010 11:49:27 GMT
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 
     * <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> 
     * 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 
     * high, the virtual machine may instead use some platform-specific
     * maximum.  Likewise, the virtual machine is free to round the 
     * 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 
     * 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 
     * @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?



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