diff options
| author | 2018-12-14 03:00:21 +0000 | |
|---|---|---|
| committer | 2018-12-14 03:00:21 +0000 | |
| commit | b11a084ebc8896cb79e8521b3d3d03349608c3fe (patch) | |
| tree | ca190a7a0885a92a2407d561666fb7ba9891c573 | |
| parent | d2a163ad3807c96c18cd986f2c57d8d83a57dd20 (diff) | |
| parent | 04ed6a35921303aa194358f6c8b84b3f556ccc92 (diff) | |
Merge "apf: Drop ARP reply if SPA is 0.0.0.0"
| -rw-r--r-- | services/net/java/android/net/apf/ApfFilter.java | 72 | ||||
| -rw-r--r-- | tests/net/java/android/net/apf/ApfTest.java | 28 |
2 files changed, 61 insertions, 39 deletions
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index b9cc372c5138..f0379059a5f7 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -139,7 +139,8 @@ public class ApfFilter { DROPPED_IPV6_MULTICAST_PING, DROPPED_IPV6_NON_ICMP_MULTICAST, DROPPED_802_3_FRAME, - DROPPED_ETHERTYPE_BLACKLISTED; + DROPPED_ETHERTYPE_BLACKLISTED, + DROPPED_ARP_REPLY_SPA_NO_HOST; // Returns the negative byte offset from the end of the APF data segment for // a given counter. @@ -156,7 +157,7 @@ public class ApfFilter { /** * When APFv4 is supported, loads R1 with the offset of the specified counter. */ - private void maybeSetCounter(ApfGenerator gen, Counter c) { + private void maybeSetupCounter(ApfGenerator gen, Counter c) { if (mApfCapabilities.hasDataAccess()) { gen.addLoadImmediate(Register.R1, c.offset()); } @@ -288,16 +289,18 @@ public class ApfFilter { private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28; private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; - private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6; - private static final short ARP_OPCODE_REQUEST = 1; - private static final short ARP_OPCODE_REPLY = 2; private static final byte[] ARP_IPV4_HEADER = { 0, 1, // Hardware type: Ethernet (1) 8, 0, // Protocol type: IP (0x0800) 6, // Hardware size: 6 4, // Protocol size: 4 }; - private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; + private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6; + // Opcode: ARP request (0x0001), ARP reply (0x0002) + private static final short ARP_OPCODE_REQUEST = 1; + private static final short ARP_OPCODE_REPLY = 2; + private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14; + private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24; // Do not log ApfProgramEvents whose actual lifetimes was less than this. private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2; // Limit on the Black List size to cap on program usage for this @@ -816,7 +819,7 @@ public class ApfFilter { gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel); } } - maybeSetCounter(gen, Counter.DROPPED_RA); + maybeSetupCounter(gen, Counter.DROPPED_RA); gen.addJump(mCountAndDropLabel); gen.defineLabel(nextFilterLabel); return filterLifetime; @@ -883,6 +886,8 @@ public class ApfFilter { // pass // if not ARP IPv4 reply or request // pass + // if ARP reply source ip is 0.0.0.0 + // drop // if unicast ARP reply // pass // if interface has no IPv4 address @@ -897,18 +902,23 @@ public class ApfFilter { // Pass if not ARP IPv4. gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET); - maybeSetCounter(gen, Counter.PASSED_ARP_NON_IPV4); + maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4); gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel); // Pass if unknown ARP opcode. gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET); gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check - maybeSetCounter(gen, Counter.PASSED_ARP_UNKNOWN); + maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN); gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel); + // Drop if ARP reply source IP is 0.0.0.0 + gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET); + maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST); + gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel); + // Pass if unicast reply. gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); - maybeSetCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY); + maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY); gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel); // Either a unicast request, a unicast reply, or a broadcast reply. @@ -916,17 +926,17 @@ public class ApfFilter { if (mIPv4Address == null) { // When there is no IPv4 address, drop GARP replies (b/29404209). gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); - maybeSetCounter(gen, Counter.DROPPED_GARP_REPLY); + maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY); gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel); } else { // When there is an IPv4 address, drop unicast/broadcast requests // and broadcast replies with a different target IPv4 address. gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); - maybeSetCounter(gen, Counter.DROPPED_ARP_OTHER_HOST); + maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST); gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel); } - maybeSetCounter(gen, Counter.PASSED_ARP); + maybeSetupCounter(gen, Counter.PASSED_ARP); gen.addJump(mCountAndPassLabel); } @@ -970,7 +980,7 @@ public class ApfFilter { // NOTE: Relies on R1 containing IPv4 header offset. gen.addAddR1(); gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter); - maybeSetCounter(gen, Counter.PASSED_DHCP); + maybeSetupCounter(gen, Counter.PASSED_DHCP); gen.addJump(mCountAndPassLabel); // Drop all multicasts/broadcasts. @@ -979,30 +989,30 @@ public class ApfFilter { // If IPv4 destination address is in multicast range, drop. gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); gen.addAnd(0xf0); - maybeSetCounter(gen, Counter.DROPPED_IPV4_MULTICAST); + maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST); gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel); // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). - maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR); + maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR); gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET); gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel); if (mIPv4Address != null && mIPv4PrefixLength < 31) { - maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET); + maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET); int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel); } // If L2 broadcast packet, drop. // TODO: can we invert this condition to fall through to the common pass case below? - maybeSetCounter(gen, Counter.PASSED_IPV4_UNICAST); + maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST); gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel); - maybeSetCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST); + maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST); gen.addJump(mCountAndDropLabel); } // Otherwise, pass - maybeSetCounter(gen, Counter.PASSED_IPV4); + maybeSetupCounter(gen, Counter.PASSED_IPV4); gen.addJump(mCountAndPassLabel); } @@ -1050,16 +1060,16 @@ public class ApfFilter { // Drop all other packets sent to ff00::/8 (multicast prefix). gen.defineLabel(dropAllIPv6MulticastsLabel); - maybeSetCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST); + maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST); gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET); gen.addJumpIfR0Equals(0xff, mCountAndDropLabel); // Not multicast. Pass. - maybeSetCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP); + maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP); gen.addJump(mCountAndPassLabel); gen.defineLabel(skipIPv6MulticastFilterLabel); } else { // If not ICMPv6, pass. - maybeSetCounter(gen, Counter.PASSED_IPV6_NON_ICMP); + maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP); gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel); } @@ -1069,7 +1079,7 @@ public class ApfFilter { String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA"; gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET); // Drop all router solicitations (b/32833400) - maybeSetCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION); + maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION); gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel); // If not neighbor announcements, skip filter. gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel); @@ -1078,7 +1088,7 @@ public class ApfFilter { gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET); gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS, skipUnsolicitedMulticastNALabel); - maybeSetCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA); + maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA); gen.addJump(mCountAndDropLabel); gen.defineLabel(skipUnsolicitedMulticastNALabel); } @@ -1108,7 +1118,7 @@ public class ApfFilter { if (mApfCapabilities.hasDataAccess()) { // Increment TOTAL_PACKETS - maybeSetCounter(gen, Counter.TOTAL_PACKETS); + maybeSetupCounter(gen, Counter.TOTAL_PACKETS); gen.addLoadData(Register.R0, 0); // load counter gen.addAdd(1); gen.addStoreData(Register.R0, 0); // write-back counter @@ -1134,12 +1144,12 @@ public class ApfFilter { if (mDrop802_3Frames) { // drop 802.3 frames (ethtype < 0x0600) - maybeSetCounter(gen, Counter.DROPPED_802_3_FRAME); + maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME); gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel); } // Handle ether-type black list - maybeSetCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED); + maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED); for (int p : mEthTypeBlackList) { gen.addJumpIfR0Equals(p, mCountAndDropLabel); } @@ -1168,9 +1178,9 @@ public class ApfFilter { // Drop non-IP non-ARP broadcasts, pass the rest gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); - maybeSetCounter(gen, Counter.PASSED_NON_IP_UNICAST); + maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST); gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel); - maybeSetCounter(gen, Counter.DROPPED_ETH_BROADCAST); + maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST); gen.addJump(mCountAndDropLabel); // Add IPv6 filters: @@ -1193,7 +1203,7 @@ public class ApfFilter { // Execution will reach the bottom of the program if none of the filters match, // which will pass the packet to the application processor. - maybeSetCounter(gen, Counter.PASSED_IPV6_ICMP); + maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP); // Append the count & pass trampoline, which increments the counter at the data address // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 436dd859beca..151b5594216a 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -1048,12 +1048,17 @@ public class ApfTest { 4, // Protocol size: 4 0, 2 // Opcode: reply (2) }; - private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; + private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14; + private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24; private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1}; private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19 private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1}; private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2}; + private static final byte[] IPV4_SOURCE_ADDR = {10, 0, 0, 3}; + private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1}; + private static final byte[] BUG_PROBE_SOURCE_ADDR1 = {0, 0, 1, 2}; + private static final byte[] BUG_PROBE_SOURCE_ADDR2 = {3, 4, 0, 0}; private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0}; // Helper to initialize a default apfFilter. @@ -1399,10 +1404,16 @@ public class ApfTest { assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR)); assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR)); + // Verify ARP reply packets from different source ip + assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR)); + assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR)); + assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR)); + assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR)); + // Verify unicast ARP reply packet is always accepted. - assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR)); - assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR)); - assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR)); + assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR)); + assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR)); + assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR)); // Verify GARP reply packets are always filtered assertDrop(program, garpReply()); @@ -1431,19 +1442,20 @@ public class ApfTest { apfFilter.shutdown(); } - private static byte[] arpRequestBroadcast(byte[] tip) { + private static byte[] arpReply(byte[] sip, byte[] tip) { ByteBuffer packet = ByteBuffer.wrap(new byte[100]); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); - put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); + put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip); put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); return packet.array(); } - private static byte[] arpReplyUnicast(byte[] tip) { + private static byte[] arpRequestBroadcast(byte[] tip) { ByteBuffer packet = ByteBuffer.wrap(new byte[100]); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); - put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); + put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); + put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER); put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); return packet.array(); } |