Merge "apf: Drop ARP reply if SPA is 0.0.0.0"

am: b11a084ebc

Change-Id: I5944f9c0afb62ced4595bf5c3c82e1b0e92a2199
This commit is contained in:
Aaron Huang
2018-12-13 19:09:58 -08:00
committed by android-build-merger
2 changed files with 61 additions and 39 deletions

View File

@@ -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

View File

@@ -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();
}