Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8acea76a authored by Hugo Benichi's avatar Hugo Benichi
Browse files

Add fuzzing tests to ApfFilter RA processing

Test: added new unit tests
Change-Id: Ie352eb1514b762e032b9140d633abc06180d0ade
parent 9cf75061
Loading
Loading
Loading
Loading
+22 −10
Original line number Diff line number Diff line
@@ -289,8 +289,15 @@ public class ApfFilter {
        return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS;
    }

    public static class InvalidRaException extends Exception {
        public InvalidRaException(String m) {
            super(m);
        }
    }

    // A class to hold information about an RA.
    private class Ra {
    @VisibleForTesting
    class Ra {
        // From RFC4861:
        private static final int ICMP6_RA_HEADER_LEN = 16;
        private static final int ICMP6_RA_CHECKSUM_OFFSET =
@@ -436,7 +443,11 @@ public class ApfFilter {
        // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
        // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
        // specifications.
        Ra(byte[] packet, int length) {
        Ra(byte[] packet, int length) throws InvalidRaException {
            if (length < ICMP6_RA_OPTION_OFFSET) {
                throw new InvalidRaException("Not an ICMP6 router advertisement");
            }

            mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
            mLastSeen = curTime();

@@ -445,7 +456,7 @@ public class ApfFilter {
            if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
                    uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 ||
                    uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) {
                throw new IllegalArgumentException("Not an ICMP6 router advertisement");
                throw new InvalidRaException("Not an ICMP6 router advertisement");
            }


@@ -511,7 +522,7 @@ public class ApfFilter {
                        break;
                }
                if (optionLength <= 0) {
                    throw new IllegalArgumentException(String.format(
                    throw new InvalidRaException(String.format(
                        "Invalid option length opt=%d len=%d", optionType, optionLength));
                }
                mPacket.position(position + optionLength);
@@ -925,8 +936,8 @@ public class ApfFilter {
            // Execution will reach the end of the program if no filters match, which will pass the
            // packet to the AP.
            program = gen.generate();
        } catch (IllegalInstructionException e) {
            Log.e(TAG, "Program failed to generate: ", e);
        } catch (IllegalInstructionException|IllegalStateException e) {
            Log.e(TAG, "Failed to generate APF program.", e);
            return;
        }
        mLastTimeInstalledProgram = curTime();
@@ -972,7 +983,8 @@ public class ApfFilter {
     * if the current APF program should be updated.
     * @return a ProcessRaResult enum describing what action was performed.
     */
    private synchronized ProcessRaResult processRa(byte[] packet, int length) {
    @VisibleForTesting
    synchronized ProcessRaResult processRa(byte[] packet, int length) {
        if (VDBG) hexDump("Read packet = ", packet, length);

        // Have we seen this RA before?
@@ -1011,7 +1023,7 @@ public class ApfFilter {
        try {
            ra = new Ra(packet, length);
        } catch (Exception e) {
            Log.e(TAG, "Error parsing RA: " + e);
            Log.e(TAG, "Error parsing RA", e);
            return ProcessRaResult.PARSE_ERROR;
        }
        // Ignore 0 lifetime RAs.
+38 −4
Original line number Diff line number Diff line
@@ -16,10 +16,6 @@

package android.net.apf;

import static android.system.OsConstants.*;

import com.android.frameworks.servicestests.R;

import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
@@ -37,6 +33,10 @@ import android.system.ErrnoException;
import android.system.Os;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import static android.system.OsConstants.*;

import com.android.frameworks.servicestests.R;
import com.android.internal.util.HexDump;

import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -54,6 +54,7 @@ import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Random;

import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -1146,6 +1147,39 @@ public class ApfTest extends AndroidTestCase {
        buffer.position(original);
    }

    public void testRaParsing() throws Exception {
        final int maxRandomPacketSize = 512;
        final Random r = new Random();
        MockIpManagerCallback cb = new MockIpManagerCallback();
        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
        for (int i = 0; i < 1000; i++) {
            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
            r.nextBytes(packet);
            try {
                apfFilter.new Ra(packet, packet.length);
            } catch (ApfFilter.InvalidRaException e) {
            } catch (Exception e) {
                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
            }
        }
    }

    public void testRaProcessing() throws Exception {
        final int maxRandomPacketSize = 512;
        final Random r = new Random();
        MockIpManagerCallback cb = new MockIpManagerCallback();
        TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
        for (int i = 0; i < 1000; i++) {
            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
            r.nextBytes(packet);
            try {
                apfFilter.processRa(packet, packet.length);
            } catch (Exception e) {
                throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
            }
        }
    }

    /**
     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
     * filter was installed {@code filter_age} seconds ago.