river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject The internet - Unicast Discovery Denial of Service Attack
Date Sat, 05 Feb 2011 10:35:42 GMT
The following class reads in the Unicast V2 discovery response from a 
lookup service, the intent of this class is to isolate this part of 
discovery on its own thread, to guard against an attackers carefully 
crafted input stream, when attempting to discover a lookup service on 
the internet.

The process of unmarshalling is isolated to a single thread, an 
Exception handler captures any Errors and terminates the thread.

This protects the application thread from Errors, like StackOverflowError.


/*
 * 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 org.apache.river.impl.security.dos;

import com.sun.jini.discovery.DiscoveryProtocolException;
import com.sun.jini.discovery.UnicastResponse;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.Collection;
import java.util.concurrent.Callable;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.io.MarshalledInstance;

class DiscoveryV2ReadUncastResponseTask implements 
Callable<UnicastResponse> {

    private final InputStream in;
    private final ClassLoader defaultLoader;
    private final boolean verifyCodebaseIntegrity;
    private final ClassLoader verifierLoader;
    private final Collection context;

    DiscoveryV2ReadUncastResponseTask(InputStream in,
            ClassLoader defaultLoader,
            boolean verifyCodebaseIntegrity,
            ClassLoader verifierLoader,
            Collection context)
    {
        this.in = in;
        this.defaultLoader = defaultLoader;
        this.verifyCodebaseIntegrity = verifyCodebaseIntegrity;
        this.verifierLoader = verifierLoader;
        this.context = context;
    }

    public UnicastResponse call() throws Exception {
        try {
            DataInput din = new DataInputStream(in);
            String host = din.readUTF();

            // read LUS port
            int port = din.readUnsignedShort();
            String[] groups = new String[din.readInt()];
            for (int i = 0; i < groups.length; i++) {
                groups[i] = din.readUTF();
            }
            MarshalledInstance mi = (MarshalledInstance) new 
ObjectInputStream(in).readObject();
            ServiceRegistrar reg =
                    (ServiceRegistrar) mi.get(defaultLoader,
                    verifyCodebaseIntegrity, verifierLoader, context);
            return new UnicastResponse(host, port, groups, reg);
        } catch (RuntimeException e) {
            throw new DiscoveryProtocolException(null, e);
        }
    }
}


/*
 * 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 org.apache.river.impl.security.dos;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Performs Callable tasks in an isolated thread, which is terminated
 * if any Errors are experienced.  This may take some time to terminate 
the thread
 * as it is not forcibly stopped.  The thread priority is minimal and a 
daemon
 * thread so it would take a number of unterminated threads to cause 
problems.
 *
 * The caller can give up on the execution of the task by setting a timeout.
 *
 * @param T
 * @author peter
 */
public class Isolate<T> {
    private volatile ExecutorService isolateExecutor;
    private volatile Throwable thrown;
   
    public Isolate()
    {
        thrown = null;
    isolateExecutor = Executors.newSingleThreadExecutor(new Factory(this));
    }
   
    /**
     * Process Callable tasks in isolation.
     * If an ExecutionException has been thrown, the task should be 
abandoned.
     * If an IsolationException has been thrown, an Error has occurred with
     * the Isolate and a new object should be created.
     *
     * @param task
     * @param timeout
     * @param timeUnit
     * @return
     * @throws org.apache.river.impl.security.dos.Isolate.IsolationException
     * @throws java.util.concurrent.ExecutionException
     */
    public T process(Callable<T> task, long timeout, TimeUnit timeUnit) 
throws
            IsolationException, ExecutionException, InterruptedException,
            TimeoutException {
        if ( thrown != null){
            throw new IsolationException ("Isolate has" +
                  "experienced an error during processing and " +
                  "cannot perform further " +
                  "tasks", thrown);
        }
        return isolateExecutor.submit(task).get(timeout, timeUnit);
    }
   
    private void terminate(Throwable e){
    thrown = e;
    isolateExecutor.shutdownNow();   
    }
   
    private static class Factory implements ThreadFactory{
    private static final ThreadGroup tg = new ThreadGroup("Isolated");
    {
        tg.setDaemon(true);
        tg.setMaxPriority(4);
    }
    private final Isolate isolate;
    Factory(Isolate uri){
        isolate = uri;
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(tg, r);
        t.setUncaughtExceptionHandler(new ExceptionHandler(isolate));
        return t;
    }   
    }
   
    private static class ExceptionHandler implements 
Thread.UncaughtExceptionHandler{
    private final Isolate isolate;
   
    ExceptionHandler(Isolate uri){
        isolate = uri;
    }

    public void uncaughtException(Thread t, Throwable e) {
        // For all other Exceptions we let the ExecutorService handle it.
        if ( e instanceof Error){
        // Do we want to take different actions based on the error?
        isolate.terminate(e);
        }
    }
   
    }
   
    public static class IsolationException extends Exception {
        private static final long serialVersionUID = 1L;

        public IsolationException() {
            super();
        }

        public IsolationException(String message) {
            super(message);
        }

        public IsolationException(String message, Throwable cause) {
            super(message, cause);
        }

        public IsolationException(Throwable cause) {
            super(cause);
        }
    }
}






Mime
View raw message