1*2f2c4c7aSAndroid Build Coastguard Worker#!/usr/bin/python3 2*2f2c4c7aSAndroid Build Coastguard Worker# 3*2f2c4c7aSAndroid Build Coastguard Worker# Copyright 2016 The Android Open Source Project 4*2f2c4c7aSAndroid Build Coastguard Worker# 5*2f2c4c7aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*2f2c4c7aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*2f2c4c7aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*2f2c4c7aSAndroid Build Coastguard Worker# 9*2f2c4c7aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*2f2c4c7aSAndroid Build Coastguard Worker# 11*2f2c4c7aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*2f2c4c7aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*2f2c4c7aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*2f2c4c7aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*2f2c4c7aSAndroid Build Coastguard Worker# limitations under the License. 16*2f2c4c7aSAndroid Build Coastguard Worker 17*2f2c4c7aSAndroid Build Coastguard Workerimport ctypes 18*2f2c4c7aSAndroid Build Coastguard Workerimport errno 19*2f2c4c7aSAndroid Build Coastguard Workerimport os 20*2f2c4c7aSAndroid Build Coastguard Workerimport socket 21*2f2c4c7aSAndroid Build Coastguard Workerimport unittest 22*2f2c4c7aSAndroid Build Coastguard Worker 23*2f2c4c7aSAndroid Build Coastguard Workerimport bpf 24*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_ADD 25*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_AND 26*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_CGROUP_INET_EGRESS 27*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_CGROUP_INET_INGRESS 28*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_CGROUP_INET_SOCK_CREATE 29*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_DW 30*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_F_RDONLY 31*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_F_WRONLY 32*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_get_current_uid_gid 33*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_get_socket_cookie 34*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_get_socket_uid 35*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_ktime_get_boot_ns 36*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_ktime_get_ns 37*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_map_lookup_elem 38*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_map_update_elem 39*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_FUNC_skb_change_head 40*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_JNE 41*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_MAP_TYPE_ARRAY 42*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_MAP_TYPE_HASH 43*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_PROG_TYPE_CGROUP_SKB 44*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_PROG_TYPE_CGROUP_SOCK 45*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_PROG_TYPE_SCHED_CLS 46*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_PROG_TYPE_SOCKET_FILTER 47*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_0 48*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_1 49*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_10 50*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_2 51*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_3 52*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_4 53*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_6 54*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_REG_7 55*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_STX 56*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_W 57*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BPF_XADD 58*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfAlu64Imm 59*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfExitInsn 60*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfFuncCall 61*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfJumpImm 62*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfLdxMem 63*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfLoadMapFd 64*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfMov64Imm 65*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfMov64Reg 66*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfProgAttach 67*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfProgAttachSocket 68*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfProgDetach 69*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfProgGetFdById 70*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfProgLoad 71*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfProgQuery 72*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfRawInsn 73*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfStMem 74*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import BpfStxMem 75*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import CreateMap 76*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import DeleteMap 77*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import GetFirstKey 78*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import GetNextKey 79*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import LookupMap 80*2f2c4c7aSAndroid Build Coastguard Workerfrom bpf import UpdateMap 81*2f2c4c7aSAndroid Build Coastguard Workerimport csocket 82*2f2c4c7aSAndroid Build Coastguard Workerimport net_test 83*2f2c4c7aSAndroid Build Coastguard Workerimport sock_diag 84*2f2c4c7aSAndroid Build Coastguard Worker 85*2f2c4c7aSAndroid Build Coastguard Workerlibc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True) 86*2f2c4c7aSAndroid Build Coastguard Worker 87*2f2c4c7aSAndroid Build Coastguard WorkerKEY_SIZE = 4 88*2f2c4c7aSAndroid Build Coastguard WorkerVALUE_SIZE = 4 89*2f2c4c7aSAndroid Build Coastguard WorkerTOTAL_ENTRIES = 20 90*2f2c4c7aSAndroid Build Coastguard WorkerTEST_UID = 5432 91*2f2c4c7aSAndroid Build Coastguard WorkerTEST_GID = 12345 92*2f2c4c7aSAndroid Build Coastguard Worker# Offset to store the map key in stack register REG10 93*2f2c4c7aSAndroid Build Coastguard Workerkey_offset = -8 94*2f2c4c7aSAndroid Build Coastguard Worker# Offset to store the map value in stack register REG10 95*2f2c4c7aSAndroid Build Coastguard Workervalue_offset = -16 96*2f2c4c7aSAndroid Build Coastguard Worker 97*2f2c4c7aSAndroid Build Coastguard Worker 98*2f2c4c7aSAndroid Build Coastguard Worker# Debug usage only. 99*2f2c4c7aSAndroid Build Coastguard Workerdef PrintMapInfo(map_fd): 100*2f2c4c7aSAndroid Build Coastguard Worker # A random key that the map does not contain. 101*2f2c4c7aSAndroid Build Coastguard Worker key = 10086 102*2f2c4c7aSAndroid Build Coastguard Worker while 1: 103*2f2c4c7aSAndroid Build Coastguard Worker try: 104*2f2c4c7aSAndroid Build Coastguard Worker next_key = GetNextKey(map_fd, key).value 105*2f2c4c7aSAndroid Build Coastguard Worker value = LookupMap(map_fd, next_key) 106*2f2c4c7aSAndroid Build Coastguard Worker print(repr(next_key) + " : " + repr(value.value)) # pylint: disable=superfluous-parens 107*2f2c4c7aSAndroid Build Coastguard Worker key = next_key 108*2f2c4c7aSAndroid Build Coastguard Worker except socket.error: 109*2f2c4c7aSAndroid Build Coastguard Worker print("no value") # pylint: disable=superfluous-parens 110*2f2c4c7aSAndroid Build Coastguard Worker break 111*2f2c4c7aSAndroid Build Coastguard Worker 112*2f2c4c7aSAndroid Build Coastguard Worker 113*2f2c4c7aSAndroid Build Coastguard Worker# A dummy loopback function that causes a socket to send traffic to itself. 114*2f2c4c7aSAndroid Build Coastguard Workerdef SocketUDPLoopBack(packet_count, version, prog_fd): 115*2f2c4c7aSAndroid Build Coastguard Worker family = {4: socket.AF_INET, 6: socket.AF_INET6}[version] 116*2f2c4c7aSAndroid Build Coastguard Worker sock = socket.socket(family, socket.SOCK_DGRAM, 0) 117*2f2c4c7aSAndroid Build Coastguard Worker try: 118*2f2c4c7aSAndroid Build Coastguard Worker if prog_fd is not None: 119*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttachSocket(sock.fileno(), prog_fd) 120*2f2c4c7aSAndroid Build Coastguard Worker net_test.SetNonBlocking(sock) 121*2f2c4c7aSAndroid Build Coastguard Worker addr = {4: "127.0.0.1", 6: "::1"}[version] 122*2f2c4c7aSAndroid Build Coastguard Worker sock.bind((addr, 0)) 123*2f2c4c7aSAndroid Build Coastguard Worker addr = sock.getsockname() 124*2f2c4c7aSAndroid Build Coastguard Worker sockaddr = csocket.Sockaddr(addr) 125*2f2c4c7aSAndroid Build Coastguard Worker for _ in range(packet_count): 126*2f2c4c7aSAndroid Build Coastguard Worker sock.sendto(b"foo", addr) 127*2f2c4c7aSAndroid Build Coastguard Worker data, retaddr = csocket.Recvfrom(sock, 4096, 0) 128*2f2c4c7aSAndroid Build Coastguard Worker assert b"foo" == data 129*2f2c4c7aSAndroid Build Coastguard Worker assert sockaddr == retaddr 130*2f2c4c7aSAndroid Build Coastguard Worker return sock 131*2f2c4c7aSAndroid Build Coastguard Worker except Exception as e: 132*2f2c4c7aSAndroid Build Coastguard Worker sock.close() 133*2f2c4c7aSAndroid Build Coastguard Worker raise e 134*2f2c4c7aSAndroid Build Coastguard Worker 135*2f2c4c7aSAndroid Build Coastguard Worker 136*2f2c4c7aSAndroid Build Coastguard Worker# The main code block for eBPF packet counting program. It takes a preloaded 137*2f2c4c7aSAndroid Build Coastguard Worker# key from BPF_REG_0 and use it to look up the bpf map, if the element does not 138*2f2c4c7aSAndroid Build Coastguard Worker# exist in the map yet, the program will update the map with a new <key, 1> 139*2f2c4c7aSAndroid Build Coastguard Worker# pair. Otherwise it will jump to next code block to handle it. 140*2f2c4c7aSAndroid Build Coastguard Worker# REG0: regiter storing return value from helper function and the final return 141*2f2c4c7aSAndroid Build Coastguard Worker# value of eBPF program. 142*2f2c4c7aSAndroid Build Coastguard Worker# REG1 - REG5: temporary register used for storing values and load parameters 143*2f2c4c7aSAndroid Build Coastguard Worker# into eBPF helper function. After calling helper function, the value for these 144*2f2c4c7aSAndroid Build Coastguard Worker# registers will be reset. 145*2f2c4c7aSAndroid Build Coastguard Worker# REG6 - REG9: registers store values that will not be cleared when calling 146*2f2c4c7aSAndroid Build Coastguard Worker# eBPF helper function. 147*2f2c4c7aSAndroid Build Coastguard Worker# REG10: A stack stores values need to be accessed by the address. Program can 148*2f2c4c7aSAndroid Build Coastguard Worker# retrieve the address of a value by specifying the position of the value in 149*2f2c4c7aSAndroid Build Coastguard Worker# the stack. 150*2f2c4c7aSAndroid Build Coastguard Workerdef BpfFuncCountPacketInit(map_fd): 151*2f2c4c7aSAndroid Build Coastguard Worker key_pos = BPF_REG_7 152*2f2c4c7aSAndroid Build Coastguard Worker return [ 153*2f2c4c7aSAndroid Build Coastguard Worker # Get a preloaded key from BPF_REG_0 and store it at BPF_REG_7 154*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(key_pos, BPF_REG_10), 155*2f2c4c7aSAndroid Build Coastguard Worker BpfAlu64Imm(BPF_ADD, key_pos, key_offset), 156*2f2c4c7aSAndroid Build Coastguard Worker # Load map fd and look up the key in the map 157*2f2c4c7aSAndroid Build Coastguard Worker BpfLoadMapFd(map_fd, BPF_REG_1), 158*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_2, key_pos), 159*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_map_lookup_elem), 160*2f2c4c7aSAndroid Build Coastguard Worker # if the map element already exist, jump out of this 161*2f2c4c7aSAndroid Build Coastguard Worker # code block and let next part to handle it 162*2f2c4c7aSAndroid Build Coastguard Worker BpfJumpImm(BPF_AND, BPF_REG_0, 0, 10), 163*2f2c4c7aSAndroid Build Coastguard Worker BpfLoadMapFd(map_fd, BPF_REG_1), 164*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_2, key_pos), 165*2f2c4c7aSAndroid Build Coastguard Worker # Initial a new <key, value> pair with value equal to 1 and update to map 166*2f2c4c7aSAndroid Build Coastguard Worker BpfStMem(BPF_W, BPF_REG_10, value_offset, 1), 167*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_3, BPF_REG_10), 168*2f2c4c7aSAndroid Build Coastguard Worker BpfAlu64Imm(BPF_ADD, BPF_REG_3, value_offset), 169*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_4, 0), 170*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_map_update_elem) 171*2f2c4c7aSAndroid Build Coastguard Worker ] 172*2f2c4c7aSAndroid Build Coastguard Worker 173*2f2c4c7aSAndroid Build Coastguard Worker 174*2f2c4c7aSAndroid Build Coastguard WorkerINS_BPF_EXIT_BLOCK = [ 175*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_0, 0), 176*2f2c4c7aSAndroid Build Coastguard Worker BpfExitInsn() 177*2f2c4c7aSAndroid Build Coastguard Worker] 178*2f2c4c7aSAndroid Build Coastguard Worker 179*2f2c4c7aSAndroid Build Coastguard Worker# Bpf instruction for cgroup bpf filter to accept a packet and exit. 180*2f2c4c7aSAndroid Build Coastguard WorkerINS_CGROUP_ACCEPT = [ 181*2f2c4c7aSAndroid Build Coastguard Worker # Set return value to 1 and exit. 182*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_0, 1), 183*2f2c4c7aSAndroid Build Coastguard Worker BpfExitInsn() 184*2f2c4c7aSAndroid Build Coastguard Worker] 185*2f2c4c7aSAndroid Build Coastguard Worker 186*2f2c4c7aSAndroid Build Coastguard Worker# Bpf instruction for socket bpf filter to accept a packet and exit. 187*2f2c4c7aSAndroid Build Coastguard WorkerINS_SK_FILTER_ACCEPT = [ 188*2f2c4c7aSAndroid Build Coastguard Worker # Precondition: BPF_REG_6 = sk_buff context 189*2f2c4c7aSAndroid Build Coastguard Worker # Load the packet length from BPF_REG_6 and store it in BPF_REG_0 as the 190*2f2c4c7aSAndroid Build Coastguard Worker # return value. 191*2f2c4c7aSAndroid Build Coastguard Worker BpfLdxMem(BPF_W, BPF_REG_0, BPF_REG_6, 0), 192*2f2c4c7aSAndroid Build Coastguard Worker BpfExitInsn() 193*2f2c4c7aSAndroid Build Coastguard Worker] 194*2f2c4c7aSAndroid Build Coastguard Worker 195*2f2c4c7aSAndroid Build Coastguard Worker# Update a existing map element with +1. 196*2f2c4c7aSAndroid Build Coastguard WorkerINS_PACK_COUNT_UPDATE = [ 197*2f2c4c7aSAndroid Build Coastguard Worker # Precondition: BPF_REG_0 = Value retrieved from BPF maps 198*2f2c4c7aSAndroid Build Coastguard Worker # Add one to the corresponding eBPF value field for a specific eBPF key. 199*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_2, BPF_REG_0), 200*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_1, 1), 201*2f2c4c7aSAndroid Build Coastguard Worker BpfRawInsn(BPF_STX | BPF_XADD | BPF_W, BPF_REG_2, BPF_REG_1, 0, 0), 202*2f2c4c7aSAndroid Build Coastguard Worker] 203*2f2c4c7aSAndroid Build Coastguard Worker 204*2f2c4c7aSAndroid Build Coastguard WorkerINS_BPF_PARAM_STORE = [ 205*2f2c4c7aSAndroid Build Coastguard Worker BpfStxMem(BPF_DW, BPF_REG_10, BPF_REG_0, key_offset), 206*2f2c4c7aSAndroid Build Coastguard Worker] 207*2f2c4c7aSAndroid Build Coastguard Worker 208*2f2c4c7aSAndroid Build Coastguard Worker 209*2f2c4c7aSAndroid Build Coastguard Workerclass BpfTest(net_test.NetworkTest): 210*2f2c4c7aSAndroid Build Coastguard Worker 211*2f2c4c7aSAndroid Build Coastguard Worker def setUp(self): 212*2f2c4c7aSAndroid Build Coastguard Worker super(BpfTest, self).setUp() 213*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = None 214*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = None 215*2f2c4c7aSAndroid Build Coastguard Worker self.sock = None 216*2f2c4c7aSAndroid Build Coastguard Worker 217*2f2c4c7aSAndroid Build Coastguard Worker def tearDown(self): 218*2f2c4c7aSAndroid Build Coastguard Worker if self.prog_fd is not None: 219*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.prog_fd) 220*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = None 221*2f2c4c7aSAndroid Build Coastguard Worker if self.map_fd is not None: 222*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.map_fd) 223*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = None 224*2f2c4c7aSAndroid Build Coastguard Worker if self.sock: 225*2f2c4c7aSAndroid Build Coastguard Worker self.sock.close() 226*2f2c4c7aSAndroid Build Coastguard Worker self.sock = None 227*2f2c4c7aSAndroid Build Coastguard Worker super(BpfTest, self).tearDown() 228*2f2c4c7aSAndroid Build Coastguard Worker 229*2f2c4c7aSAndroid Build Coastguard Worker def testCreateMap(self): 230*2f2c4c7aSAndroid Build Coastguard Worker key, value = 1, 1 231*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 232*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 233*2f2c4c7aSAndroid Build Coastguard Worker UpdateMap(self.map_fd, key, value) 234*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(value, LookupMap(self.map_fd, key).value) 235*2f2c4c7aSAndroid Build Coastguard Worker DeleteMap(self.map_fd, key) 236*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.ENOENT, LookupMap, self.map_fd, key) 237*2f2c4c7aSAndroid Build Coastguard Worker 238*2f2c4c7aSAndroid Build Coastguard Worker def CheckAllMapEntry(self, nonexistent_key, total_entries, value): 239*2f2c4c7aSAndroid Build Coastguard Worker count = 0 240*2f2c4c7aSAndroid Build Coastguard Worker key = nonexistent_key 241*2f2c4c7aSAndroid Build Coastguard Worker while True: 242*2f2c4c7aSAndroid Build Coastguard Worker if count == total_entries: 243*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.ENOENT, GetNextKey, self.map_fd, key) 244*2f2c4c7aSAndroid Build Coastguard Worker break 245*2f2c4c7aSAndroid Build Coastguard Worker else: 246*2f2c4c7aSAndroid Build Coastguard Worker result = GetNextKey(self.map_fd, key) 247*2f2c4c7aSAndroid Build Coastguard Worker key = result.value 248*2f2c4c7aSAndroid Build Coastguard Worker self.assertGreaterEqual(key, 0) 249*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(value, LookupMap(self.map_fd, key).value) 250*2f2c4c7aSAndroid Build Coastguard Worker count += 1 251*2f2c4c7aSAndroid Build Coastguard Worker 252*2f2c4c7aSAndroid Build Coastguard Worker def testIterateMap(self): 253*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 254*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 255*2f2c4c7aSAndroid Build Coastguard Worker value = 1024 256*2f2c4c7aSAndroid Build Coastguard Worker for key in range(0, TOTAL_ENTRIES): 257*2f2c4c7aSAndroid Build Coastguard Worker UpdateMap(self.map_fd, key, value) 258*2f2c4c7aSAndroid Build Coastguard Worker for key in range(0, TOTAL_ENTRIES): 259*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(value, LookupMap(self.map_fd, key).value) 260*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.ENOENT, LookupMap, self.map_fd, 101) 261*2f2c4c7aSAndroid Build Coastguard Worker nonexistent_key = -1 262*2f2c4c7aSAndroid Build Coastguard Worker self.CheckAllMapEntry(nonexistent_key, TOTAL_ENTRIES, value) 263*2f2c4c7aSAndroid Build Coastguard Worker 264*2f2c4c7aSAndroid Build Coastguard Worker def testFindFirstMapKey(self): 265*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 266*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 267*2f2c4c7aSAndroid Build Coastguard Worker value = 1024 268*2f2c4c7aSAndroid Build Coastguard Worker for key in range(0, TOTAL_ENTRIES): 269*2f2c4c7aSAndroid Build Coastguard Worker UpdateMap(self.map_fd, key, value) 270*2f2c4c7aSAndroid Build Coastguard Worker first_key = GetFirstKey(self.map_fd) 271*2f2c4c7aSAndroid Build Coastguard Worker key = first_key.value 272*2f2c4c7aSAndroid Build Coastguard Worker self.CheckAllMapEntry(key, TOTAL_ENTRIES - 1, value) 273*2f2c4c7aSAndroid Build Coastguard Worker 274*2f2c4c7aSAndroid Build Coastguard Worker def testArrayNonZeroOffset(self): 275*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_ARRAY, KEY_SIZE, VALUE_SIZE, 2) 276*2f2c4c7aSAndroid Build Coastguard Worker key = 1 277*2f2c4c7aSAndroid Build Coastguard Worker value = 123 278*2f2c4c7aSAndroid Build Coastguard Worker UpdateMap(self.map_fd, key, value) 279*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(value, LookupMap(self.map_fd, key).value) 280*2f2c4c7aSAndroid Build Coastguard Worker 281*2f2c4c7aSAndroid Build Coastguard Worker def testRdOnlyMap(self): 282*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 283*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES, map_flags=BPF_F_RDONLY) 284*2f2c4c7aSAndroid Build Coastguard Worker value = 1024 285*2f2c4c7aSAndroid Build Coastguard Worker key = 1 286*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EPERM, UpdateMap, self.map_fd, key, value) 287*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.ENOENT, LookupMap, self.map_fd, key) 288*2f2c4c7aSAndroid Build Coastguard Worker 289*2f2c4c7aSAndroid Build Coastguard Worker def testWrOnlyMap(self): 290*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 291*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES, map_flags=BPF_F_WRONLY) 292*2f2c4c7aSAndroid Build Coastguard Worker value = 1024 293*2f2c4c7aSAndroid Build Coastguard Worker key = 1 294*2f2c4c7aSAndroid Build Coastguard Worker UpdateMap(self.map_fd, key, value) 295*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EPERM, LookupMap, self.map_fd, key) 296*2f2c4c7aSAndroid Build Coastguard Worker 297*2f2c4c7aSAndroid Build Coastguard Worker def testProgLoad(self): 298*2f2c4c7aSAndroid Build Coastguard Worker # Move skb to BPF_REG_6 for further usage 299*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 300*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_6, BPF_REG_1) 301*2f2c4c7aSAndroid Build Coastguard Worker ] 302*2f2c4c7aSAndroid Build Coastguard Worker instructions += INS_SK_FILTER_ACCEPT 303*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, instructions) 304*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(1, 4, self.prog_fd).close() 305*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(1, 6, self.prog_fd).close() 306*2f2c4c7aSAndroid Build Coastguard Worker 307*2f2c4c7aSAndroid Build Coastguard Worker def testPacketBlock(self): 308*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, INS_BPF_EXIT_BLOCK) 309*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EAGAIN, SocketUDPLoopBack, 1, 4, self.prog_fd) 310*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EAGAIN, SocketUDPLoopBack, 1, 6, self.prog_fd) 311*2f2c4c7aSAndroid Build Coastguard Worker 312*2f2c4c7aSAndroid Build Coastguard Worker def testPacketCount(self): 313*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 314*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 315*2f2c4c7aSAndroid Build Coastguard Worker key = 0xf0f0 316*2f2c4c7aSAndroid Build Coastguard Worker # Set up instruction block with key loaded at BPF_REG_0. 317*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 318*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_6, BPF_REG_1), 319*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_0, key) 320*2f2c4c7aSAndroid Build Coastguard Worker ] 321*2f2c4c7aSAndroid Build Coastguard Worker # Concatenate the generic packet count bpf program to it. 322*2f2c4c7aSAndroid Build Coastguard Worker instructions += (INS_BPF_PARAM_STORE + BpfFuncCountPacketInit(self.map_fd) 323*2f2c4c7aSAndroid Build Coastguard Worker + INS_SK_FILTER_ACCEPT + INS_PACK_COUNT_UPDATE 324*2f2c4c7aSAndroid Build Coastguard Worker + INS_SK_FILTER_ACCEPT) 325*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, instructions) 326*2f2c4c7aSAndroid Build Coastguard Worker packet_count = 10 327*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(packet_count, 4, self.prog_fd).close() 328*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(packet_count, 6, self.prog_fd).close() 329*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(packet_count * 2, LookupMap(self.map_fd, key).value) 330*2f2c4c7aSAndroid Build Coastguard Worker 331*2f2c4c7aSAndroid Build Coastguard Worker ############################################################################## 332*2f2c4c7aSAndroid Build Coastguard Worker # 333*2f2c4c7aSAndroid Build Coastguard Worker # Test for presence of kernel patch: 334*2f2c4c7aSAndroid Build Coastguard Worker # 335*2f2c4c7aSAndroid Build Coastguard Worker # ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head 336*2f2c4c7aSAndroid Build Coastguard Worker # 337*2f2c4c7aSAndroid Build Coastguard Worker # 4.14: https://android-review.googlesource.com/c/kernel/common/+/1237789 338*2f2c4c7aSAndroid Build Coastguard Worker # commit fe82848d9c1c887d2a84d3738c13e644d01b6d6f 339*2f2c4c7aSAndroid Build Coastguard Worker # 340*2f2c4c7aSAndroid Build Coastguard Worker # 4.19: https://android-review.googlesource.com/c/kernel/common/+/1237788 341*2f2c4c7aSAndroid Build Coastguard Worker # commit 6e04d94ab72435b45c413daff63520fd724e260e 342*2f2c4c7aSAndroid Build Coastguard Worker # 343*2f2c4c7aSAndroid Build Coastguard Worker # 5.4: https://android-review.googlesource.com/c/kernel/common/+/1237787 344*2f2c4c7aSAndroid Build Coastguard Worker # commit d730995e7bc5b4c10cc176235b704a274e6ec16f 345*2f2c4c7aSAndroid Build Coastguard Worker # 346*2f2c4c7aSAndroid Build Coastguard Worker # Upstream in Linux v5.8: 347*2f2c4c7aSAndroid Build Coastguard Worker # net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head 348*2f2c4c7aSAndroid Build Coastguard Worker # commit 6f3f65d80dac8f2bafce2213005821fccdce194c 349*2f2c4c7aSAndroid Build Coastguard Worker # 350*2f2c4c7aSAndroid Build Coastguard Worker def testSkbChangeHead(self): 351*2f2c4c7aSAndroid Build Coastguard Worker # long bpf_skb_change_head(struct sk_buff *skb, u32 len, u64 flags) 352*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 353*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_2, 14), # u32 len 354*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Imm(BPF_REG_3, 0), # u64 flags 355*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_skb_change_head), 356*2f2c4c7aSAndroid Build Coastguard Worker ] + INS_BPF_EXIT_BLOCK 357*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions, 358*2f2c4c7aSAndroid Build Coastguard Worker b"Apache 2.0") 359*2f2c4c7aSAndroid Build Coastguard Worker # No exceptions? Good. 360*2f2c4c7aSAndroid Build Coastguard Worker 361*2f2c4c7aSAndroid Build Coastguard Worker def testKtimeGetNsGPL(self): 362*2f2c4c7aSAndroid Build Coastguard Worker instructions = [BpfFuncCall(BPF_FUNC_ktime_get_ns)] + INS_BPF_EXIT_BLOCK 363*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions) 364*2f2c4c7aSAndroid Build Coastguard Worker # No exceptions? Good. 365*2f2c4c7aSAndroid Build Coastguard Worker 366*2f2c4c7aSAndroid Build Coastguard Worker ############################################################################## 367*2f2c4c7aSAndroid Build Coastguard Worker # 368*2f2c4c7aSAndroid Build Coastguard Worker # Test for presence of kernel patch: 369*2f2c4c7aSAndroid Build Coastguard Worker # 370*2f2c4c7aSAndroid Build Coastguard Worker # UPSTREAM: net: bpf: Make bpf_ktime_get_ns() available to non GPL programs 371*2f2c4c7aSAndroid Build Coastguard Worker # 372*2f2c4c7aSAndroid Build Coastguard Worker # 4.14: https://android-review.googlesource.com/c/kernel/common/+/1585269 373*2f2c4c7aSAndroid Build Coastguard Worker # commit cbb4c73f9eab8f3c8ac29175d45c99ccba382e15 374*2f2c4c7aSAndroid Build Coastguard Worker # 375*2f2c4c7aSAndroid Build Coastguard Worker # 4.19: https://android-review.googlesource.com/c/kernel/common/+/1355243 376*2f2c4c7aSAndroid Build Coastguard Worker # commit 272e21ccc9a92feeee80aff0587410a314b73c5b 377*2f2c4c7aSAndroid Build Coastguard Worker # 378*2f2c4c7aSAndroid Build Coastguard Worker # 5.4: https://android-review.googlesource.com/c/kernel/common/+/1355422 379*2f2c4c7aSAndroid Build Coastguard Worker # commit 45217b91eaaa3a563247c4f470f4cb785de6b1c6 380*2f2c4c7aSAndroid Build Coastguard Worker # 381*2f2c4c7aSAndroid Build Coastguard Worker def testKtimeGetNsApache2(self): 382*2f2c4c7aSAndroid Build Coastguard Worker instructions = [BpfFuncCall(BPF_FUNC_ktime_get_ns)] + INS_BPF_EXIT_BLOCK 383*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions, 384*2f2c4c7aSAndroid Build Coastguard Worker b"Apache 2.0") 385*2f2c4c7aSAndroid Build Coastguard Worker # No exceptions? Good. 386*2f2c4c7aSAndroid Build Coastguard Worker 387*2f2c4c7aSAndroid Build Coastguard Worker ############################################################################## 388*2f2c4c7aSAndroid Build Coastguard Worker # 389*2f2c4c7aSAndroid Build Coastguard Worker # Test for presence of kernel patch: 390*2f2c4c7aSAndroid Build Coastguard Worker # 391*2f2c4c7aSAndroid Build Coastguard Worker # BACKPORT: bpf: add bpf_ktime_get_boot_ns() 392*2f2c4c7aSAndroid Build Coastguard Worker # 393*2f2c4c7aSAndroid Build Coastguard Worker # 4.14: https://android-review.googlesource.com/c/kernel/common/+/1585587 394*2f2c4c7aSAndroid Build Coastguard Worker # commit 34073d7a8ee47ca908b56e9a1d14ca0615fdfc09 395*2f2c4c7aSAndroid Build Coastguard Worker # 396*2f2c4c7aSAndroid Build Coastguard Worker # 4.19: https://android-review.googlesource.com/c/kernel/common/+/1585606 397*2f2c4c7aSAndroid Build Coastguard Worker # commit 4812ec50935dfe59ba9f48a572e278dd0b02af68 398*2f2c4c7aSAndroid Build Coastguard Worker # 399*2f2c4c7aSAndroid Build Coastguard Worker # 5.4: https://android-review.googlesource.com/c/kernel/common/+/1585252 400*2f2c4c7aSAndroid Build Coastguard Worker # commit 57b3f4830fb66a6038c4c1c66ca2e138fe8be231 401*2f2c4c7aSAndroid Build Coastguard Worker # 402*2f2c4c7aSAndroid Build Coastguard Worker def testKtimeGetBootNs(self): 403*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 404*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_ktime_get_boot_ns), 405*2f2c4c7aSAndroid Build Coastguard Worker ] + INS_BPF_EXIT_BLOCK 406*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SCHED_CLS, instructions, 407*2f2c4c7aSAndroid Build Coastguard Worker b"Apache 2.0") 408*2f2c4c7aSAndroid Build Coastguard Worker # No exceptions? Good. 409*2f2c4c7aSAndroid Build Coastguard Worker 410*2f2c4c7aSAndroid Build Coastguard Worker ############################################################################## 411*2f2c4c7aSAndroid Build Coastguard Worker # 412*2f2c4c7aSAndroid Build Coastguard Worker # Test for presence of upstream 5.14 kernel patches: 413*2f2c4c7aSAndroid Build Coastguard Worker # 414*2f2c4c7aSAndroid Build Coastguard Worker # Android12-5.10: 415*2f2c4c7aSAndroid Build Coastguard Worker # UPSTREAM: net: initialize net->net_cookie at netns setup 416*2f2c4c7aSAndroid Build Coastguard Worker # https://android-review.git.corp.google.com/c/kernel/common/+/2503195 417*2f2c4c7aSAndroid Build Coastguard Worker # 418*2f2c4c7aSAndroid Build Coastguard Worker # UPSTREAM: net: retrieve netns cookie via getsocketopt 419*2f2c4c7aSAndroid Build Coastguard Worker # https://android-review.git.corp.google.com/c/kernel/common/+/2503056 420*2f2c4c7aSAndroid Build Coastguard Worker # 421*2f2c4c7aSAndroid Build Coastguard Worker # (and potentially if you care about kernel ABI) 422*2f2c4c7aSAndroid Build Coastguard Worker # 423*2f2c4c7aSAndroid Build Coastguard Worker # ANDROID: fix ABI by undoing atomic64_t -> u64 type conversion 424*2f2c4c7aSAndroid Build Coastguard Worker # https://android-review.git.corp.google.com/c/kernel/common/+/2504335 425*2f2c4c7aSAndroid Build Coastguard Worker # 426*2f2c4c7aSAndroid Build Coastguard Worker # Android13-5.10: 427*2f2c4c7aSAndroid Build Coastguard Worker # UPSTREAM: net: initialize net->net_cookie at netns setup 428*2f2c4c7aSAndroid Build Coastguard Worker # https://android-review.git.corp.google.com/c/kernel/common/+/2503795 429*2f2c4c7aSAndroid Build Coastguard Worker # 430*2f2c4c7aSAndroid Build Coastguard Worker # UPSTREAM: net: retrieve netns cookie via getsocketopt 431*2f2c4c7aSAndroid Build Coastguard Worker # https://android-review.git.corp.google.com/c/kernel/common/+/2503796 432*2f2c4c7aSAndroid Build Coastguard Worker # 433*2f2c4c7aSAndroid Build Coastguard Worker # (and potentially if you care about kernel ABI) 434*2f2c4c7aSAndroid Build Coastguard Worker # 435*2f2c4c7aSAndroid Build Coastguard Worker # ANDROID: fix ABI by undoing atomic64_t -> u64 type conversion 436*2f2c4c7aSAndroid Build Coastguard Worker # https://android-review.git.corp.google.com/c/kernel/common/+/2506895 437*2f2c4c7aSAndroid Build Coastguard Worker # 438*2f2c4c7aSAndroid Build Coastguard Worker @unittest.skipUnless(bpf.HAVE_SO_NETNS_COOKIE, "no SO_NETNS_COOKIE support") 439*2f2c4c7aSAndroid Build Coastguard Worker def testGetNetNsCookie(self): 440*2f2c4c7aSAndroid Build Coastguard Worker sk = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0) 441*2f2c4c7aSAndroid Build Coastguard Worker sizeof_u64 = 8 442*2f2c4c7aSAndroid Build Coastguard Worker cookie = sk.getsockopt(socket.SOL_SOCKET, bpf.SO_NETNS_COOKIE, sizeof_u64) 443*2f2c4c7aSAndroid Build Coastguard Worker sk.close() 444*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(len(cookie), 8) 445*2f2c4c7aSAndroid Build Coastguard Worker cookie = int.from_bytes(cookie, "little") 446*2f2c4c7aSAndroid Build Coastguard Worker self.assertGreaterEqual(cookie, 0) 447*2f2c4c7aSAndroid Build Coastguard Worker 448*2f2c4c7aSAndroid Build Coastguard Worker def testGetSocketCookie(self): 449*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 450*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 451*2f2c4c7aSAndroid Build Coastguard Worker # Move skb to REG6 for further usage, call helper function to get socket 452*2f2c4c7aSAndroid Build Coastguard Worker # cookie of current skb and return the cookie at REG0 for next code block 453*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 454*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_6, BPF_REG_1), 455*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_get_socket_cookie) 456*2f2c4c7aSAndroid Build Coastguard Worker ] 457*2f2c4c7aSAndroid Build Coastguard Worker instructions += (INS_BPF_PARAM_STORE + BpfFuncCountPacketInit(self.map_fd) 458*2f2c4c7aSAndroid Build Coastguard Worker + INS_SK_FILTER_ACCEPT + INS_PACK_COUNT_UPDATE 459*2f2c4c7aSAndroid Build Coastguard Worker + INS_SK_FILTER_ACCEPT) 460*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, instructions) 461*2f2c4c7aSAndroid Build Coastguard Worker packet_count = 10 462*2f2c4c7aSAndroid Build Coastguard Worker def PacketCountByCookie(version): 463*2f2c4c7aSAndroid Build Coastguard Worker self.sock = SocketUDPLoopBack(packet_count, version, self.prog_fd) 464*2f2c4c7aSAndroid Build Coastguard Worker cookie = sock_diag.SockDiag.GetSocketCookie(self.sock) 465*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(packet_count, LookupMap(self.map_fd, cookie).value) 466*2f2c4c7aSAndroid Build Coastguard Worker self.sock.close() 467*2f2c4c7aSAndroid Build Coastguard Worker PacketCountByCookie(4) 468*2f2c4c7aSAndroid Build Coastguard Worker PacketCountByCookie(6) 469*2f2c4c7aSAndroid Build Coastguard Worker 470*2f2c4c7aSAndroid Build Coastguard Worker def testGetSocketUid(self): 471*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 472*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 473*2f2c4c7aSAndroid Build Coastguard Worker # Set up the instruction with uid at BPF_REG_0. 474*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 475*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_6, BPF_REG_1), 476*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_get_socket_uid) 477*2f2c4c7aSAndroid Build Coastguard Worker ] 478*2f2c4c7aSAndroid Build Coastguard Worker # Concatenate the generic packet count bpf program to it. 479*2f2c4c7aSAndroid Build Coastguard Worker instructions += (INS_BPF_PARAM_STORE + BpfFuncCountPacketInit(self.map_fd) 480*2f2c4c7aSAndroid Build Coastguard Worker + INS_SK_FILTER_ACCEPT + INS_PACK_COUNT_UPDATE 481*2f2c4c7aSAndroid Build Coastguard Worker + INS_SK_FILTER_ACCEPT) 482*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER, instructions) 483*2f2c4c7aSAndroid Build Coastguard Worker packet_count = 10 484*2f2c4c7aSAndroid Build Coastguard Worker uid = TEST_UID 485*2f2c4c7aSAndroid Build Coastguard Worker with net_test.RunAsUid(uid): 486*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.ENOENT, LookupMap, self.map_fd, uid) 487*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(packet_count, 4, self.prog_fd).close() 488*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(packet_count, LookupMap(self.map_fd, uid).value) 489*2f2c4c7aSAndroid Build Coastguard Worker DeleteMap(self.map_fd, uid) 490*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(packet_count, 6, self.prog_fd).close() 491*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(packet_count, LookupMap(self.map_fd, uid).value) 492*2f2c4c7aSAndroid Build Coastguard Worker 493*2f2c4c7aSAndroid Build Coastguard Worker 494*2f2c4c7aSAndroid Build Coastguard Workerclass BpfCgroupTest(net_test.NetworkTest): 495*2f2c4c7aSAndroid Build Coastguard Worker 496*2f2c4c7aSAndroid Build Coastguard Worker @classmethod 497*2f2c4c7aSAndroid Build Coastguard Worker def setUpClass(cls): 498*2f2c4c7aSAndroid Build Coastguard Worker super(BpfCgroupTest, cls).setUpClass() 499*2f2c4c7aSAndroid Build Coastguard Worker # os.open() throws exception on failure 500*2f2c4c7aSAndroid Build Coastguard Worker cls._cg_fd = os.open("/sys/fs/cgroup", os.O_DIRECTORY | os.O_RDONLY) 501*2f2c4c7aSAndroid Build Coastguard Worker 502*2f2c4c7aSAndroid Build Coastguard Worker @classmethod 503*2f2c4c7aSAndroid Build Coastguard Worker def tearDownClass(cls): 504*2f2c4c7aSAndroid Build Coastguard Worker if cls._cg_fd is not None: 505*2f2c4c7aSAndroid Build Coastguard Worker os.close(cls._cg_fd) 506*2f2c4c7aSAndroid Build Coastguard Worker cls._cg_fd = None 507*2f2c4c7aSAndroid Build Coastguard Worker super(BpfCgroupTest, cls).tearDownClass() 508*2f2c4c7aSAndroid Build Coastguard Worker 509*2f2c4c7aSAndroid Build Coastguard Worker def setUp(self): 510*2f2c4c7aSAndroid Build Coastguard Worker super(BpfCgroupTest, self).setUp() 511*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = None 512*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = None 513*2f2c4c7aSAndroid Build Coastguard Worker self.cg_inet_ingress = BpfProgGetFdById( 514*2f2c4c7aSAndroid Build Coastguard Worker BpfProgQuery(self._cg_fd, BPF_CGROUP_INET_INGRESS, 0, 0)) 515*2f2c4c7aSAndroid Build Coastguard Worker self.cg_inet_egress = BpfProgGetFdById( 516*2f2c4c7aSAndroid Build Coastguard Worker BpfProgQuery(self._cg_fd, BPF_CGROUP_INET_EGRESS, 0, 0)) 517*2f2c4c7aSAndroid Build Coastguard Worker self.cg_inet_sock_create = BpfProgGetFdById( 518*2f2c4c7aSAndroid Build Coastguard Worker BpfProgQuery(self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE, 0, 0)) 519*2f2c4c7aSAndroid Build Coastguard Worker if self.cg_inet_ingress: 520*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_INGRESS) 521*2f2c4c7aSAndroid Build Coastguard Worker if self.cg_inet_egress: 522*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_EGRESS) 523*2f2c4c7aSAndroid Build Coastguard Worker if self.cg_inet_sock_create: 524*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE) 525*2f2c4c7aSAndroid Build Coastguard Worker 526*2f2c4c7aSAndroid Build Coastguard Worker def tearDown(self): 527*2f2c4c7aSAndroid Build Coastguard Worker if self.prog_fd is not None: 528*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.prog_fd) 529*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = None 530*2f2c4c7aSAndroid Build Coastguard Worker if self.map_fd is not None: 531*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.map_fd) 532*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = None 533*2f2c4c7aSAndroid Build Coastguard Worker if self.cg_inet_ingress is None: 534*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_INGRESS) 535*2f2c4c7aSAndroid Build Coastguard Worker else: 536*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.cg_inet_ingress, self._cg_fd, BPF_CGROUP_INET_INGRESS) 537*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.cg_inet_ingress) 538*2f2c4c7aSAndroid Build Coastguard Worker self.cg_inet_ingress = None 539*2f2c4c7aSAndroid Build Coastguard Worker if self.cg_inet_egress is None: 540*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_EGRESS) 541*2f2c4c7aSAndroid Build Coastguard Worker else: 542*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.cg_inet_egress, self._cg_fd, BPF_CGROUP_INET_EGRESS) 543*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.cg_inet_egress) 544*2f2c4c7aSAndroid Build Coastguard Worker self.cg_inet_egress = None 545*2f2c4c7aSAndroid Build Coastguard Worker if self.cg_inet_sock_create is None: 546*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE) 547*2f2c4c7aSAndroid Build Coastguard Worker else: 548*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.cg_inet_sock_create, self._cg_fd, 549*2f2c4c7aSAndroid Build Coastguard Worker BPF_CGROUP_INET_SOCK_CREATE) 550*2f2c4c7aSAndroid Build Coastguard Worker os.close(self.cg_inet_sock_create) 551*2f2c4c7aSAndroid Build Coastguard Worker self.cg_inet_sock_create = None 552*2f2c4c7aSAndroid Build Coastguard Worker super(BpfCgroupTest, self).tearDown() 553*2f2c4c7aSAndroid Build Coastguard Worker 554*2f2c4c7aSAndroid Build Coastguard Worker def testCgroupBpfAttach(self): 555*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_CGROUP_SKB, INS_BPF_EXIT_BLOCK) 556*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.prog_fd, self._cg_fd, BPF_CGROUP_INET_INGRESS) 557*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_INGRESS) 558*2f2c4c7aSAndroid Build Coastguard Worker 559*2f2c4c7aSAndroid Build Coastguard Worker def testCgroupIngress(self): 560*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_CGROUP_SKB, INS_BPF_EXIT_BLOCK) 561*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.prog_fd, self._cg_fd, BPF_CGROUP_INET_INGRESS) 562*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EAGAIN, SocketUDPLoopBack, 1, 4, None) 563*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EAGAIN, SocketUDPLoopBack, 1, 6, None) 564*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_INGRESS) 565*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(1, 4, None).close() 566*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(1, 6, None).close() 567*2f2c4c7aSAndroid Build Coastguard Worker 568*2f2c4c7aSAndroid Build Coastguard Worker def testCgroupEgress(self): 569*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_CGROUP_SKB, INS_BPF_EXIT_BLOCK) 570*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.prog_fd, self._cg_fd, BPF_CGROUP_INET_EGRESS) 571*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EPERM, SocketUDPLoopBack, 1, 4, None) 572*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.EPERM, SocketUDPLoopBack, 1, 6, None) 573*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_EGRESS) 574*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(1, 4, None).close() 575*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(1, 6, None).close() 576*2f2c4c7aSAndroid Build Coastguard Worker 577*2f2c4c7aSAndroid Build Coastguard Worker def testCgroupBpfUid(self): 578*2f2c4c7aSAndroid Build Coastguard Worker self.map_fd = CreateMap(BPF_MAP_TYPE_HASH, KEY_SIZE, VALUE_SIZE, 579*2f2c4c7aSAndroid Build Coastguard Worker TOTAL_ENTRIES) 580*2f2c4c7aSAndroid Build Coastguard Worker # Similar to the program used in testGetSocketUid. 581*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 582*2f2c4c7aSAndroid Build Coastguard Worker BpfMov64Reg(BPF_REG_6, BPF_REG_1), 583*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_get_socket_uid) 584*2f2c4c7aSAndroid Build Coastguard Worker ] 585*2f2c4c7aSAndroid Build Coastguard Worker instructions += (INS_BPF_PARAM_STORE + BpfFuncCountPacketInit(self.map_fd) 586*2f2c4c7aSAndroid Build Coastguard Worker + INS_CGROUP_ACCEPT + INS_PACK_COUNT_UPDATE 587*2f2c4c7aSAndroid Build Coastguard Worker + INS_CGROUP_ACCEPT) 588*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_CGROUP_SKB, instructions) 589*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.prog_fd, self._cg_fd, BPF_CGROUP_INET_INGRESS) 590*2f2c4c7aSAndroid Build Coastguard Worker packet_count = 20 591*2f2c4c7aSAndroid Build Coastguard Worker uid = TEST_UID 592*2f2c4c7aSAndroid Build Coastguard Worker with net_test.RunAsUid(uid): 593*2f2c4c7aSAndroid Build Coastguard Worker self.assertRaisesErrno(errno.ENOENT, LookupMap, self.map_fd, uid) 594*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(packet_count, 4, None).close() 595*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(packet_count, LookupMap(self.map_fd, uid).value) 596*2f2c4c7aSAndroid Build Coastguard Worker DeleteMap(self.map_fd, uid) 597*2f2c4c7aSAndroid Build Coastguard Worker SocketUDPLoopBack(packet_count, 6, None).close() 598*2f2c4c7aSAndroid Build Coastguard Worker self.assertEqual(packet_count, LookupMap(self.map_fd, uid).value) 599*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_INGRESS) 600*2f2c4c7aSAndroid Build Coastguard Worker 601*2f2c4c7aSAndroid Build Coastguard Worker def checkSocketCreate(self, family, socktype, sockproto, success): 602*2f2c4c7aSAndroid Build Coastguard Worker try: 603*2f2c4c7aSAndroid Build Coastguard Worker sock = socket.socket(family, socktype, sockproto) 604*2f2c4c7aSAndroid Build Coastguard Worker sock.close() 605*2f2c4c7aSAndroid Build Coastguard Worker except socket.error as e: 606*2f2c4c7aSAndroid Build Coastguard Worker if success: 607*2f2c4c7aSAndroid Build Coastguard Worker self.fail("Failed to create socket family=%d type=%d proto=%d err=%s" % 608*2f2c4c7aSAndroid Build Coastguard Worker (family, socktype, sockproto, os.strerror(e.errno))) 609*2f2c4c7aSAndroid Build Coastguard Worker return 610*2f2c4c7aSAndroid Build Coastguard Worker if not success: 611*2f2c4c7aSAndroid Build Coastguard Worker self.fail("unexpected socket family=%d type=%d proto=%d created, " 612*2f2c4c7aSAndroid Build Coastguard Worker "should be blocked" % (family, socktype, sockproto)) 613*2f2c4c7aSAndroid Build Coastguard Worker 614*2f2c4c7aSAndroid Build Coastguard Worker def testPfKeySocketCreate(self): 615*2f2c4c7aSAndroid Build Coastguard Worker # AF_KEY socket type. See include/linux/socket.h. 616*2f2c4c7aSAndroid Build Coastguard Worker AF_KEY = 15 # pylint: disable=invalid-name 617*2f2c4c7aSAndroid Build Coastguard Worker 618*2f2c4c7aSAndroid Build Coastguard Worker # PFKEYv2 constants. See include/uapi/linux/pfkeyv2.h. 619*2f2c4c7aSAndroid Build Coastguard Worker PF_KEY_V2 = 2 # pylint: disable=invalid-name 620*2f2c4c7aSAndroid Build Coastguard Worker 621*2f2c4c7aSAndroid Build Coastguard Worker self.checkSocketCreate(AF_KEY, socket.SOCK_RAW, PF_KEY_V2, True) 622*2f2c4c7aSAndroid Build Coastguard Worker 623*2f2c4c7aSAndroid Build Coastguard Worker def trySocketCreate(self, success): 624*2f2c4c7aSAndroid Build Coastguard Worker for family in [socket.AF_INET, socket.AF_INET6]: 625*2f2c4c7aSAndroid Build Coastguard Worker for socktype in [socket.SOCK_DGRAM, socket.SOCK_STREAM]: 626*2f2c4c7aSAndroid Build Coastguard Worker self.checkSocketCreate(family, socktype, 0, success) 627*2f2c4c7aSAndroid Build Coastguard Worker 628*2f2c4c7aSAndroid Build Coastguard Worker def testCgroupSocketCreateBlock(self): 629*2f2c4c7aSAndroid Build Coastguard Worker instructions = [ 630*2f2c4c7aSAndroid Build Coastguard Worker BpfFuncCall(BPF_FUNC_get_current_uid_gid), 631*2f2c4c7aSAndroid Build Coastguard Worker BpfAlu64Imm(BPF_AND, BPF_REG_0, 0xfffffff), 632*2f2c4c7aSAndroid Build Coastguard Worker BpfJumpImm(BPF_JNE, BPF_REG_0, TEST_UID, 2), 633*2f2c4c7aSAndroid Build Coastguard Worker ] 634*2f2c4c7aSAndroid Build Coastguard Worker instructions += INS_BPF_EXIT_BLOCK + INS_CGROUP_ACCEPT 635*2f2c4c7aSAndroid Build Coastguard Worker 636*2f2c4c7aSAndroid Build Coastguard Worker fd = BpfProgGetFdById( 637*2f2c4c7aSAndroid Build Coastguard Worker BpfProgQuery(self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE, 0, 0)) 638*2f2c4c7aSAndroid Build Coastguard Worker assert fd is None 639*2f2c4c7aSAndroid Build Coastguard Worker 640*2f2c4c7aSAndroid Build Coastguard Worker self.prog_fd = BpfProgLoad(BPF_PROG_TYPE_CGROUP_SOCK, instructions) 641*2f2c4c7aSAndroid Build Coastguard Worker BpfProgAttach(self.prog_fd, self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE) 642*2f2c4c7aSAndroid Build Coastguard Worker 643*2f2c4c7aSAndroid Build Coastguard Worker fd = BpfProgGetFdById( 644*2f2c4c7aSAndroid Build Coastguard Worker BpfProgQuery(self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE, 0, 0)) 645*2f2c4c7aSAndroid Build Coastguard Worker assert fd is not None 646*2f2c4c7aSAndroid Build Coastguard Worker # equality while almost certain is not actually 100% guaranteed: 647*2f2c4c7aSAndroid Build Coastguard Worker assert fd >= self.prog_fd + 1 648*2f2c4c7aSAndroid Build Coastguard Worker os.close(fd) 649*2f2c4c7aSAndroid Build Coastguard Worker fd = None 650*2f2c4c7aSAndroid Build Coastguard Worker 651*2f2c4c7aSAndroid Build Coastguard Worker with net_test.RunAsUid(TEST_UID): 652*2f2c4c7aSAndroid Build Coastguard Worker # Socket creation with target uid should fail 653*2f2c4c7aSAndroid Build Coastguard Worker self.trySocketCreate(False) 654*2f2c4c7aSAndroid Build Coastguard Worker # Socket create with different uid should success 655*2f2c4c7aSAndroid Build Coastguard Worker self.trySocketCreate(True) 656*2f2c4c7aSAndroid Build Coastguard Worker BpfProgDetach(self._cg_fd, BPF_CGROUP_INET_SOCK_CREATE) 657*2f2c4c7aSAndroid Build Coastguard Worker with net_test.RunAsUid(TEST_UID): 658*2f2c4c7aSAndroid Build Coastguard Worker self.trySocketCreate(True) 659*2f2c4c7aSAndroid Build Coastguard Worker 660*2f2c4c7aSAndroid Build Coastguard Workerif __name__ == "__main__": 661*2f2c4c7aSAndroid Build Coastguard Worker unittest.main() 662