diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 485f2f5318f49..ce374266b6a24 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -367,8 +367,9 @@ public class ApfFilter { } // Note that this parses RA and may throw IllegalArgumentException (from - // Buffer.position(int) ) or IndexOutOfBoundsException (from ByteBuffer.get(int) ) if - // parsing encounters something non-compliant with specifications. + // 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) { mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length)); mPacket.clear(); @@ -418,6 +419,10 @@ public class ApfFilter { // compatibility. break; } + if (optionLength <= 0) { + throw new IllegalArgumentException(String.format( + "Invalid option length opt=%d len=%d", optionType, optionLength)); + } mPacket.position(mPacket.position() + optionLength); } // Mark non-lifetime bytes since last lifetime. diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java index fae82ca4e7a35..8ac238a9c415d 100644 --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java +++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java @@ -552,6 +552,10 @@ public class ApfTest extends AndroidTestCase { assertTrue(mGotApfProgram.block(TIMEOUT_MS)); return mLastApfProgram; } + + public void assertNoProgramUpdate() { + assertFalse(mGotApfProgram.block(TIMEOUT_MS)); + } } private static class TestApfFilter extends ApfFilter { @@ -863,6 +867,13 @@ public class ApfTest extends AndroidTestCase { verifyRaLifetime(ipManagerCallback, packet, lifetime); } + private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, + ByteBuffer packet) throws IOException, ErrnoException { + ipManagerCallback.resetApfProgramWait(); + apfFilter.pretendPacketReceived(packet.array()); + ipManagerCallback.assertNoProgramUpdate(); + } + @LargeTest public void testApfFilterRa() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); @@ -881,6 +892,16 @@ public class ApfTest extends AndroidTestCase { testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); + // Ensure zero-length options cause the packet to be silently skipped. + // Do this before we test other packets. http://b/29586253 + ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap( + new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); + basePacket.clear(); + zeroLengthOptionPacket.put(basePacket); + zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE); + zeroLengthOptionPacket.put((byte)0); + assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket); + // Generate several RAs with different options and lifetimes, and verify when // ApfFilter is shown these packets, it generates programs to filter them for the // appropriate lifetime.