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

Commit b05c9234 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

DHCP: parsing robustness fixes.

1. Check the length of the fixed-length portions of the packet.
2. Catch BufferUnderflowException while parsing options.

Change-Id: If907f49f02a04a4a3360f46a3192e94ab099af0e
parent 06d7e530
Loading
Loading
Loading
Loading
+123 −105
Original line number Diff line number Diff line
@@ -41,6 +41,13 @@ abstract class DhcpPacket {
    public static final int ENCAP_L3 = 1;    // IP/UDP header included
    public static final int ENCAP_BOOTP = 2; // BOOTP contents only

    /**
     * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
     */
    public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
    public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
    public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;

    /**
     * IP layer definitions.
     */
@@ -399,13 +406,8 @@ abstract class DhcpPacket {
     * Converts a signed short value to an unsigned int value.  Needed
     * because Java does not have unsigned types.
     */
    private int intAbs(short v) {
        if (v < 0) {
            int r = v + 65536;
            return r;
        } else {
            return(v);
        }
    private static int intAbs(short v) {
        return v & 0xFFFF;
    }

    /**
@@ -655,6 +657,10 @@ abstract class DhcpPacket {

        // check to see if we need to parse L2, IP, and UDP encaps
        if (pktType == ENCAP_L2) {
            if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
                return null;
            }

            byte[] l2dst = new byte[6];
            byte[] l2src = new byte[6];

@@ -668,6 +674,10 @@ abstract class DhcpPacket {
        }

        if (pktType <= ENCAP_L3) {
            if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
                return null;
            }

            byte ipTypeAndLength = packet.get();
            int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
            if (ipVersion != 4) {
@@ -690,7 +700,9 @@ abstract class DhcpPacket {
            if (ipProto != IP_TYPE_UDP) // UDP
                return null;

            // Skip options.
            // Skip options. This cannot cause us to read beyond the end of the buffer because the
            // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
            // MIN_PACKET_LENGTH_L3.
            int optionWords = ((ipTypeAndLength & 0x0f) - 5);
            for (int i = 0; i < optionWords; i++) {
                packet.getInt();
@@ -706,6 +718,11 @@ abstract class DhcpPacket {
                return null;
        }

        // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
        if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
            return null;
        }

        byte type = packet.get();
        byte hwType = packet.get();
        byte addrLen = packet.get();
@@ -746,12 +763,13 @@ abstract class DhcpPacket {
        boolean notFinishedOptions = true;

        while ((packet.position() < packet.limit()) && notFinishedOptions) {
            try {
                byte optionType = packet.get();

                if (optionType == (byte) 0xFF) {
                    notFinishedOptions = false;
                } else {
                byte optionLen = packet.get();
                    int optionLen = packet.get() & 0xFF;
                    int expectedLen = 0;

                    switch(optionType) {
@@ -764,10 +782,7 @@ abstract class DhcpPacket {
                            expectedLen = 4;
                            break;
                        case DHCP_DNS_SERVER:
                        expectedLen = 0;

                        for (expectedLen = 0; expectedLen < optionLen;
                             expectedLen += 4) {
                            for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
                                dnsServers.add(readIpAddress(packet));
                            }
                            break;
@@ -845,6 +860,9 @@ abstract class DhcpPacket {
                        return null;
                    }
                }
            } catch (BufferUnderflowException e) {
                return null;
            }
        }

        DhcpPacket newPacket;