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 "bpfilter/cgen/matcher/ip6.h"
7 :
8 : #include <linux/bpf.h>
9 : #include <linux/bpf_common.h>
10 : #include <linux/if_ether.h>
11 : #include <linux/ipv6.h>
12 :
13 : #include <endian.h>
14 : #include <errno.h>
15 : #include <stddef.h>
16 : #include <stdint.h>
17 :
18 : #include "bpfilter/cgen/jmp.h"
19 : #include "bpfilter/cgen/program.h"
20 : #include "core/logger.h"
21 : #include "core/matcher.h"
22 :
23 : #include "external/filter.h"
24 :
25 : #define _bf_make32(a, b, c, d) \
26 : (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(c) << 8) | \
27 : (uint32_t)(d))
28 : #define _BF_MASK_LAST_BYTE 15
29 :
30 0 : static int _bf_matcher_generate_ip6_addr(struct bf_program *program,
31 : const struct bf_matcher *matcher)
32 : {
33 : struct bf_jmpctx j0, j1;
34 : struct bf_matcher_ip6_addr *addr = (void *)&matcher->payload;
35 0 : size_t offset = matcher->type == BF_MATCHER_IP6_SADDR ?
36 0 : offsetof(struct ipv6hdr, saddr) :
37 : offsetof(struct ipv6hdr, daddr);
38 :
39 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_6, offset));
40 0 : EMIT(program, BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_6, offset + 8));
41 :
42 0 : if (addr->mask[_BF_MASK_LAST_BYTE] != (uint8_t)~0) {
43 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
44 : _bf_make32(addr->mask[7], addr->mask[6],
45 : addr->mask[5], addr->mask[4])));
46 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
47 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
48 : _bf_make32(addr->mask[3], addr->mask[2],
49 : addr->mask[1], addr->mask[0])));
50 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
51 0 : EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_3));
52 :
53 0 : EMIT(program,
54 : BPF_MOV32_IMM(BPF_REG_3,
55 : _bf_make32(addr->mask[15], addr->mask[14],
56 : addr->mask[13], addr->mask[12])));
57 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
58 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
59 : _bf_make32(addr->mask[11], addr->mask[10],
60 : addr->mask[9], addr->mask[8])));
61 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
62 0 : EMIT(program, BPF_ALU64_REG(BPF_AND, BPF_REG_2, BPF_REG_3));
63 : }
64 :
65 0 : if (matcher->op == BF_MATCHER_EQ) {
66 : /* If we want to match an IP, both addr->addr[0] and addr->addr[1]
67 : * must match the packet, otherwise we jump to the next rule. */
68 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
69 : _bf_make32(addr->addr[7] & addr->mask[7],
70 : addr->addr[6] & addr->mask[6],
71 : addr->addr[5] & addr->mask[5],
72 : addr->addr[4] & addr->mask[4])));
73 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
74 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
75 : _bf_make32(addr->addr[3] & addr->mask[3],
76 : addr->addr[2] & addr->mask[2],
77 : addr->addr[1] & addr->mask[1],
78 : addr->addr[0] & addr->mask[0])));
79 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
80 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
81 : BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
82 :
83 0 : EMIT(program,
84 : BPF_MOV32_IMM(BPF_REG_3,
85 : _bf_make32(addr->addr[15] & addr->mask[15],
86 : addr->addr[14] & addr->mask[14],
87 : addr->addr[13] & addr->mask[13],
88 : addr->addr[12] & addr->mask[12])));
89 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
90 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
91 : _bf_make32(addr->addr[11] & addr->mask[11],
92 : addr->addr[10] & addr->mask[10],
93 : addr->addr[9] & addr->mask[9],
94 : addr->addr[8] & addr->mask[8])));
95 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
96 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
97 : BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
98 : } else {
99 : /* If we want to *not* match an IP, none of addr->addr[0] and
100 : * addr->addr[1] should match the packet, otherwise we jump to the
101 : * next rule. */
102 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_3,
103 : _bf_make32(addr->addr[7] & addr->mask[7],
104 : addr->addr[6] & addr->mask[6],
105 : addr->addr[5] & addr->mask[5],
106 : addr->addr[4] & addr->mask[4])));
107 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
108 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
109 : _bf_make32(addr->addr[3] & addr->mask[3],
110 : addr->addr[2] & addr->mask[2],
111 : addr->addr[1] & addr->mask[1],
112 : addr->addr[0] & addr->mask[0])));
113 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
114 :
115 : /* Branching:
116 : * - addr->addr[0] matches the address' 64 MSB: continue to compare
117 : * the address' 64 LSB.
118 : * - addr->addr[0] doesn't matches the address' 64 MSB: jump to the
119 : * end of the matcher to continue the processing of the current rule.
120 : * This matcher matched. */
121 0 : j0 = bf_jmpctx_get(program,
122 : BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 0));
123 :
124 0 : EMIT(program,
125 : BPF_MOV32_IMM(BPF_REG_3,
126 : _bf_make32(addr->addr[15] & addr->mask[15],
127 : addr->addr[14] & addr->mask[14],
128 : addr->addr[13] & addr->mask[13],
129 : addr->addr[12] & addr->mask[12])));
130 0 : EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 32));
131 0 : EMIT(program, BPF_MOV32_IMM(BPF_REG_4,
132 : _bf_make32(addr->addr[11] & addr->mask[11],
133 : addr->addr[10] & addr->mask[10],
134 : addr->addr[9] & addr->mask[9],
135 : addr->addr[8] & addr->mask[8])));
136 0 : EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_3, BPF_REG_4));
137 :
138 : /* Branching:
139 : * - addr->addr[1] matches the address' 64 LSB: addr->addr matches the
140 : * packet's address, meaning the matcher doesn't match. Jump to the
141 : * next rule.
142 : * - addr->addr[1] doesn't matches the address' 64 LSB: the matcher
143 : * matched: addr->addr is not equal to the packet's address. Continue
144 : * processing with the next matcher. */
145 0 : j1 = bf_jmpctx_get(program,
146 : BPF_JMP_REG(BPF_JNE, BPF_REG_2, BPF_REG_3, 0));
147 :
148 0 : EMIT_FIXUP_JMP_NEXT_RULE(program, BPF_JMP_A(0));
149 :
150 : // j0 and j1 should jump here if they can't match the packet's IP.
151 0 : bf_jmpctx_cleanup(&j0);
152 0 : bf_jmpctx_cleanup(&j1);
153 : }
154 :
155 : return 0;
156 : }
157 :
158 0 : int bf_matcher_generate_ip6(struct bf_program *program,
159 : const struct bf_matcher *matcher)
160 : {
161 : int r;
162 :
163 0 : EMIT_FIXUP_JMP_NEXT_RULE(
164 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(ETH_P_IPV6), 0));
165 :
166 0 : EMIT(program,
167 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l3_hdr)));
168 :
169 0 : switch (matcher->type) {
170 0 : case BF_MATCHER_IP6_SADDR:
171 : case BF_MATCHER_IP6_DADDR:
172 0 : r = _bf_matcher_generate_ip6_addr(program, matcher);
173 : break;
174 0 : default:
175 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
176 : };
177 :
178 0 : return r;
179 : }
|