Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "cgen/matcher/tcp.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : : #include <linux/in.h> // NOLINT
11 : : #include <linux/tcp.h>
12 : :
13 : : #include <endian.h>
14 : : #include <errno.h>
15 : : #include <stddef.h>
16 : : #include <stdint.h>
17 : :
18 : : #include <bpfilter/logger.h>
19 : : #include <bpfilter/matcher.h>
20 : :
21 : : #include "cgen/program.h"
22 : : #include "filter.h"
23 : :
24 : 160 : static int _bf_matcher_generate_tcp_port(struct bf_program *program,
25 : : const struct bf_matcher *matcher)
26 : : {
27 : 160 : uint16_t *port = (uint16_t *)bf_matcher_payload(matcher);
28 : 160 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_TCP_SPORT ?
29 [ + + ]: 160 : offsetof(struct tcphdr, source) :
30 : : offsetof(struct tcphdr, dest);
31 : :
32 [ - + ]: 160 : EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_6, offset));
33 : :
34 [ + + + - ]: 160 : switch (bf_matcher_get_op(matcher)) {
35 : 60 : case BF_MATCHER_EQ:
36 [ - + ]: 60 : EMIT_FIXUP_JMP_NEXT_RULE(program,
37 : : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, *port, 0));
38 : 60 : break;
39 : 60 : case BF_MATCHER_NE:
40 [ - + ]: 60 : EMIT_FIXUP_JMP_NEXT_RULE(program,
41 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, *port, 0));
42 : 60 : break;
43 : 40 : case BF_MATCHER_RANGE:
44 : : /* Convert the big-endian value stored in the packet into a
45 : : * little-endian value for x86 and arm before comparing it to the
46 : : * reference value. This is a JLT/JGT comparison, we need to have the
47 : : * MSB where the machine expects then. */
48 [ - + ]: 40 : EMIT(program, BPF_BSWAP(BPF_REG_1, 16));
49 [ - + ]: 40 : EMIT_FIXUP_JMP_NEXT_RULE(program,
50 : : BPF_JMP_IMM(BPF_JLT, BPF_REG_1, port[0], 0));
51 [ - + ]: 40 : EMIT_FIXUP_JMP_NEXT_RULE(program,
52 : : BPF_JMP_IMM(BPF_JGT, BPF_REG_1, port[1], 0));
53 : 40 : break;
54 : 0 : default:
55 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown matcher operator '%s' (%d)",
56 : : bf_matcher_op_to_str(bf_matcher_get_op(matcher)),
57 : : bf_matcher_get_op(matcher));
58 : : }
59 : :
60 : : return 0;
61 : : }
62 : :
63 : 100 : static int _bf_matcher_generate_tcp_flags(struct bf_program *program,
64 : : const struct bf_matcher *matcher)
65 : : {
66 : 100 : uint8_t flags = *(uint8_t *)bf_matcher_payload(matcher);
67 : :
68 [ - + ]: 100 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6, 13));
69 : :
70 [ + + + + : 100 : switch (bf_matcher_get_op(matcher)) {
- ]
71 : 20 : case BF_MATCHER_EQ:
72 [ - + ]: 20 : EMIT_FIXUP_JMP_NEXT_RULE(program,
73 : : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, flags, 0));
74 : 20 : break;
75 : 20 : case BF_MATCHER_NE:
76 [ - + ]: 20 : EMIT_FIXUP_JMP_NEXT_RULE(program,
77 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, flags, 0));
78 : 20 : break;
79 : 30 : case BF_MATCHER_ANY:
80 [ - + ]: 30 : EMIT(program, BPF_ALU32_IMM(BPF_AND, BPF_REG_1, flags));
81 [ - + ]: 30 : EMIT_FIXUP_JMP_NEXT_RULE(program,
82 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0));
83 : 30 : break;
84 : 30 : case BF_MATCHER_ALL:
85 [ - + ]: 30 : EMIT(program, BPF_ALU32_IMM(BPF_AND, BPF_REG_1, flags));
86 [ - + ]: 30 : EMIT_FIXUP_JMP_NEXT_RULE(program,
87 : : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, flags, 0));
88 : 30 : break;
89 : 0 : default:
90 [ # # ]: 0 : return bf_err_r(-EINVAL, "unsupported matcher for tcp.flags: %s",
91 : : bf_matcher_op_to_str(bf_matcher_get_op(matcher)));
92 : : }
93 : :
94 : : return 0;
95 : : }
96 : :
97 : 260 : int bf_matcher_generate_tcp(struct bf_program *program,
98 : : const struct bf_matcher *matcher)
99 : : {
100 : : int r;
101 : :
102 [ - + ]: 260 : EMIT_FIXUP_JMP_NEXT_RULE(program,
103 : : BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_TCP, 0));
104 [ - + ]: 260 : EMIT(program,
105 : : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
106 : :
107 [ + + - ]: 260 : switch (bf_matcher_get_type(matcher)) {
108 : 160 : case BF_MATCHER_TCP_SPORT:
109 : : case BF_MATCHER_TCP_DPORT:
110 : 160 : r = _bf_matcher_generate_tcp_port(program, matcher);
111 : 160 : break;
112 : 100 : case BF_MATCHER_TCP_FLAGS:
113 : 100 : r = _bf_matcher_generate_tcp_flags(program, matcher);
114 : 100 : break;
115 : 0 : default:
116 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown matcher type %d",
117 : : bf_matcher_get_type(matcher));
118 : : };
119 : :
120 : : return r;
121 : : }
|