xref: /aosp_15_r20/kernel/tests/net/test/bpf_test.py (revision 2f2c4c7ab4226c71756b9c31670392fdd6887c4f)
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