Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "cgen/stub.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : : #include <linux/icmp.h>
11 : : #include <linux/icmpv6.h>
12 : : #include <linux/if_ether.h>
13 : : #include <linux/in.h> // NOLINT
14 : : #include <linux/in6.h>
15 : : #include <linux/ip.h>
16 : : #include <linux/ipv6.h>
17 : : #include <linux/tcp.h>
18 : : #include <linux/udp.h>
19 : :
20 : : #include <endian.h>
21 : : #include <stddef.h>
22 : :
23 : : #include <bpfilter/ctx.h>
24 : : #include <bpfilter/elfstub.h>
25 : : #include <bpfilter/flavor.h>
26 : : #include <bpfilter/helper.h>
27 : : #include <bpfilter/matcher.h>
28 : : #include <bpfilter/verdict.h>
29 : :
30 : : #include "cgen/jmp.h"
31 : : #include "cgen/printer.h"
32 : : #include "cgen/program.h"
33 : : #include "cgen/swich.h"
34 : : #include "filter.h"
35 : :
36 : : #define _BF_LOW_EH_BITMASK 0x1801800000000801ULL
37 : :
38 : : /**
39 : : * Generate stub to create a dynptr.
40 : : *
41 : : * @param program Program to generate the stub for. Must not be NULL.
42 : : * @param arg_reg Register where the first argument to the dynptr creation
43 : : * function is located (SKB or xdp_md structure).
44 : : * @param kfunc Name of the kfunc to use to create the dynamic pointer.
45 : : * @return 0 on success, or negative errno value on error.
46 : : */
47 : 1372 : static int _bf_stub_make_ctx_dynptr(struct bf_program *program, int arg_reg,
48 : : const char *kfunc)
49 : : {
50 : : int ret_code;
51 : : int r;
52 : :
53 : : assert(program);
54 : : assert(kfunc);
55 : :
56 : : // Call bpf_dynptr_from_xxx()
57 [ - + ]: 1372 : if (arg_reg != BPF_REG_1)
58 [ # # ]: 0 : EMIT(program, BPF_MOV64_IMM(BPF_REG_1, arg_reg));
59 [ + - ]: 1372 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
60 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
61 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(dynptr)));
62 [ + - ]: 1372 : EMIT_KFUNC_CALL(program, kfunc);
63 : :
64 : : // If the function call failed, quit the program
65 : : {
66 : 2744 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
67 [ + - ]: 1372 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
68 : :
69 : : // Update the error counter
70 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
71 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
72 [ + - + - ]: 2744 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
73 [ + - ]: 1372 : EMIT(program,
74 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
75 [ + - ]: 1372 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
76 : :
77 [ - + ]: 1372 : if (bf_ctx_is_verbose(BF_VERBOSE_BPF))
78 [ # # # # : 0 : EMIT_PRINT(program, "failed to create a new dynamic pointer");
# # # # ]
79 : :
80 : 1372 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT, &ret_code);
81 [ + - ]: 1372 : if (r)
82 : : return r;
83 : :
84 [ + - ]: 1372 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
85 [ + - ]: 1372 : EMIT(program, BPF_EXIT_INSN());
86 : : }
87 : :
88 : 1372 : return 0;
89 : : }
90 : :
91 : 210 : int bf_stub_make_ctx_xdp_dynptr(struct bf_program *program, int md_reg)
92 : : {
93 : : assert(program);
94 : :
95 : 210 : return _bf_stub_make_ctx_dynptr(program, md_reg, "bpf_dynptr_from_xdp");
96 : : }
97 : :
98 : 1162 : int bf_stub_make_ctx_skb_dynptr(struct bf_program *program, int skb_reg)
99 : : {
100 : : assert(program);
101 : :
102 : 1162 : return _bf_stub_make_ctx_dynptr(program, skb_reg, "bpf_dynptr_from_skb");
103 : : }
104 : :
105 : 498 : int bf_stub_parse_l2_ethhdr(struct bf_program *program)
106 : : {
107 : : int ret_code;
108 : : int r;
109 : :
110 : : assert(program);
111 : :
112 : : // Call bpf_dynptr_slice()
113 [ + - ]: 498 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
114 [ + - ]: 498 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
115 [ + - ]: 498 : EMIT(program, BPF_MOV64_IMM(BPF_REG_2, 0));
116 [ + - ]: 498 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
117 [ + - ]: 498 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l2)));
118 [ + - ]: 498 : EMIT(program, BPF_MOV64_IMM(BPF_REG_4, sizeof(struct ethhdr)));
119 : :
120 [ + - ]: 498 : EMIT(program,
121 : : BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(l2_size)));
122 : :
123 [ + - ]: 498 : EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
124 : :
125 : : // If the function call failed, quit the program
126 : : {
127 : 996 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
128 [ + - ]: 498 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
129 : :
130 : : // Update the error counter
131 [ + - ]: 498 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
132 [ + - ]: 498 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
133 [ + - + - ]: 996 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
134 [ + - ]: 498 : EMIT(program,
135 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
136 [ + - ]: 498 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
137 : :
138 [ - + ]: 498 : if (bf_ctx_is_verbose(BF_VERBOSE_BPF))
139 [ # # # # : 0 : EMIT_PRINT(program, "failed to create L2 dynamic pointer slice");
# # # # ]
140 : :
141 : 498 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT, &ret_code);
142 [ + - ]: 498 : if (r)
143 : : return r;
144 : :
145 [ + - ]: 498 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
146 [ + - ]: 498 : EMIT(program, BPF_EXIT_INSN());
147 : : }
148 : :
149 : : // Store the L2 header address into the runtime context
150 [ + - ]: 498 : EMIT(program,
151 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l2_hdr)));
152 : :
153 : : // Store the L3 protocol ID in r7
154 [ + - ]: 498 : EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_0,
155 : : offsetof(struct ethhdr, h_proto)));
156 : :
157 : : // Set bf_runtime.l3_offset
158 : 498 : EMIT(program, BPF_ST_MEM(BPF_W, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset),
159 : : sizeof(struct ethhdr)));
160 : :
161 : : return 0;
162 : : }
163 : :
164 : 1372 : int bf_stub_parse_l3_hdr(struct bf_program *program)
165 : : {
166 : 1372 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_default();
167 : : int ret_code;
168 : : int r;
169 : :
170 : : assert(program);
171 : :
172 : : /* Store the size of the L3 protocol header in r4, depending on the protocol
173 : : * ID stored in r7. If the protocol is not supported, we store 0 into r7
174 : : * and we skip the instructions below. */
175 : : {
176 : 1372 : _clean_bf_swich_ struct bf_swich swich =
177 [ - + ]: 1372 : bf_swich_get(program, BPF_REG_7);
178 : :
179 [ - + ]: 1372 : EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IP),
180 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct iphdr)));
181 [ - + ]: 1372 : EMIT_SWICH_OPTION(&swich, htobe16(ETH_P_IPV6),
182 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct ipv6hdr)));
183 [ - + ]: 1372 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0));
184 : :
185 : 1372 : r = bf_swich_generate(&swich);
186 [ + - ]: 1372 : if (r)
187 : : return r;
188 : : }
189 [ + - ]: 1372 : _ = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, 0, 0));
190 : :
191 [ + - ]: 1372 : EMIT(program,
192 : : BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(l3_size)));
193 : :
194 : : // Call bpf_dynptr_slice()
195 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
196 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
197 [ + - ]: 1372 : EMIT(program,
198 : : BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, BF_PROG_CTX_OFF(l3_offset)));
199 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
200 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l2)));
201 [ + - ]: 1372 : EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
202 : :
203 : : // If the function call failed, quit the program
204 : : {
205 : 2744 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
206 [ + - ]: 1372 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
207 : :
208 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
209 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
210 [ + - + - ]: 2744 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
211 [ + - ]: 1372 : EMIT(program,
212 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
213 [ + - ]: 1372 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
214 : :
215 [ - + ]: 1372 : if (bf_ctx_is_verbose(BF_VERBOSE_BPF))
216 [ # # # # : 0 : EMIT_PRINT(program, "failed to create L3 dynamic pointer slice");
# # # # ]
217 : :
218 : 1372 : r = program->runtime.ops->get_verdict(BF_VERDICT_ACCEPT, &ret_code);
219 [ + - ]: 1372 : if (r)
220 : : return r;
221 : :
222 [ + - ]: 1372 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
223 [ + - ]: 1372 : EMIT(program, BPF_EXIT_INSN());
224 : : }
225 : :
226 : : // Store the L3 header address into the runtime context
227 [ + - ]: 1372 : EMIT(program,
228 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l3_hdr)));
229 : :
230 : : /* Unsupported L3 protocols have been filtered out at the beginning of this
231 : : * function and would jump over the block below, so there is no need to
232 : : * worry about them here. */
233 : : {
234 : : // IPv4
235 [ + - ]: 2744 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_get(
236 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IP), 0));
237 : :
238 [ + - ]: 1372 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0));
239 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x0f));
240 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 2));
241 [ + - ]: 1372 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10,
242 : : BF_PROG_CTX_OFF(l3_offset)));
243 [ + - ]: 1372 : EMIT(program, BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2));
244 [ + - ]: 1372 : EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1,
245 : : BF_PROG_CTX_OFF(l4_offset)));
246 [ + - ]: 1372 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_0,
247 : : offsetof(struct iphdr, protocol)));
248 : : }
249 : :
250 : : {
251 : : // IPv6
252 : : struct bf_jmpctx tcpjmp, udpjmp, noehjmp, ehjmp;
253 : : struct bpf_insn ld64[2] = {BPF_LD_IMM64(BPF_REG_2, _BF_LOW_EH_BITMASK)};
254 [ + - ]: 2744 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_get(
255 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
256 : :
257 [ + - ]: 1372 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_0,
258 : : offsetof(struct ipv6hdr, nexthdr)));
259 : :
260 : : /* Fast path for TCP and UDP: quickly recognize the most used protocol
261 : : * to process them as fast as possible. */
262 [ + - ]: 1372 : tcpjmp = bf_jmpctx_get(program,
263 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, IPPROTO_TCP, 0));
264 [ + - ]: 1372 : udpjmp = bf_jmpctx_get(program,
265 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, IPPROTO_UDP, 0));
266 : :
267 : : /* For all the EH protocol numbers <64, use a bitmask:
268 : : * mask = (1<<0) | (1<<43) | (1<<44) | (1<<50) | (1<<51) | (1<<60)
269 : : *
270 : : * Pseudo-code:
271 : : * - r3 = 1 << r8 (nexthdr)
272 : : * - r3 = r3 & mask
273 : : * - if r3 != 0: go to slow path (EH present) */
274 [ + - ]: 1372 : EMIT(program, ld64[0]);
275 [ + - ]: 1372 : EMIT(program, ld64[1]);
276 [ + - ]: 1372 : EMIT(program, BPF_JMP_IMM(BPF_JGE, BPF_REG_8, 64, 4));
277 [ + - ]: 1372 : EMIT(program, BPF_MOV64_IMM(BPF_REG_3, 1));
278 [ + - ]: 1372 : EMIT(program, BPF_ALU64_REG(BPF_LSH, BPF_REG_3, BPF_REG_8));
279 [ + - ]: 1372 : EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_3, BPF_REG_2));
280 [ + - ]: 1372 : EMIT(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_3, 0, 4));
281 : :
282 : : // EH with protocol numbers >64 are processed individually
283 [ + - ]: 1372 : EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 135, 3));
284 [ + - ]: 1372 : EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 139, 2));
285 [ + - ]: 1372 : EMIT(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 140, 1));
286 : :
287 : : // If no EH matched, nexthdr is L4, skip EH processing
288 [ + - ]: 1372 : noehjmp = bf_jmpctx_get(program, BPF_JMP_A(0));
289 : :
290 : : // Process EH
291 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
292 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
293 : : // If any rule filters on ipv6.nexthdr, store the EH in the runtime context
294 : : // during process, so we won't have to process the EH again.
295 [ + + ]: 1372 : if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR))
296 [ + - ]: 30 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_PARSE_IPV6_NH);
297 : : else
298 [ + - ]: 1342 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_PARSE_IPV6_EH);
299 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_8, BPF_REG_0));
300 : :
301 [ + - ]: 1372 : ehjmp = bf_jmpctx_get(program, BPF_JMP_A(0));
302 : :
303 : : // If no EH found, all the jmp will end up here
304 : 1372 : bf_jmpctx_cleanup(&tcpjmp);
305 : 1372 : bf_jmpctx_cleanup(&udpjmp);
306 : 1372 : bf_jmpctx_cleanup(&noehjmp);
307 : :
308 : : // Process IPv6 header, no EH (BPF_REG_8 already contains nexthdr)
309 [ + - ]: 1372 : EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10,
310 : : BF_PROG_CTX_OFF(l3_offset)));
311 [ + - ]: 1372 : EMIT(program,
312 : : BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, sizeof(struct ipv6hdr)));
313 [ + - ]: 1372 : EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2,
314 : : BF_PROG_CTX_OFF(l4_offset)));
315 : :
316 : 1372 : bf_jmpctx_cleanup(&ehjmp);
317 : : }
318 : :
319 : 1372 : return 0;
320 : : }
321 : :
322 : 1372 : int bf_stub_parse_l4_hdr(struct bf_program *program)
323 : : {
324 : 1372 : _clean_bf_jmpctx_ struct bf_jmpctx _ = bf_jmpctx_default();
325 : : int r;
326 : :
327 : : assert(program);
328 : :
329 : : /* Parse the L4 protocol and handle unuspported protocol, similarly to
330 : : * bf_stub_parse_l3_hdr() above. */
331 : : {
332 : 1372 : _clean_bf_swich_ struct bf_swich swich =
333 [ - + ]: 1372 : bf_swich_get(program, BPF_REG_8);
334 : :
335 [ - + ]: 1372 : EMIT_SWICH_OPTION(&swich, IPPROTO_TCP,
336 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct tcphdr)));
337 [ - + ]: 1372 : EMIT_SWICH_OPTION(&swich, IPPROTO_UDP,
338 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct udphdr)));
339 [ - + ]: 1372 : EMIT_SWICH_OPTION(&swich, IPPROTO_ICMP,
340 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct icmphdr)));
341 [ - + ]: 1372 : EMIT_SWICH_OPTION(&swich, IPPROTO_ICMPV6,
342 : : BPF_MOV64_IMM(BPF_REG_4, sizeof(struct icmp6hdr)));
343 [ - + ]: 1372 : EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_8, 0));
344 : :
345 : 1372 : r = bf_swich_generate(&swich);
346 [ + - ]: 1372 : if (r)
347 : : return r;
348 : : }
349 [ + - ]: 1372 : _ = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_8, 0, 0));
350 : :
351 [ + - ]: 1372 : EMIT(program,
352 : : BPF_STX_MEM(BPF_B, BPF_REG_10, BPF_REG_4, BF_PROG_CTX_OFF(l4_size)));
353 : :
354 : : // Call bpf_dynptr_slice()
355 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
356 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(dynptr)));
357 [ + - ]: 1372 : EMIT(program,
358 : : BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, BF_PROG_CTX_OFF(l4_offset)));
359 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_3, BPF_REG_10));
360 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, BF_PROG_CTX_OFF(l4)));
361 [ + - ]: 1372 : EMIT_KFUNC_CALL(program, "bpf_dynptr_slice");
362 : :
363 : : /* If the function call failed (e.g. the packet is too short), continue as
364 : : * if the L4 protocol was not supported: the rules and the chain policy
365 : : * still apply. */
366 : : {
367 : 2744 : _clean_bf_jmpctx_ struct bf_jmpctx _ =
368 [ + - ]: 1372 : bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 0));
369 : :
370 [ + - ]: 1372 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
371 [ + - ]: 1372 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
372 [ + - + - ]: 2744 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
373 [ + - ]: 1372 : EMIT(program,
374 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_error_counter_idx(program)));
375 [ + - ]: 1372 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
376 : :
377 [ - + ]: 1372 : if (bf_ctx_is_verbose(BF_VERBOSE_BPF))
378 [ # # # # : 0 : EMIT_PRINT(program, "failed to create L4 dynamic pointer slice");
# # # # ]
379 : :
380 : : /* No L4 protocol (r8 = 0) and no L4 header (r0 = NULL, the calls
381 : : * above overwrote r0). */
382 [ + - ]: 1372 : EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
383 [ + - ]: 1372 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, 0));
384 : : }
385 : :
386 : : // Store the L4 header address (NULL on failure) into the runtime context
387 : 1372 : EMIT(program,
388 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, BF_PROG_CTX_OFF(l4_hdr)));
389 : :
390 : : return 0;
391 : : }
392 : :
393 : 1295 : int bf_stub_rule_check_protocol(struct bf_program *program,
394 : : const struct bf_matcher_meta *meta)
395 : : {
396 : : assert(program);
397 : : assert(meta);
398 : :
399 [ + + - ]: 1295 : switch (meta->layer) {
400 : 835 : case BF_MATCHER_LAYER_3:
401 [ - + ]: 835 : EMIT_FIXUP_JMP_NEXT_RULE(
402 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7,
403 : : htobe16((uint16_t)meta->hdr_id), 0));
404 : 835 : break;
405 : 460 : case BF_MATCHER_LAYER_4:
406 [ - + ]: 460 : EMIT_FIXUP_JMP_NEXT_RULE(
407 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_8, (uint8_t)meta->hdr_id, 0));
408 : 460 : break;
409 : 0 : default:
410 [ # # ]: 0 : return bf_err_r(-EINVAL, "rule can't check for layer ID %d",
411 : : meta->layer);
412 : : }
413 : :
414 : : return 0;
415 : : }
416 : :
417 : 1995 : int bf_stub_load_header(struct bf_program *program,
418 : : const struct bf_matcher_meta *meta, int reg)
419 : : {
420 : : assert(program);
421 : : assert(meta);
422 : :
423 [ + + - ]: 1995 : switch (meta->layer) {
424 : 956 : case BF_MATCHER_LAYER_3:
425 : 956 : EMIT(program,
426 : : BPF_LDX_MEM(BPF_DW, reg, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
427 : : break;
428 : 1039 : case BF_MATCHER_LAYER_4:
429 : 1039 : EMIT(program,
430 : : BPF_LDX_MEM(BPF_DW, reg, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
431 : : break;
432 : 0 : default:
433 [ # # ]: 0 : return bf_err_r(-EINVAL,
434 : : "layer ID %d is not a valid layer to load header for",
435 : : meta->layer);
436 : : }
437 : :
438 : : return 0;
439 : : }
440 : :
441 : 372 : int bf_stub_load(struct bf_program *program, size_t src_offset, size_t size,
442 : : int dst_offset)
443 : : {
444 : : size_t src_off = src_offset;
445 : : int dst_off = dst_offset;
446 : : size_t remaining_size = size;
447 : :
448 : : assert(program);
449 : :
450 [ + + ]: 806 : while (remaining_size) {
451 : : int bpf_size = BPF_B;
452 : : size_t copy_bytes = 1;
453 : :
454 [ + + + + : 434 : if (BF_ALIGNED_64(src_off) && BF_ALIGNED_64(dst_off) &&
+ + ]
455 : : remaining_size >= 8) {
456 : : bpf_size = BPF_DW;
457 : : copy_bytes = 8;
458 [ + + + - : 316 : } else if (BF_ALIGNED_32(src_off) && BF_ALIGNED_32(dst_off) &&
+ + ]
459 : : remaining_size >= 4) {
460 : : bpf_size = BPF_W;
461 : : copy_bytes = 4;
462 [ + + - + : 195 : } else if (BF_ALIGNED_16(src_off) && BF_ALIGNED_16(dst_off) &&
+ + ]
463 : : remaining_size >= 2) {
464 : : bpf_size = BPF_H;
465 : : copy_bytes = 2;
466 : : }
467 : :
468 [ + - ]: 434 : EMIT(program, BPF_LDX_MEM(bpf_size, BPF_REG_1, BPF_REG_6, src_off));
469 [ + - ]: 434 : EMIT(program, BPF_STX_MEM(bpf_size, BPF_REG_10, BPF_REG_1, dst_off));
470 : :
471 : 434 : remaining_size -= copy_bytes;
472 : 434 : src_off += copy_bytes;
473 : 434 : dst_off += (int)copy_bytes;
474 : : }
475 : :
476 : : return 0;
477 : : }
478 : :
479 : 6 : int bf_stub_store(struct bf_program *program, int reg, size_t size,
480 : : int dst_offset)
481 : : {
482 : : int dst_off = dst_offset;
483 : : size_t remaining_size = size;
484 : :
485 : : assert(program);
486 : :
487 [ - + ]: 6 : if (size > 8)
488 [ # # ]: 0 : return bf_err_r(-E2BIG, "bf_stub_store copies at most 8 bytes");
489 : :
490 [ + - ]: 9 : while (remaining_size) {
491 : : int bpf_size = BPF_B;
492 : : size_t copy_bytes = 1;
493 : :
494 [ + + + - ]: 9 : if (BF_ALIGNED_64(dst_off) && remaining_size >= 8) {
495 : : bpf_size = BPF_DW;
496 : : copy_bytes = 8;
497 [ + + + + ]: 9 : } else if (BF_ALIGNED_32(dst_off) && remaining_size >= 4) {
498 : : bpf_size = BPF_W;
499 : : copy_bytes = 4;
500 [ + + + + ]: 5 : } else if (BF_ALIGNED_16(dst_off) && remaining_size >= 2) {
501 : : bpf_size = BPF_H;
502 : : copy_bytes = 2;
503 : : }
504 : :
505 [ + - ]: 9 : EMIT(program, BPF_STX_MEM(bpf_size, BPF_REG_10, reg, dst_off));
506 : :
507 : 9 : remaining_size -= copy_bytes;
508 : 9 : dst_off += (int)copy_bytes;
509 : :
510 [ + + ]: 9 : if (remaining_size)
511 [ + - ]: 3 : EMIT(program, BPF_ALU64_IMM(BPF_RSH, reg, copy_bytes * 8));
512 : : }
513 : :
514 : : return 0;
515 : : }
516 : :
517 : 301 : int bf_stub_stx_payload(struct bf_program *program,
518 : : const struct bf_matcher_meta *meta, size_t offset)
519 : : {
520 : : assert(program);
521 : : assert(meta);
522 : :
523 : 602 : return bf_stub_load(program, meta->hdr_payload_offset,
524 : 301 : meta->hdr_payload_size, BF_PROG_SCR_OFF(offset));
525 : : }
|