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/program.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : : #include <linux/limits.h>
11 : :
12 : : #include <errno.h>
13 : : #include <fcntl.h>
14 : : #include <limits.h>
15 : : #include <stddef.h>
16 : : #include <stdint.h>
17 : : #include <stdio.h>
18 : : #include <stdlib.h>
19 : : #include <string.h>
20 : : #include <unistd.h>
21 : :
22 : : #include <bpfilter/bpf.h>
23 : : #include <bpfilter/btf.h>
24 : : #include <bpfilter/chain.h>
25 : : #include <bpfilter/core/list.h>
26 : : #include <bpfilter/counter.h>
27 : : #include <bpfilter/ctx.h>
28 : : #include <bpfilter/dump.h>
29 : : #include <bpfilter/flavor.h>
30 : : #include <bpfilter/helper.h>
31 : : #include <bpfilter/hook.h>
32 : : #include <bpfilter/io.h>
33 : : #include <bpfilter/logger.h>
34 : : #include <bpfilter/matcher.h>
35 : : #include <bpfilter/pack.h>
36 : : #include <bpfilter/rule.h>
37 : : #include <bpfilter/set.h>
38 : : #include <bpfilter/verdict.h>
39 : :
40 : : #include "cgen/cgroup_skb.h"
41 : : #include "cgen/cgroup_sock_addr.h"
42 : : #include "cgen/dump.h"
43 : : #include "cgen/fixup.h"
44 : : #include "cgen/handle.h"
45 : : #include "cgen/jmp.h"
46 : : #include "cgen/nf.h"
47 : : #include "cgen/printer.h"
48 : : #include "cgen/prog/link.h"
49 : : #include "cgen/prog/map.h"
50 : : #include "cgen/stub.h"
51 : : #include "cgen/tc.h"
52 : : #include "cgen/xdp.h"
53 : : #include "filter.h"
54 : :
55 : : #define _BF_LOG_BUF_SIZE \
56 : : (UINT32_MAX >> 8) /* verifier maximum in kernels <= 5.1 */
57 : : #define _BF_LOG_MAP_N_ENTRIES 1000
58 : : #define _BF_LOG_MAP_SIZE \
59 : : _bf_round_next_power_of_2(sizeof(struct bf_log) * _BF_LOG_MAP_N_ENTRIES)
60 : : #define _BF_SET_MAP_PREFIX "bf_set_"
61 : : #define _BF_COUNTER_MAP_NAME "bf_cmap"
62 : : #define _BF_PRINTER_MAP_NAME "bf_pmap"
63 : : #define _BF_LOG_MAP_NAME "bf_lmap"
64 : :
65 : : static inline size_t _bf_round_next_power_of_2(size_t value)
66 : : {
67 : : if (value == 0)
68 : : return 1;
69 : :
70 : : value--;
71 : : value |= value >> 1;
72 : : value |= value >> 2;
73 : : value |= value >> 4;
74 : : value |= value >> 8;
75 : : value |= value >> 16;
76 : : #if SIZE_MAX > 0xFFFFFFFFU
77 : : value |= value >> 32;
78 : : #endif
79 : :
80 : : return ++value;
81 : : }
82 : :
83 : : static const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)
84 : : {
85 : : static const struct bf_flavor_ops *flavor_ops[] = {
86 : : [BF_FLAVOR_TC] = &bf_flavor_ops_tc,
87 : : [BF_FLAVOR_NF] = &bf_flavor_ops_nf,
88 : : [BF_FLAVOR_XDP] = &bf_flavor_ops_xdp,
89 : : [BF_FLAVOR_CGROUP_SKB] = &bf_flavor_ops_cgroup_skb,
90 : : [BF_FLAVOR_CGROUP_SOCK_ADDR] = &bf_flavor_ops_cgroup_sock_addr,
91 : : };
92 : :
93 : : static_assert_enum_mapping(flavor_ops, _BF_FLAVOR_MAX);
94 : :
95 : 1190 : return flavor_ops[flavor];
96 : : }
97 : :
98 : 1190 : int bf_program_new(struct bf_program **program, const struct bf_chain *chain,
99 : : struct bf_handle *handle)
100 : : {
101 : 1190 : _free_bf_program_ struct bf_program *_program = NULL;
102 : : int r;
103 : :
104 : : assert(program);
105 : : assert(chain);
106 : : assert(handle);
107 : :
108 : 1190 : _program = calloc(1, sizeof(*_program));
109 [ + - ]: 1190 : if (!_program)
110 : : return -ENOMEM;
111 : :
112 : 1190 : _program->flavor = bf_hook_to_flavor(chain->hook);
113 : 1190 : _program->runtime.ops = bf_flavor_ops_get(_program->flavor);
114 : 1190 : _program->runtime.chain = chain;
115 : 1190 : _program->img = bf_vector_default(sizeof(struct bpf_insn));
116 : 1190 : _program->fixups = bf_list_default(bf_fixup_free, NULL);
117 : 1190 : _program->handle = handle;
118 : :
119 : 1190 : r = bf_vector_reserve(&_program->img, 512);
120 [ + - ]: 1190 : if (r)
121 : : return r;
122 : :
123 : 1190 : r = bf_printer_new(&_program->printer);
124 [ + - ]: 1190 : if (r)
125 : : return r;
126 : :
127 : 1190 : *program = TAKE_PTR(_program);
128 : :
129 : 1190 : return 0;
130 : : }
131 : :
132 : 2380 : void bf_program_free(struct bf_program **program)
133 : : {
134 [ + + ]: 2380 : if (!*program)
135 : : return;
136 : :
137 : 1190 : bf_list_clean(&(*program)->fixups);
138 : 1190 : bf_vector_clean(&(*program)->img);
139 : :
140 : 1190 : bf_printer_free(&(*program)->printer);
141 : :
142 : 1190 : free(*program);
143 : 1190 : *program = NULL;
144 : : }
145 : :
146 : 0 : void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
147 : : {
148 : : assert(program);
149 : : assert(prefix);
150 : :
151 [ # # ]: 0 : DUMP(prefix, "struct bf_program at %p", program);
152 : :
153 : 0 : bf_dump_prefix_push(prefix);
154 : :
155 [ # # ]: 0 : DUMP(prefix, "handle: struct bf_handle *");
156 : 0 : bf_dump_prefix_push(prefix);
157 : 0 : bf_handle_dump(program->handle, bf_dump_prefix_last(prefix));
158 : 0 : bf_dump_prefix_pop(prefix);
159 : :
160 [ # # ]: 0 : DUMP(prefix, "printer: struct bf_printer *");
161 : 0 : bf_dump_prefix_push(prefix);
162 : 0 : bf_printer_dump(program->printer, prefix);
163 : 0 : bf_dump_prefix_pop(prefix);
164 : :
165 [ # # ]: 0 : DUMP(prefix, "img: %p", program->img.data);
166 [ # # ]: 0 : DUMP(prefix, "img.size: %lu", program->img.size);
167 [ # # ]: 0 : DUMP(prefix, "img.cap: %lu", program->img.cap);
168 : :
169 [ # # ]: 0 : DUMP(prefix, "fixups: bf_list<struct bf_fixup>[%lu]",
170 : : bf_list_size(&program->fixups));
171 : 0 : bf_dump_prefix_push(prefix);
172 [ # # # # : 0 : bf_list_foreach (&program->fixups, fixup_node) {
# # ]
173 : : struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
174 : :
175 [ # # ]: 0 : if (bf_list_is_tail(&program->fixups, fixup_node))
176 : 0 : bf_dump_prefix_last(prefix);
177 : :
178 : 0 : bf_fixup_dump(fixup, prefix);
179 : : }
180 : 0 : bf_dump_prefix_pop(prefix);
181 : :
182 [ # # ]: 0 : DUMP(bf_dump_prefix_last(prefix), "runtime: <anonymous>");
183 : 0 : bf_dump_prefix_push(prefix);
184 [ # # ]: 0 : DUMP(bf_dump_prefix_last(prefix), "ops: %p", program->runtime.ops);
185 : 0 : bf_dump_prefix_pop(prefix);
186 : :
187 : 0 : bf_dump_prefix_pop(prefix);
188 : 0 : }
189 : :
190 : 19965 : static void _bf_program_fixup_insn(struct bpf_insn *insn,
191 : : enum bf_fixup_insn type, int32_t value)
192 : : {
193 [ + + - ]: 19965 : switch (type) {
194 : 4551 : case BF_FIXUP_INSN_OFF:
195 : : assert(!insn->off);
196 : : assert(value < SHRT_MAX);
197 : 4551 : insn->off = (int16_t)value;
198 : 4551 : break;
199 : 15414 : case BF_FIXUP_INSN_IMM:
200 : : assert(!insn->imm);
201 : 15414 : insn->imm = value;
202 : 15414 : break;
203 : 0 : default:
204 [ # # ]: 0 : bf_abort(
205 : : "unsupported fixup instruction type, this should not happen: %d",
206 : : type);
207 : : break;
208 : : }
209 : 19965 : }
210 : :
211 : 6218 : static int _bf_program_fixup(struct bf_program *program,
212 : : enum bf_fixup_type type)
213 : : {
214 : : assert(program);
215 : : assert(type >= 0 && type < _BF_FIXUP_TYPE_MAX);
216 : :
217 [ + - + + : 129796 : bf_list_foreach (&program->fixups, fixup_node) {
+ + ]
218 : : enum bf_fixup_insn insn_type = _BF_FIXUP_INSN_MAX;
219 : : int32_t value;
220 : : size_t offset;
221 : : struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
222 : : struct bpf_insn *insn;
223 : : struct bf_map *map;
224 : :
225 [ + + ]: 58680 : if (type != fixup->type)
226 : 38715 : continue;
227 : :
228 : 19965 : insn = bf_vector_get(&program->img, fixup->insn);
229 [ - + ]: 19965 : if (!insn) {
230 [ # # ]: 0 : return bf_err_r(-EINVAL,
231 : : "fixup references invalid instruction index %lu",
232 : : fixup->insn);
233 : : }
234 : :
235 [ + + + + : 19965 : switch (type) {
+ + - ]
236 : 4551 : case BF_FIXUP_TYPE_JMP_NEXT_RULE:
237 : : insn_type = BF_FIXUP_INSN_OFF;
238 : 4551 : value = (int)(program->img.size - fixup->insn - 1U);
239 : 4551 : break;
240 : 6356 : case BF_FIXUP_TYPE_COUNTERS_MAP_FD:
241 : : insn_type = BF_FIXUP_INSN_IMM;
242 : 6356 : value = program->handle->cmap->fd;
243 : 6356 : break;
244 : 1211 : case BF_FIXUP_TYPE_PRINTER_MAP_FD:
245 : : insn_type = BF_FIXUP_INSN_IMM;
246 : 1211 : value = program->handle->pmap->fd;
247 : 1211 : break;
248 : 24 : case BF_FIXUP_TYPE_LOG_MAP_FD:
249 : : insn_type = BF_FIXUP_INSN_IMM;
250 : 24 : value = program->handle->lmap->fd;
251 : 24 : break;
252 : 282 : case BF_FIXUP_TYPE_SET_MAP_FD:
253 : 282 : map = bf_list_get_at(&program->handle->sets, fixup->attr.set_index);
254 [ - + ]: 282 : if (!map) {
255 [ # # ]: 0 : return bf_err_r(-ENOENT, "can't find set map at index %lu",
256 : : fixup->attr.set_index);
257 : : }
258 : : insn_type = BF_FIXUP_INSN_IMM;
259 : 282 : value = map->fd;
260 : 282 : break;
261 : 7541 : case BF_FIXUP_ELFSTUB_CALL:
262 : : insn_type = BF_FIXUP_INSN_IMM;
263 : 7541 : offset = program->elfstubs_location[fixup->attr.elfstub_id] -
264 : 7541 : fixup->insn - 1;
265 [ - + ]: 7541 : if (offset >= INT_MAX)
266 [ # # ]: 0 : return bf_err_r(-EINVAL, "invalid ELF stub call offset");
267 : 7541 : value = (int32_t)offset;
268 : 7541 : break;
269 : 0 : default:
270 [ # # ]: 0 : bf_abort("unsupported fixup type, this should not happen: %d",
271 : : type);
272 : : break;
273 : : }
274 : :
275 : 19965 : _bf_program_fixup_insn(insn, insn_type, value);
276 : 19965 : bf_list_delete(&program->fixups, fixup_node);
277 : : }
278 : :
279 : : return 0;
280 : : }
281 : :
282 : 1452 : static int _bf_program_generate_rule(struct bf_program *program,
283 : : struct bf_rule *rule)
284 : : {
285 : : uint32_t checked_layers = 0;
286 : : int ret_code;
287 : : int r;
288 : :
289 : : assert(program);
290 : : assert(rule);
291 : : assert(program->runtime.ops->gen_inline_matcher);
292 : : assert(program->runtime.ops->gen_inline_log);
293 : :
294 [ + + ]: 1452 : if (rule->disabled)
295 : : return 0;
296 : :
297 [ + - + + : 8212 : bf_list_foreach (&rule->matchers, matcher_node) {
+ + ]
298 : : struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
299 : : const struct bf_matcher_meta *meta =
300 : 2657 : bf_matcher_get_meta(bf_matcher_get_type(matcher));
301 : :
302 [ + + ]: 2657 : if (bf_matcher_get_type(matcher) == BF_MATCHER_SET)
303 : 282 : continue;
304 : :
305 [ - + ]: 2375 : if (!meta) {
306 [ # # ]: 0 : return bf_err_r(-EINVAL, "missing meta for matcher type %d",
307 : : bf_matcher_get_type(matcher));
308 : : }
309 : :
310 [ + + ]: 2375 : if (checked_layers & BF_FLAG(meta->layer))
311 : 834 : continue;
312 : :
313 : 1541 : if (meta->layer == BF_MATCHER_LAYER_2 ||
314 [ + + ]: 1541 : meta->layer == BF_MATCHER_LAYER_3 ||
315 : : meta->layer == BF_MATCHER_LAYER_4) {
316 : 924 : r = bf_stub_rule_check_protocol(program, meta);
317 [ + - ]: 924 : if (r)
318 : : return r;
319 : 924 : checked_layers |= BF_FLAG(meta->layer);
320 : : }
321 : : }
322 : :
323 [ + - + + : 8212 : bf_list_foreach (&rule->matchers, matcher_node) {
+ + ]
324 : : struct bf_matcher *matcher = bf_list_node_get_data(matcher_node);
325 : :
326 : 2657 : r = program->runtime.ops->gen_inline_matcher(program, matcher);
327 [ + - ]: 2657 : if (r)
328 : : return r;
329 : : }
330 : :
331 [ + + ]: 1449 : if (bf_rule_mark_is_set(rule)) {
332 [ - + ]: 10 : if (!program->runtime.ops->gen_inline_set_mark) {
333 [ # # ]: 0 : return bf_err_r(-ENOTSUP, "set mark is not supported by %s",
334 : : program->runtime.chain->name);
335 : : }
336 : :
337 : 10 : r = program->runtime.ops->gen_inline_set_mark(program,
338 : : bf_rule_mark_get(rule));
339 [ - + ]: 10 : if (r) {
340 [ # # ]: 0 : return bf_err_r(r,
341 : : "failed to generate bytecode to set mark for '%s'",
342 : : program->runtime.chain->name);
343 : : }
344 : : }
345 : :
346 [ + + ]: 1449 : if (rule->log) {
347 : 33 : r = program->runtime.ops->gen_inline_log(program, rule);
348 [ + - ]: 33 : if (r)
349 : : return r;
350 : : }
351 : :
352 [ + + ]: 1449 : if (rule->counters) {
353 [ + - ]: 1353 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
354 [ + - ]: 1353 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
355 [ + - + - ]: 2706 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
356 [ + - ]: 1353 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3, rule->index));
357 [ + - ]: 1353 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
358 : : }
359 : :
360 [ + + - + ]: 1449 : switch (rule->verdict) {
361 : 1397 : case BF_VERDICT_ACCEPT:
362 : : case BF_VERDICT_DROP:
363 : : case BF_VERDICT_NEXT:
364 : 1397 : r = program->runtime.ops->get_verdict(rule->verdict, &ret_code);
365 [ + - ]: 1397 : if (r)
366 : : return r;
367 [ + - ]: 1397 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
368 [ + - ]: 1397 : EMIT(program, BPF_EXIT_INSN());
369 : : break;
370 : 12 : case BF_VERDICT_REDIRECT:
371 [ + + ]: 12 : if (!program->runtime.ops->gen_inline_redirect) {
372 [ + - ]: 2 : return bf_err_r(-ENOTSUP, "redirect is not supported by %s hook",
373 : : bf_hook_to_str(program->runtime.chain->hook));
374 : : }
375 : 10 : r = program->runtime.ops->gen_inline_redirect(
376 : : program, rule->redirect_ifindex, rule->redirect_dir);
377 [ + + ]: 10 : if (r)
378 : : return r;
379 : : break;
380 : : case BF_VERDICT_CONTINUE:
381 : : // Fall through to next rule or default chain policy.
382 : : break;
383 : 0 : default:
384 [ # # ]: 0 : bf_abort("unsupported verdict, this should not happen: %d",
385 : : rule->verdict);
386 : : break;
387 : : }
388 : :
389 : 1446 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_JMP_NEXT_RULE);
390 [ + - ]: 1446 : if (r)
391 [ # # ]: 0 : return bf_err_r(r, "failed to generate next rule fixups");
392 : :
393 : : return 0;
394 : : }
395 : :
396 : 1187 : static int _bf_program_generate_elfstubs(struct bf_program *program)
397 : : {
398 : : const struct bf_elfstub *elfstub;
399 : : size_t start_at;
400 : : int r;
401 : :
402 : : assert(program);
403 : :
404 [ + - + + : 33106 : bf_list_foreach (&program->fixups, fixup_node) {
+ + ]
405 : : struct bf_fixup *fixup = bf_list_node_get_data(fixup_node);
406 : 15366 : size_t off = program->img.size;
407 : :
408 [ + + ]: 15366 : if (fixup->type != BF_FIXUP_ELFSTUB_CALL)
409 : 7825 : continue;
410 : :
411 : : // Only generate each ELF stub once
412 [ + + ]: 7541 : if (program->elfstubs_location[fixup->attr.elfstub_id])
413 : 5178 : continue;
414 : :
415 [ - + ]: 2363 : bf_dbg("generate ELF stub for ID %d", fixup->attr.elfstub_id);
416 : :
417 : 2363 : elfstub = bf_ctx_get_elfstub(fixup->attr.elfstub_id);
418 [ - + ]: 2363 : if (!elfstub) {
419 [ # # ]: 0 : return bf_err_r(-ENOENT, "no ELF stub found for ID %d",
420 : : fixup->attr.elfstub_id);
421 : : }
422 : :
423 : 2363 : start_at = program->img.size;
424 : :
425 [ + + ]: 89340 : for (size_t i = 0; i < elfstub->ninsns; ++i) {
426 : 86977 : r = bf_program_emit(program, elfstub->insns[i]);
427 [ - + ]: 86977 : if (r)
428 [ # # ]: 0 : return bf_err_r(r, "failed to insert ELF stub instruction");
429 : : }
430 : :
431 [ + + - + : 7148 : bf_list_foreach (&elfstub->strs, pstr_node) {
+ + ]
432 : 1211 : _free_bf_fixup_ struct bf_fixup *fixup = NULL;
433 : : struct bf_printk_str *pstr = bf_list_node_get_data(pstr_node);
434 : 1211 : size_t insn_idx = start_at + pstr->insn_idx;
435 : : const struct bf_printer_msg *msg =
436 : 1211 : bf_printer_add_msg(program->printer, pstr->str);
437 : 1211 : struct bpf_insn ld_insn[2] = {
438 : : BPF_LD_MAP_FD(BPF_REG_1, 0),
439 : : };
440 : :
441 : 1211 : ld_insn[0].src_reg = BPF_PSEUDO_MAP_VALUE;
442 : 1211 : ld_insn[1].imm = (int)bf_printer_msg_offset(msg);
443 : :
444 : 1211 : r = bf_vector_set(&program->img, insn_idx, &ld_insn[0]);
445 [ - + ]: 1211 : if (r) {
446 [ # # ]: 0 : return bf_err_r(
447 : : r, "failed to set ELF stub instruction at index %lu",
448 : : insn_idx);
449 : : }
450 : 1211 : r = bf_vector_set(&program->img, insn_idx + 1, &ld_insn[1]);
451 [ - + ]: 1211 : if (r) {
452 [ # # ]: 0 : return bf_err_r(
453 : : r, "failed to set ELF stub instruction at index %lu",
454 : : insn_idx + 1);
455 : : }
456 : :
457 : 1211 : r = bf_fixup_new(&fixup, BF_FIXUP_TYPE_PRINTER_MAP_FD, insn_idx,
458 : : NULL);
459 [ + - ]: 1211 : if (r)
460 : : return r;
461 : :
462 : 1211 : r = bf_list_add_tail(&program->fixups, fixup);
463 [ + - ]: 1211 : if (r)
464 : : return r;
465 : :
466 : 1211 : TAKE_PTR(fixup);
467 : : }
468 : :
469 : 2363 : program->elfstubs_location[fixup->attr.elfstub_id] = off;
470 : : }
471 : :
472 : : return 0;
473 : : }
474 : :
475 : 3826 : int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
476 : : {
477 : : int r;
478 : :
479 : : assert(program);
480 : : assert(name);
481 : :
482 : 3826 : r = bf_btf_get_id(name);
483 [ + - ]: 3826 : if (r < 0)
484 : : return r;
485 : :
486 : 3826 : EMIT(program, ((struct bpf_insn) {.code = BPF_JMP | BPF_CALL,
487 : : .dst_reg = 0,
488 : : .src_reg = BPF_PSEUDO_KFUNC_CALL,
489 : : .off = 0,
490 : : .imm = r}));
491 : :
492 : : return 0;
493 : : }
494 : :
495 : 11229 : int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type,
496 : : struct bpf_insn insn, const union bf_fixup_attr *attr)
497 : : {
498 : 22458 : _free_bf_fixup_ struct bf_fixup *fixup = NULL;
499 : : int r;
500 : :
501 : : assert(program);
502 : :
503 [ + - ]: 11229 : EMIT(program, insn);
504 : :
505 : 11229 : r = bf_fixup_new(&fixup, type, program->img.size - 1, attr);
506 [ + - ]: 11229 : if (r)
507 : : return r;
508 : :
509 : 11229 : r = bf_list_add_tail(&program->fixups, fixup);
510 [ + - ]: 11229 : if (r)
511 : : return r;
512 : :
513 : 11229 : TAKE_PTR(fixup);
514 : :
515 : 11229 : return 0;
516 : : }
517 : :
518 : 7554 : int bf_program_emit_fixup_elfstub(struct bf_program *program,
519 : : enum bf_elfstub_id id)
520 : : {
521 : 15108 : _free_bf_fixup_ struct bf_fixup *fixup = NULL;
522 : : int r;
523 : :
524 : : assert(program);
525 : :
526 [ + - ]: 7554 : EMIT(program, BPF_CALL_REL(0));
527 : :
528 : 7554 : r = bf_fixup_new(&fixup, BF_FIXUP_ELFSTUB_CALL, program->img.size - 1,
529 : : NULL);
530 [ + - ]: 7554 : if (r)
531 : : return r;
532 : :
533 : 7554 : fixup->attr.elfstub_id = id;
534 : :
535 : 7554 : r = bf_list_add_tail(&program->fixups, fixup);
536 [ + - ]: 7554 : if (r)
537 : : return r;
538 : :
539 : 7554 : TAKE_PTR(fixup);
540 : :
541 : 7554 : return 0;
542 : : }
543 : :
544 : 1190 : int bf_program_generate(struct bf_program *program)
545 : : {
546 : 1190 : const struct bf_chain *chain = program->runtime.chain;
547 : : int ret_code;
548 : : int r;
549 : :
550 : : // Save the program's argument into the context.
551 [ + - ]: 1190 : EMIT(program,
552 : : BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
553 : :
554 : : // Reset the protocol ID registers
555 [ + - ]: 1190 : EMIT(program, BPF_MOV64_IMM(BPF_REG_7, 0));
556 [ + - ]: 1190 : EMIT(program, BPF_MOV64_IMM(BPF_REG_8, 0));
557 : :
558 : : // If at least one rule logs the matched packets, populate ctx->log_map
559 [ + + ]: 1190 : if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) {
560 [ + - + - ]: 48 : EMIT_LOAD_LOG_FD_FIXUP(program, BPF_REG_2);
561 [ + - ]: 24 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2,
562 : : BF_PROG_CTX_OFF(log_map)));
563 : : }
564 : :
565 : : // Zeroing IPv6 extension headers
566 [ + + ]: 1190 : if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_STORE_NEXTHDR)) {
567 [ + - ]: 30 : EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7,
568 : : BF_PROG_CTX_OFF(ipv6_eh)));
569 : : }
570 : :
571 : 1190 : r = program->runtime.ops->gen_inline_prologue(program);
572 [ + - ]: 1190 : if (r)
573 : : return r;
574 : :
575 [ + + + + : 5278 : bf_list_foreach (&chain->rules, rule_node) {
+ + ]
576 : 1452 : r = _bf_program_generate_rule(program,
577 : : bf_list_node_get_data(rule_node));
578 [ + + ]: 1452 : if (r)
579 : : return r;
580 : : }
581 : :
582 : 1187 : r = program->runtime.ops->gen_inline_epilogue(program);
583 [ + - ]: 1187 : if (r)
584 : : return r;
585 : :
586 : : // Call the update counters function
587 : : /// @todo Allow chains to have no counters at all.
588 [ + - ]: 1187 : EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10));
589 [ + - ]: 1187 : EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg)));
590 [ + - + - ]: 2374 : EMIT_LOAD_COUNTERS_FD_FIXUP(program, BPF_REG_2);
591 [ + - ]: 1187 : EMIT(program,
592 : : BPF_MOV32_IMM(BPF_REG_3, bf_program_chain_counter_idx(program)));
593 [ + - ]: 1187 : EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_UPDATE_COUNTERS);
594 : :
595 : 1187 : r = program->runtime.ops->get_verdict(chain->policy, &ret_code);
596 [ + - ]: 1187 : if (r)
597 : : return r;
598 [ + - ]: 1187 : EMIT(program, BPF_MOV64_IMM(BPF_REG_0, ret_code));
599 [ + - ]: 1187 : EMIT(program, BPF_EXIT_INSN());
600 : :
601 : 1187 : r = _bf_program_generate_elfstubs(program);
602 [ + - ]: 1187 : if (r)
603 : : return r;
604 : :
605 : 1187 : r = _bf_program_fixup(program, BF_FIXUP_ELFSTUB_CALL);
606 [ - + ]: 1187 : if (r)
607 [ # # ]: 0 : return bf_err_r(r, "failed to generate ELF stub call fixups");
608 : :
609 : : return 0;
610 : : }
611 : :
612 : 1187 : static int _bf_program_load_printer_map(struct bf_program *program)
613 : : {
614 : 1187 : _cleanup_free_ void *pstr = NULL;
615 : : size_t pstr_len;
616 : 1187 : uint32_t key = 0;
617 : : int r;
618 : :
619 : : assert(program);
620 : :
621 : 1187 : r = bf_printer_assemble(program->printer, &pstr, &pstr_len);
622 [ - + ]: 1187 : if (r)
623 [ # # ]: 0 : return bf_err_r(r, "failed to assemble printer map string");
624 : :
625 : 1187 : r = bf_map_new(&program->handle->pmap, _BF_PRINTER_MAP_NAME,
626 : : BF_MAP_TYPE_PRINTER, sizeof(uint32_t), pstr_len, 1);
627 [ - + ]: 1187 : if (r)
628 [ # # ]: 0 : return bf_err_r(r, "failed to create the printer bf_map object");
629 : :
630 : 1187 : r = bf_map_set_elem(program->handle->pmap, &key, pstr);
631 [ - + ]: 1187 : if (r)
632 [ # # ]: 0 : return bf_err_r(r, "failed to set print map elem");
633 : :
634 : 1187 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_PRINTER_MAP_FD);
635 [ - + ]: 1187 : if (r)
636 [ # # ]: 0 : return bf_err_r(r, "failed to fixup printer map FD");
637 : :
638 : : return 0;
639 : : }
640 : :
641 : 1187 : static int _bf_program_load_counters_map(struct bf_program *program)
642 : : {
643 : : int r;
644 : :
645 : : assert(program);
646 : :
647 : 1187 : r = bf_map_new(&program->handle->cmap, _BF_COUNTER_MAP_NAME,
648 : : BF_MAP_TYPE_COUNTERS, sizeof(uint32_t),
649 : : sizeof(struct bf_counter),
650 : 1187 : bf_list_size(&program->runtime.chain->rules) + 2);
651 [ - + ]: 1187 : if (r)
652 [ # # ]: 0 : return bf_err_r(r, "failed to create the counters bf_map object");
653 : :
654 : 1187 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_COUNTERS_MAP_FD);
655 [ - + ]: 1187 : if (r)
656 [ # # ]: 0 : return bf_err_r(r, "failed to fixup counters map FD");
657 : :
658 : : return 0;
659 : : }
660 : :
661 : 1187 : static int _bf_program_load_log_map(struct bf_program *program)
662 : : {
663 : : int r;
664 : :
665 : : assert(program);
666 : :
667 : : // Do not create a log map if it's unused in the chain
668 [ + + ]: 1187 : if (!(program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)))
669 : : return 0;
670 : :
671 : 24 : r = bf_map_new(&program->handle->lmap, _BF_LOG_MAP_NAME, BF_MAP_TYPE_LOG, 0,
672 : : 0, _BF_LOG_MAP_SIZE);
673 [ - + ]: 24 : if (r)
674 [ # # ]: 0 : return bf_err_r(r, "failed to create the log bf_map object");
675 : :
676 : 24 : r = _bf_program_fixup(program, BF_FIXUP_TYPE_LOG_MAP_FD);
677 [ + - ]: 24 : if (r)
678 [ # # ]: 0 : return bf_err_r(r, "failed to fixup log map FD");
679 : :
680 : : return 0;
681 : : }
682 : :
683 : 1187 : static int _bf_program_load_sets_maps(struct bf_program *new_prog)
684 : : {
685 : : char name[BPF_OBJ_NAME_LEN];
686 : : size_t set_idx = 0;
687 : : int r;
688 : :
689 : : assert(new_prog);
690 : :
691 [ + + + + : 2946 : bf_list_foreach (&new_prog->runtime.chain->sets, set_node) {
+ + ]
692 : : struct bf_set *set = bf_list_node_get_data(set_node);
693 [ + + ]: 568 : _free_bf_map_ struct bf_map *map = NULL;
694 : : _cleanup_free_ uint8_t *values = NULL;
695 : : _cleanup_free_ uint8_t *keys = NULL;
696 : : size_t nelems = bf_list_size(&set->elems);
697 : : size_t idx = 0;
698 : :
699 [ + + ]: 290 : if (!nelems) {
700 : 4 : r = bf_list_add_tail(&new_prog->handle->sets, NULL);
701 [ + - ]: 4 : if (r)
702 : : return r;
703 : : continue;
704 : : }
705 : :
706 : 282 : (void)snprintf(name, BPF_OBJ_NAME_LEN, _BF_SET_MAP_PREFIX "%04x",
707 : 282 : (uint8_t)set_idx++);
708 : 282 : r = bf_map_new_from_set(&map, name, set);
709 [ + - ]: 282 : if (r)
710 : : return r;
711 : :
712 : 282 : values = malloc(nelems);
713 [ - + ]: 282 : if (!values)
714 [ # # ]: 0 : return bf_err_r(-errno, "failed to allocate map values");
715 : :
716 : 282 : keys = malloc(set->elem_size * nelems);
717 [ - + ]: 282 : if (!keys)
718 [ # # ]: 0 : return bf_err_r(errno, "failed to allocate map keys");
719 : :
720 [ + - + + ]: 1512 : bf_list_foreach (&set->elems, elem_node) {
721 : : void *elem = bf_list_node_get_data(elem_node);
722 : :
723 : 615 : memcpy(keys + (idx * set->elem_size), elem, set->elem_size);
724 : 615 : values[idx] = 1;
725 [ + + ]: 615 : ++idx;
726 : : }
727 : :
728 : 282 : r = bf_bpf_map_update_batch(map->fd, keys, values, nelems, BPF_ANY);
729 [ - + ]: 282 : if (r)
730 [ # # ]: 0 : return bf_err_r(r, "failed to add set elements to the map");
731 : :
732 : 282 : r = bf_list_push(&new_prog->handle->sets, (void **)&map);
733 [ + - ]: 282 : if (r)
734 : : return r;
735 : : };
736 : :
737 : 1187 : r = _bf_program_fixup(new_prog, BF_FIXUP_TYPE_SET_MAP_FD);
738 : : if (r)
739 : : return r;
740 : :
741 : : return 0;
742 : : }
743 : :
744 : 1187 : int bf_program_load(struct bf_program *prog)
745 : : {
746 : : _cleanup_free_ char *log_buf = NULL;
747 : : int r;
748 : :
749 : : assert(prog);
750 : :
751 : 1187 : r = _bf_program_load_sets_maps(prog);
752 [ - + ]: 1187 : if (r)
753 [ # # ]: 0 : return bf_err_r(r, "failed to load the sets map");
754 : :
755 : 1187 : r = _bf_program_load_counters_map(prog);
756 [ - + ]: 1187 : if (r)
757 [ # # ]: 0 : return bf_err_r(r, "failed to load the counter map");
758 : :
759 : 1187 : r = _bf_program_load_printer_map(prog);
760 [ - + ]: 1187 : if (r)
761 [ # # ]: 0 : return bf_err_r(r, "failed to load the printer map");
762 : :
763 : 1187 : r = _bf_program_load_log_map(prog);
764 [ - + ]: 1187 : if (r)
765 [ # # ]: 0 : return bf_err_r(r, "failed to load the log map");
766 : :
767 [ - + ]: 1187 : if (bf_ctx_is_verbose(BF_VERBOSE_DEBUG)) {
768 : 0 : log_buf = malloc(_BF_LOG_BUF_SIZE);
769 [ # # ]: 0 : if (!log_buf) {
770 [ # # ]: 0 : return bf_err_r(-ENOMEM,
771 : : "failed to allocate BPF_PROG_LOAD logs buffer");
772 : : }
773 : : }
774 : :
775 [ - + ]: 1187 : if (bf_ctx_is_verbose(BF_VERBOSE_BYTECODE))
776 : 0 : bf_program_dump_bytecode(prog);
777 : :
778 [ + - ]: 2374 : r = bf_bpf_prog_load(prog->handle->prog_name,
779 : 1187 : bf_hook_to_bpf_prog_type(prog->runtime.chain->hook),
780 : : prog->img.data, prog->img.size,
781 : 1187 : bf_hook_to_bpf_attach_type(prog->runtime.chain->hook),
782 : : log_buf, log_buf ? _BF_LOG_BUF_SIZE : 0,
783 : 1187 : bf_ctx_token(), &prog->handle->prog_fd);
784 [ - + ]: 1187 : if (r) {
785 [ # # # # ]: 0 : return bf_err_r(r, "failed to load bf_program (%lu insns):\n%s\nerrno:",
786 : : prog->img.size, log_buf ? log_buf : "<NO LOG BUFFER>");
787 : : }
788 : :
789 : : return r;
790 : : }
791 : :
792 : 0 : int bf_program_get_counter(const struct bf_program *program,
793 : : uint32_t counter_idx, struct bf_counter *counter)
794 : : {
795 : : assert(program);
796 : : assert(counter);
797 : :
798 : 0 : return bf_handle_get_counter(program->handle, counter_idx, counter);
799 : : }
800 : :
801 : 0 : int bf_cgen_set_counters(struct bf_program *program,
802 : : const struct bf_counter *counters)
803 : : {
804 : : (void)program;
805 : : (void)counters;
806 : :
807 : 0 : return -ENOTSUP;
808 : : }
809 : :
810 : 1187 : size_t bf_program_chain_counter_idx(const struct bf_program *program)
811 : : {
812 : 1187 : return bf_list_size(&program->runtime.chain->rules);
813 : : }
814 : :
815 : 3826 : size_t bf_program_error_counter_idx(const struct bf_program *program)
816 : : {
817 : 3826 : return bf_list_size(&program->runtime.chain->rules) + 1;
818 : : }
|