1 /*
2 * Copyright 2024, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apf_interpreter.h"
18
19 #include <string.h> /* For memcmp, memcpy, memset */
20
21 #if __GNUC__ >= 7 || __clang__
22 #define FALLTHROUGH __attribute__((fallthrough))
23 #else
24 #define FALLTHROUGH
25 #endif
26
27 typedef enum { False, True } Boolean;
28
29 /* Begin include of apf_defs.h */
30 typedef int8_t s8;
31 typedef int16_t s16;
32 typedef int32_t s32;
33
34 typedef uint8_t u8;
35 typedef uint16_t u16;
36 typedef uint32_t u32;
37
38 typedef enum {
39 error_program = -2,
40 error_packet = -1,
41 nomatch = False,
42 match = True
43 } match_result_type;
44
45 #define ETH_P_IP 0x0800
46 #define ETH_P_IPV6 0x86DD
47
48 #define ETH_HLEN 14
49 #define IPV4_HLEN 20
50 #define IPV6_HLEN 40
51 #define TCP_HLEN 20
52 #define UDP_HLEN 8
53
54 #define FUNC(x) x; x
55 /* End include of apf_defs.h */
56 /* Begin include of apf.h */
57 /*
58 * Copyright 2024, The Android Open Source Project
59 *
60 * Licensed under the Apache License, Version 2.0 (the "License");
61 * you may not use this file except in compliance with the License.
62 * You may obtain a copy of the License at
63 *
64 * http://www.apache.org/licenses/LICENSE-2.0
65 *
66 * Unless required by applicable law or agreed to in writing, software
67 * distributed under the License is distributed on an "AS IS" BASIS,
68 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
69 * See the License for the specific language governing permissions and
70 * limitations under the License.
71 */
72
73 #ifndef ANDROID_APF_APF_H
74 #define ANDROID_APF_APF_H
75
76 /* A brief overview of APF:
77 *
78 * APF machine is composed of:
79 * 1. A read-only program consisting of bytecodes as described below.
80 * 2. Two 32-bit registers, called R0 and R1.
81 * 3. Sixteen 32-bit temporary memory slots (cleared between packets).
82 * 4. A read-only packet.
83 * 5. An optional read-write transmit buffer.
84 * The program is executed by the interpreter below and parses the packet
85 * to determine if the application processor (AP) should be woken up to
86 * handle the packet or if it can be dropped. The program may also choose
87 * to allocate/transmit/deallocate the transmit buffer.
88 *
89 * APF bytecode description:
90 *
91 * The APF interpreter uses big-endian byte order for loads from the packet
92 * and for storing immediates in instructions.
93 *
94 * Each instruction starts with a byte composed of:
95 * Top 5 bits form "opcode" field, see *_OPCODE defines below.
96 * Next 2 bits form "size field", which indicates the length of an immediate
97 * value which follows the first byte. Values in this field:
98 * 0 => immediate value is 0 and no bytes follow.
99 * 1 => immediate value is 1 byte big.
100 * 2 => immediate value is 2 bytes big.
101 * 3 => immediate value is 4 bytes big.
102 * Bottom bit forms "register" field, which (usually) indicates which register
103 * this instruction operates on.
104 *
105 * There are four main categories of instructions:
106 * Load instructions
107 * These instructions load byte(s) of the packet into a register.
108 * They load either 1, 2 or 4 bytes, as determined by the "opcode" field.
109 * They load into the register specified by the "register" field.
110 * The immediate value that follows the first byte of the instruction is
111 * the byte offset from the beginning of the packet to load from.
112 * There are "indexing" loads which add the value in R1 to the byte offset
113 * to load from. The "opcode" field determines which loads are "indexing".
114 * Arithmetic instructions
115 * These instructions perform simple operations, like addition, on register
116 * values. The result of these instructions is always written into R0. One
117 * argument of the arithmetic operation is R0's value. The other argument
118 * of the arithmetic operation is determined by the "register" field:
119 * If the "register" field is 0 then the immediate value following
120 * the first byte of the instruction is used as the other argument
121 * to the arithmetic operation.
122 * If the "register" field is 1 then R1's value is used as the other
123 * argument to the arithmetic operation.
124 * Conditional jump instructions
125 * These instructions compare register R0's value with another value, and if
126 * the comparison succeeds, jump (i.e. adjust the program counter). The
127 * immediate value that follows the first byte of the instruction
128 * represents the jump target offset, i.e. the value added to the program
129 * counter if the comparison succeeds. The other value compared is
130 * determined by the "register" field:
131 * If the "register" field is 0 then another immediate value
132 * follows the jump target offset. This immediate value is of the
133 * same size as the jump target offset, and represents the value
134 * to compare against.
135 * If the "register" field is 1 then register R1's value is
136 * compared against.
137 * The type of comparison (e.g. equal to, greater than etc) is determined
138 * by the "opcode" field. The comparison interprets both values being
139 * compared as unsigned values.
140 * Miscellaneous instructions
141 * Instructions for:
142 * - allocating/transmitting/deallocating transmit buffer
143 * - building the transmit packet (copying bytes into it)
144 * - read/writing data section
145 *
146 * Miscellaneous details:
147 *
148 * Pre-filled temporary memory slot values
149 * When the APF program begins execution, six of the sixteen memory slots
150 * are pre-filled by the interpreter with values that may be useful for
151 * programs:
152 * #0 to #7 are zero initialized.
153 * Slot #8 is initialized with apf version (on APF >4).
154 * Slot #9 this is slot #15 with greater resolution (1/16384ths of a second)
155 * Slot #10 starts at zero, implicitly used as tx buffer output pointer.
156 * Slot #11 contains the size (in bytes) of the APF program.
157 * Slot #12 contains the total size of the APF program + data.
158 * Slot #13 is filled with the IPv4 header length. This value is calculated
159 * by loading the first byte of the IPv4 header and taking the
160 * bottom 4 bits and multiplying their value by 4. This value is
161 * set to zero if the first 4 bits after the link layer header are
162 * not 4, indicating not IPv4.
163 * Slot #14 is filled with size of the packet in bytes, including the
164 * ethernet link-layer header.
165 * Slot #15 is filled with the filter age in seconds. This is the number of
166 * seconds since the host installed the program. This may
167 * be used by filters that should have a particular lifetime. For
168 * example, it can be used to rate-limit particular packets to one
169 * every N seconds.
170 * Special jump targets:
171 * When an APF program executes a jump to the byte immediately after the last
172 * byte of the progam (i.e., one byte past the end of the program), this
173 * signals the program has completed and determined the packet should be
174 * passed to the AP.
175 * When an APF program executes a jump two bytes past the end of the program,
176 * this signals the program has completed and determined the packet should
177 * be dropped.
178 * Jump if byte sequence doesn't match:
179 * This is a special instruction to facilitate matching long sequences of
180 * bytes in the packet. Initially it is encoded like a conditional jump
181 * instruction with two exceptions:
182 * The first byte of the instruction is always followed by two immediate
183 * fields: The first immediate field is the jump target offset like other
184 * conditional jump instructions. The second immediate field specifies the
185 * number of bytes to compare.
186 * These two immediate fields are followed by a sequence of bytes. These
187 * bytes are compared with the bytes in the packet starting from the
188 * position specified by the value of the register specified by the
189 * "register" field of the instruction.
190 */
191
192 /* Number of temporary memory slots, see ldm/stm instructions. */
193 #define MEMORY_ITEMS 16
194 /* Upon program execution, some temporary memory slots are prefilled: */
195
196 typedef union {
197 struct {
198 u32 pad[8]; /* 0..7 */
199 u32 apf_version; /* 8: Initialized with apf_version() */
200 u32 filter_age_16384ths; /* 9: Age since filter installed in 1/16384 seconds. */
201 u32 tx_buf_offset; /* 10: Offset in tx_buf where next byte will be written */
202 u32 program_size; /* 11: Size of program (in bytes) */
203 u32 ram_len; /* 12: Total size of program + data, ie. ram_len */
204 u32 ipv4_header_size; /* 13: 4*([APF_FRAME_HEADER_SIZE]&15) */
205 u32 packet_size; /* 14: Size of packet in bytes. */
206 u32 filter_age; /* 15: Age since filter installed in seconds. */
207 } named;
208 u32 slot[MEMORY_ITEMS];
209 } memory_type;
210
211 /* ---------------------------------------------------------------------------------------------- */
212
213 /* Standard opcodes. */
214
215 /* Unconditionally pass (if R=0) or drop (if R=1) packet and optionally increment counter.
216 * An optional non-zero unsigned immediate value can be provided to encode the counter number.
217 * The counter is located (-4 * counter number) bytes from the end of the data region.
218 * It is a U32 big-endian value and is always incremented by 1.
219 * This is more or less equivalent to: lddw R0, -4*N; add R0, 1; stdw R0, -4*N; {pass,drop}
220 * e.g. "pass", "pass 1", "drop", "drop 1"
221 */
222 #define PASSDROP_OPCODE 0
223
224 #define LDB_OPCODE 1 /* Load 1 byte from immediate offset, e.g. "ldb R0, [5]" */
225 #define LDH_OPCODE 2 /* Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" */
226 #define LDW_OPCODE 3 /* Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" */
227 #define LDBX_OPCODE 4 /* Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5+R0]" */
228 #define LDHX_OPCODE 5 /* Load 2 bytes from immediate offset plus register, e.g. "ldhx R0, [5+R0]" */
229 #define LDWX_OPCODE 6 /* Load 4 bytes from immediate offset plus register, e.g. "ldwx R0, [5+R0]" */
230 #define ADD_OPCODE 7 /* Add, e.g. "add R0,5" */
231 #define MUL_OPCODE 8 /* Multiply, e.g. "mul R0,5" */
232 #define DIV_OPCODE 9 /* Divide, e.g. "div R0,5" */
233 #define AND_OPCODE 10 /* And, e.g. "and R0,5" */
234 #define OR_OPCODE 11 /* Or, e.g. "or R0,5" */
235 #define SH_OPCODE 12 /* Left shift, e.g. "sh R0, 5" or "sh R0, -5" (shifts right) */
236 #define LI_OPCODE 13 /* Load signed immediate, e.g. "li R0,5" */
237 #define JMP_OPCODE 14 /* Unconditional jump, e.g. "jmp label" */
238 #define JEQ_OPCODE 15 /* Compare equal and branch, e.g. "jeq R0,5,label" */
239 #define JNE_OPCODE 16 /* Compare not equal and branch, e.g. "jne R0,5,label" */
240 #define JGT_OPCODE 17 /* Compare greater than and branch, e.g. "jgt R0,5,label" */
241 #define JLT_OPCODE 18 /* Compare less than and branch, e.g. "jlt R0,5,label" */
242 #define JSET_OPCODE 19 /* Compare any bits set and branch, e.g. "jset R0,5,label" */
243 #define JBSMATCH_OPCODE 20 /* Compare byte sequence [R=0 not] equal, e.g. "jbsne R0,2,label,0x1122" */
244 /* NOTE: Only APFv6+ implements R=1 'jbseq' version and multi match */
245 /* imm1 is jmp target, imm2 is (cnt - 1) * 2048 + compare_len, */
246 /* which is followed by cnt * compare_len bytes to compare against. */
247 /* Warning: do not specify the same byte sequence multiple times. */
248 #define EXT_OPCODE 21 /* Immediate value is one of *_EXT_OPCODE */
249 #define LDDW_OPCODE 22 /* Load 4 bytes from data address (register + signed imm): "lddw R0, [5+R1]" */
250 /* LDDW/STDW in APFv6+ *mode* load/store from counter specified in imm. */
251 #define STDW_OPCODE 23 /* Store 4 bytes to data address (register + signed imm): "stdw R0, [5+R1]" */
252
253 /* Write 1, 2 or 4 byte immediate to the output buffer and auto-increment the output buffer pointer.
254 * Immediate length field specifies size of write. R must be 0. imm_len != 0.
255 * e.g. "write 5"
256 */
257 #define WRITE_OPCODE 24
258
259 /* Copy bytes from input packet/APF program/data region to output buffer and
260 * auto-increment the output buffer pointer.
261 * Register bit is used to specify the source of data copy.
262 * R=0 means copy from packet.
263 * R=1 means copy from APF program/data region.
264 * The source offset is stored in imm1, copy length is stored in u8 imm2.
265 * e.g. "pktcopy 0, 16" or "datacopy 0, 16"
266 */
267 #define PKTDATACOPY_OPCODE 25
268
269 /* ---------------------------------------------------------------------------------------------- */
270
271 /* Extended opcodes. */
272 /* These all have an opcode of EXT_OPCODE and specify the actual opcode in the immediate field. */
273
274 #define LDM_EXT_OPCODE 0 /* Load from temporary memory, e.g. "ldm R0,5" */
275 /* Values 0-15 represent loading the different temporary memory slots. */
276 #define STM_EXT_OPCODE 16 /* Store to temporary memory, e.g. "stm R0,5" */
277 /* Values 16-31 represent storing to the different temporary memory slots. */
278 #define NOT_EXT_OPCODE 32 /* Not, e.g. "not R0" */
279 #define NEG_EXT_OPCODE 33 /* Negate, e.g. "neg R0" */
280 #define SWAP_EXT_OPCODE 34 /* Swap, e.g. "swap R0,R1" */
281 #define MOV_EXT_OPCODE 35 /* Move, e.g. "move R0,R1" */
282
283 /* Allocate writable output buffer.
284 * R=0: register R0 specifies the length
285 * R=1: length provided in u16 imm2
286 * e.g. "allocate R0" or "allocate 123"
287 * On failure automatically executes 'pass 3'
288 */
289 #define ALLOCATE_EXT_OPCODE 36
290 /* Transmit and deallocate the buffer (transmission can be delayed until the program
291 * terminates). Length of buffer is the output buffer pointer (0 means discard).
292 * R=1 iff udp style L4 checksum
293 * u8 imm2 - ip header offset from start of buffer (255 for non-ip packets)
294 * u8 imm3 - offset from start of buffer to store L4 checksum (255 for no L4 checksum)
295 * u8 imm4 - offset from start of buffer to begin L4 checksum calculation (present iff imm3 != 255)
296 * u16 imm5 - partial checksum value to include in L4 checksum (present iff imm3 != 255)
297 * "e.g. transmit"
298 */
299 #define TRANSMIT_EXT_OPCODE 37
300 /* Write 1, 2 or 4 byte value from register to the output buffer and auto-increment the
301 * output buffer pointer.
302 * e.g. "ewrite1 r0" or "ewrite2 r1"
303 */
304 #define EWRITE1_EXT_OPCODE 38
305 #define EWRITE2_EXT_OPCODE 39
306 #define EWRITE4_EXT_OPCODE 40
307
308 /* Copy bytes from input packet/APF program/data region to output buffer and
309 * auto-increment the output buffer pointer.
310 * Register bit is used to specify the source of data copy.
311 * R=0 means copy from packet.
312 * R=1 means copy from APF program/data region.
313 * The source offset is stored in R0, copy length is stored in u8 imm2 or R1.
314 * e.g. "epktcopy r0, 16", "edatacopy r0, 16", "epktcopy r0, r1", "edatacopy r0, r1"
315 */
316 #define EPKTDATACOPYIMM_EXT_OPCODE 41
317 #define EPKTDATACOPYR1_EXT_OPCODE 42
318 /* Jumps if the UDP payload content (starting at R0) does [not] match one
319 * of the specified QNAMEs in question records, applying case insensitivity.
320 * SAFE version PASSES corrupt packets, while the other one DROPS.
321 * R=0/1 meaning 'does not match'/'matches'
322 * R0: Offset to UDP payload content
323 * imm1: Extended opcode
324 * imm2: Jump label offset
325 * imm3(u8): Question type (PTR/SRV/TXT/A/AAAA)
326 * imm4(bytes): null terminated list of null terminated LV-encoded QNAMEs
327 * e.g.: "jdnsqeq R0,label,0xc,\002aa\005local\0\0", "jdnsqne R0,label,0xc,\002aa\005local\0\0"
328 */
329 #define JDNSQMATCH_EXT_OPCODE 43
330 #define JDNSQMATCHSAFE_EXT_OPCODE 45
331 /* Jumps if the UDP payload content (starting at R0) does [not] match one
332 * of the specified NAMEs in answers/authority/additional records, applying
333 * case insensitivity.
334 * SAFE version PASSES corrupt packets, while the other one DROPS.
335 * R=0/1 meaning 'does not match'/'matches'
336 * R0: Offset to UDP payload content
337 * imm1: Extended opcode
338 * imm2: Jump label offset
339 * imm3(bytes): null terminated list of null terminated LV-encoded NAMEs
340 * e.g.: "jdnsaeq R0,label,0xc,\002aa\005local\0\0", "jdnsane R0,label,0xc,\002aa\005local\0\0"
341 */
342 #define JDNSAMATCH_EXT_OPCODE 44
343 #define JDNSAMATCHSAFE_EXT_OPCODE 46
344
345 /* Jump if register is [not] one of the list of values
346 * R bit - specifies the register (R0/R1) to test
347 * imm1: Extended opcode
348 * imm2: Jump label offset
349 * imm3(u8): top 5 bits - number 'n' of following u8/be16/be32 values - 2
350 * middle 2 bits - 1..4 length of immediates - 1
351 * bottom 1 bit - =0 jmp if in set, =1 if not in set
352 * imm4(n * 1/2/3/4 bytes): the *UNIQUE* values to compare against
353 */
354 #define JONEOF_EXT_OPCODE 47
355
356 /* Specify length of exception buffer, which is populated on abnormal program termination.
357 * imm1: Extended opcode
358 * imm2(u16): Length of exception buffer (located *immediately* after the program itself)
359 */
360 #define EXCEPTIONBUFFER_EXT_OPCODE 48
361
362 /* This extended opcode is used to implement PKTDATACOPY_OPCODE */
363 #define PKTDATACOPYIMM_EXT_OPCODE 65536
364
365 #define EXTRACT_OPCODE(i) (((i) >> 3) & 31)
366 #define EXTRACT_REGISTER(i) ((i) & 1)
367 #define EXTRACT_IMM_LENGTH(i) (((i) >> 1) & 3)
368
369 #endif /* ANDROID_APF_APF_H */
370 /* End include of apf.h */
371 /* Begin include of apf_utils.h */
read_be16(const u8 * buf)372 static u32 read_be16(const u8* buf) {
373 return buf[0] * 256u + buf[1];
374 }
375
store_be16(u8 * const buf,const u16 v)376 static void store_be16(u8* const buf, const u16 v) {
377 buf[0] = (u8)(v >> 8);
378 buf[1] = (u8)v;
379 }
380
uppercase(u8 c)381 static u8 uppercase(u8 c) {
382 return (c >= 'a') && (c <= 'z') ? c - ('a' - 'A') : c;
383 }
384 /* End include of apf_utils.h */
385 /* Begin include of apf_dns.h */
386 /**
387 * Compares a (Q)NAME starting at udp[*ofs] with the target name.
388 *
389 * @param needle - non-NULL - pointer to DNS encoded target name to match against.
390 * example: [11]_googlecast[4]_tcp[5]local[0] (where [11] is a byte with value 11)
391 * @param needle_bound - non-NULL - points at first invalid byte past needle.
392 * @param udp - non-NULL - pointer to the start of the UDP payload (DNS header).
393 * @param udp_len - length of the UDP payload.
394 * @param ofs - non-NULL - pointer to the offset of the beginning of the (Q)NAME.
395 * On non-error return will be updated to point to the first unread offset,
396 * ie. the next position after the (Q)NAME.
397 *
398 * @return 1 if matched, 0 if not matched, -1 if error in packet, -2 if error in program.
399 */
FUNC(match_result_type apf_internal_match_single_name (const u8 * needle,const u8 * const needle_bound,const u8 * const udp,const u32 udp_len,u32 * const ofs))400 FUNC(match_result_type apf_internal_match_single_name(const u8* needle,
401 const u8* const needle_bound,
402 const u8* const udp,
403 const u32 udp_len,
404 u32* const ofs)) {
405 u32 first_unread_offset = *ofs;
406 Boolean is_qname_match = True;
407 int lvl;
408
409 /* DNS names are <= 255 characters including terminating 0, since >= 1 char + '.' per level => max. 127 levels */
410 for (lvl = 1; lvl <= 127; ++lvl) {
411 u8 v;
412 if (*ofs >= udp_len) return error_packet;
413 v = udp[(*ofs)++];
414 if (v >= 0xC0) { /* RFC 1035 4.1.4 - handle message compression */
415 u8 w;
416 u32 new_ofs;
417 if (*ofs >= udp_len) return error_packet;
418 w = udp[(*ofs)++];
419 if (*ofs > first_unread_offset) first_unread_offset = *ofs;
420 new_ofs = (v - 0xC0) * 256u + w;
421 if (new_ofs >= *ofs) return error_packet; /* RFC 1035 4.1.4 allows only backward pointers */
422 *ofs = new_ofs;
423 } else if (v > 63) {
424 return error_packet; /* RFC 1035 2.3.4 - label size is 1..63. */
425 } else if (v) {
426 u8 label_size = v;
427 if (*ofs + label_size > udp_len) return error_packet;
428 if (needle >= needle_bound) return error_program;
429 if (is_qname_match) {
430 u8 len = *needle++;
431 if (len == label_size) {
432 if (needle + label_size > needle_bound) return error_program;
433 while (label_size--) {
434 u8 w = udp[(*ofs)++];
435 is_qname_match &= (uppercase(w) == *needle++);
436 }
437 } else {
438 if (len != 0xFF) is_qname_match = False;
439 *ofs += label_size;
440 }
441 } else {
442 is_qname_match = False;
443 *ofs += label_size;
444 }
445 } else { /* reached the end of the name */
446 if (first_unread_offset > *ofs) *ofs = first_unread_offset;
447 return (is_qname_match && *needle == 0) ? match : nomatch;
448 }
449 }
450 return error_packet; /* too many dns domain name levels */
451 }
452
453 /**
454 * Check if DNS packet contains any of the target names with the provided
455 * question_type.
456 *
457 * @param needles - non-NULL - pointer to DNS encoded target nameS to match against.
458 * example: [3]foo[3]com[0][3]bar[3]net[0][0] -- note ends with an extra NULL byte.
459 * @param needle_bound - non-NULL - points at first invalid byte past needles.
460 * @param udp - non-NULL - pointer to the start of the UDP payload (DNS header).
461 * @param udp_len - length of the UDP payload.
462 * @param question_type - question type to match against or -1 to match answers.
463 *
464 * @return 1 if matched, 0 if not matched, -1 if error in packet, -2 if error in program.
465 */
FUNC(match_result_type apf_internal_match_names (const u8 * needles,const u8 * const needle_bound,const u8 * const udp,const u32 udp_len,const int question_type))466 FUNC(match_result_type apf_internal_match_names(const u8* needles,
467 const u8* const needle_bound,
468 const u8* const udp,
469 const u32 udp_len,
470 const int question_type)) {
471 u32 num_questions, num_answers;
472 if (udp_len < 12) return error_packet; /* lack of dns header */
473
474 /* dns header: be16 tid, flags, num_{questions,answers,authority,additional} */
475 num_questions = read_be16(udp + 4);
476 num_answers = read_be16(udp + 6) + read_be16(udp + 8) + read_be16(udp + 10);
477
478 /* loop until we hit final needle, which is a null byte */
479 while (True) {
480 u32 i, ofs = 12; /* dns header is 12 bytes */
481 if (needles >= needle_bound) return error_program;
482 if (!*needles) return nomatch; /* we've run out of needles without finding a match */
483 /* match questions */
484 for (i = 0; i < num_questions; ++i) {
485 match_result_type m = apf_internal_match_single_name(needles, needle_bound, udp, udp_len, &ofs);
486 int qtype;
487 if (m < nomatch) return m;
488 if (ofs + 2 > udp_len) return error_packet;
489 qtype = (int)read_be16(udp + ofs);
490 ofs += 4; /* skip be16 qtype & qclass */
491 if (question_type == -1) continue;
492 if (m == nomatch) continue;
493 if (qtype == 0xFF /* QTYPE_ANY */ || qtype == question_type) return match;
494 }
495 /* match answers */
496 if (question_type == -1) for (i = 0; i < num_answers; ++i) {
497 match_result_type m = apf_internal_match_single_name(needles, needle_bound, udp, udp_len, &ofs);
498 if (m < nomatch) return m;
499 ofs += 8; /* skip be16 type, class & be32 ttl */
500 if (ofs + 2 > udp_len) return error_packet;
501 ofs += 2 + read_be16(udp + ofs); /* skip be16 rdata length field, plus length bytes */
502 if (m == match) return match;
503 }
504 /* move needles pointer to the next needle. */
505 do {
506 u8 len = *needles++;
507 if (len == 0xFF) continue;
508 if (len > 63) return error_program;
509 needles += len;
510 if (needles >= needle_bound) return error_program;
511 } while (*needles);
512 needles++; /* skip the NULL byte at the end of *a* DNS name */
513 }
514 }
515 /* End include of apf_dns.h */
516 /* Begin include of apf_checksum.h */
517 /**
518 * Calculate big endian 16-bit sum of a buffer (max 128kB),
519 * then fold and negate it, producing a 16-bit result in [0..FFFE].
520 */
FUNC(u16 apf_internal_calc_csum (u32 sum,const u8 * const buf,const s32 len))521 FUNC(u16 apf_internal_calc_csum(u32 sum, const u8* const buf, const s32 len)) {
522 u16 csum;
523 s32 i;
524 for (i = 0; i < len; ++i) sum += buf[i] * ((i & 1) ? 1u : 256u);
525
526 sum = (sum & 0xFFFF) + (sum >> 16); /* max after this is 1FFFE */
527 csum = sum + (sum >> 16);
528 return ~csum; /* assuming sum > 0 on input, this is in [0..FFFE] */
529 }
530
fix_udp_csum(u16 csum)531 static u16 fix_udp_csum(u16 csum) {
532 return csum ? csum : 0xFFFF;
533 }
534
535 /**
536 * Calculate and store packet checksums and return dscp.
537 *
538 * @param pkt - pointer to the very start of the to-be-transmitted packet,
539 * ie. the start of the ethernet header (if one is present)
540 * WARNING: at minimum 266 bytes of buffer pointed to by 'pkt' pointer
541 * *MUST* be writable.
542 * (IPv4 header checksum is a 2 byte value, 10 bytes after ip_ofs,
543 * which has a maximum value of 254. Thus 254[ip_ofs] + 10 + 2[u16] = 266)
544 *
545 * @param len - length of the packet (this may be < 266).
546 * @param ip_ofs - offset from beginning of pkt to IPv4 or IPv6 header:
547 * IP version detected based on top nibble of this byte,
548 * for IPv4 we will calculate and store IP header checksum,
549 * but only for the first 20 bytes of the header,
550 * prior to calling this the IPv4 header checksum field
551 * must be initialized to the partial checksum of the IPv4
552 * options (0 if none)
553 * 255 means there is no IP header (for example ARP)
554 * DSCP will be retrieved from this IP header (0 if none).
555 * @param partial_csum - additional value to include in L4 checksum
556 * @param csum_start - offset from beginning of pkt to begin L4 checksum
557 * calculation (until end of pkt specified by len)
558 * @param csum_ofs - offset from beginning of pkt to store L4 checksum
559 * 255 means do not calculate/store L4 checksum
560 * @param udp - True iff we should generate a UDP style L4 checksum (0 -> 0xFFFF)
561 *
562 * @return 6-bit DSCP value [0..63], garbage on parse error.
563 */
FUNC(int apf_internal_csum_and_return_dscp (u8 * const pkt,const s32 len,const u8 ip_ofs,const u16 partial_csum,const u8 csum_start,const u8 csum_ofs,const Boolean udp))564 FUNC(int apf_internal_csum_and_return_dscp(u8* const pkt, const s32 len, const u8 ip_ofs,
565 const u16 partial_csum, const u8 csum_start, const u8 csum_ofs, const Boolean udp)) {
566 if (csum_ofs < 255) {
567 /* note that apf_internal_calc_csum() treats negative lengths as zero */
568 u32 csum = apf_internal_calc_csum(partial_csum, pkt + csum_start, len - csum_start);
569 if (udp) csum = fix_udp_csum(csum);
570 store_be16(pkt + csum_ofs, csum);
571 }
572 if (ip_ofs < 255) {
573 u8 ip = pkt[ip_ofs] >> 4;
574 if (ip == 4) {
575 store_be16(pkt + ip_ofs + 10, apf_internal_calc_csum(0, pkt + ip_ofs, IPV4_HLEN));
576 return pkt[ip_ofs + 1] >> 2; /* DSCP */
577 } else if (ip == 6) {
578 return (read_be16(pkt + ip_ofs) >> 6) & 0x3F; /* DSCP */
579 }
580 }
581 return 0;
582 }
583 /* End include of apf_checksum.h */
584
585 /* User hook for interpreter debug tracing. */
586 #ifdef APF_TRACE_HOOK
587 extern void APF_TRACE_HOOK(u32 pc, const u32* regs, const u8* program,
588 u32 program_len, const u8 *packet, u32 packet_len,
589 const u32* memory, u32 ram_len);
590 #else
591 #define APF_TRACE_HOOK(pc, regs, program, program_len, packet, packet_len, memory, memory_len) \
592 do { /* nop*/ \
593 } while (0)
594 #endif
595
596 /* Return code indicating "packet" should accepted. */
597 #define PASS 1
598 /* Return code indicating "packet" should be accepted (and something unexpected happened). */
599 #define EXCEPTION 2
600 /* Return code indicating "packet" should be dropped. */
601 #define DROP 0
602 /* Verify an internal condition and accept packet if it fails. */
603 #define ASSERT_RETURN(c) if (!(c)) return EXCEPTION
604 /* If "c" is of an unsigned type, generate a compile warning that gets promoted to an error. */
605 /* This makes bounds checking simpler because ">= 0" can be avoided. Otherwise adding */
606 /* superfluous ">= 0" with unsigned expressions generates compile warnings. */
607 #define ENFORCE_UNSIGNED(c) ((c)==(u32)(c))
608
apf_version(void)609 u32 apf_version(void) {
610 return 6000;
611 }
612
613 typedef struct {
614 /* Note: the following 4 fields take up exactly 8 bytes. */
615 u16 except_buf_sz; /* Length of the exception buffer (at program_len offset) */
616 u8 ptr_size; /* sizeof(void*) */
617 u8 v6; /* Set to 1 by first jmpdata (APFv6+) instruction */
618 u32 pc; /* Program counter. */
619 /* All the pointers should be next to each other for better struct packing. */
620 /* We are at offset 8, so even 64-bit pointers will not need extra padding. */
621 void *caller_ctx; /* Passed in to interpreter, passed through to alloc/transmit. */
622 u8* tx_buf; /* The output buffer pointer */
623 u8* program; /* Pointer to program/data buffer */
624 const u8* packet; /* Pointer to input packet buffer */
625 /* Order fields in order of decreasing size */
626 u32 tx_buf_len; /* The length of the output buffer */
627 u32 program_len; /* Length of the program */
628 u32 ram_len; /* Length of the entire apf program/data region */
629 u32 packet_len; /* Length of the input packet buffer */
630 u32 R[2]; /* Register values. */
631 memory_type mem; /* Memory slot values. (array of u32s) */
632 /* Note: any extra u16s go here, then u8s */
633 } apf_context;
634
FUNC(int apf_internal_do_transmit_buffer (apf_context * ctx,u32 pkt_len,u8 dscp))635 FUNC(int apf_internal_do_transmit_buffer(apf_context* ctx, u32 pkt_len, u8 dscp)) {
636 int ret = apf_transmit_buffer(ctx->caller_ctx, ctx->tx_buf, pkt_len, dscp);
637 ctx->tx_buf = NULL;
638 ctx->tx_buf_len = 0;
639 return ret;
640 }
641
do_discard_buffer(apf_context * ctx)642 static int do_discard_buffer(apf_context* ctx) {
643 return apf_internal_do_transmit_buffer(ctx, 0 /* pkt_len */, 0 /* dscp */);
644 }
645
646 /* Decode an immediate, lengths [0..4] all work, does not do range checking. */
647 /* But note that program is at least 20 bytes shorter than ram, so first few */
648 /* immediates can always be safely decoded without exceeding ram buffer. */
decode_imm(apf_context * ctx,u32 length)649 static u32 decode_imm(apf_context* ctx, u32 length) {
650 u32 i, v = 0;
651 for (i = 0; i < length; ++i) v = (v << 8) | ctx->program[ctx->pc++];
652 return v;
653 }
654
655 #define DECODE_U8() (ctx->program[ctx->pc++])
656
decode_be16(apf_context * ctx)657 static u16 decode_be16(apf_context* ctx) {
658 u16 v = ctx->program[ctx->pc++];
659 v <<= 8;
660 v |= ctx->program[ctx->pc++];
661 return v;
662 }
663
do_apf_run(apf_context * ctx)664 static int do_apf_run(apf_context* ctx) {
665 /* Is offset within ram bounds? */
666 #define IN_RAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < ctx->ram_len)
667 /* Is offset within packet bounds? */
668 #define IN_PACKET_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < ctx->packet_len)
669 /* Is access to offset |p| length |size| within data bounds? */
670 #define IN_DATA_BOUNDS(p, size) (ENFORCE_UNSIGNED(p) && \
671 ENFORCE_UNSIGNED(size) && \
672 (p) + (size) <= ctx->ram_len && \
673 (p) + (size) >= (p)) /* catch wraparounds */
674 /* Accept packet if not within ram bounds */
675 #define ASSERT_IN_RAM_BOUNDS(p) ASSERT_RETURN(IN_RAM_BOUNDS(p))
676 /* Accept packet if not within packet bounds */
677 #define ASSERT_IN_PACKET_BOUNDS(p) ASSERT_RETURN(IN_PACKET_BOUNDS(p))
678 /* Accept packet if not within data bounds */
679 #define ASSERT_IN_DATA_BOUNDS(p, size) ASSERT_RETURN(IN_DATA_BOUNDS(p, size))
680
681 /* Counters start at end of RAM and count *backwards* so this array takes negative integers. */
682 u32 *counter = (u32*)(ctx->program + ctx->ram_len);
683
684 /* Count of instructions remaining to execute. This is done to ensure an */
685 /* upper bound on execution time. It should never be hit and is only for */
686 /* safety. Initialize to the number of bytes in the program which is an */
687 /* upper bound on the number of instructions in the program. */
688 u32 instructions_remaining = ctx->program_len;
689
690 /* APFv6 requires at least 5 u32 counters at the end of ram, this makes counter[-5]++ valid */
691 /* This cannot wrap due to previous check, that enforced program_len & ram_len < 2GiB. */
692 if (ctx->program_len + 20 > ctx->ram_len) return EXCEPTION;
693
694 /* Only populate if packet long enough, and IP version is IPv4. */
695 /* Note: this doesn't actually check the ethertype... */
696 if ((ctx->packet_len >= ETH_HLEN + IPV4_HLEN) && ((ctx->packet[ETH_HLEN] & 0xf0) == 0x40)) {
697 ctx->mem.named.ipv4_header_size = (ctx->packet[ETH_HLEN] & 15) * 4;
698 }
699
700 /* Is access to offset |p| length |size| within output buffer bounds? */
701 #define IN_OUTPUT_BOUNDS(p, size) (ENFORCE_UNSIGNED(p) && \
702 ENFORCE_UNSIGNED(size) && \
703 (p) + (size) <= ctx->tx_buf_len && \
704 (p) + (size) >= (p))
705 /* Accept packet if not write within allocated output buffer */
706 #define ASSERT_IN_OUTPUT_BOUNDS(p, size) ASSERT_RETURN(IN_OUTPUT_BOUNDS(p, size))
707
708 do {
709 APF_TRACE_HOOK(ctx->pc, ctx->R, ctx->program, ctx->program_len,
710 ctx->packet, ctx->packet_len, ctx->mem.slot, ctx->ram_len);
711 if (ctx->pc == ctx->program_len + 1) return DROP;
712 if (ctx->pc == ctx->program_len) return PASS;
713 if (ctx->pc > ctx->program_len) return EXCEPTION;
714
715 { /* half indent to avoid needless line length... */
716
717 const u8 bytecode = ctx->program[ctx->pc++];
718 const u8 opcode = EXTRACT_OPCODE(bytecode);
719 const u8 reg_num = EXTRACT_REGISTER(bytecode);
720 #define REG (ctx->R[reg_num])
721 #define OTHER_REG (ctx->R[reg_num ^ 1])
722 /* All instructions have immediate fields, so load them now. */
723 const u8 len_field = EXTRACT_IMM_LENGTH(bytecode);
724 const u8 imm_len = ((len_field + 1u) >> 2) + len_field; /* 0,1,2,3 -> 0,1,2,4 */
725 u32 pktcopy_src_offset = 0; /* used for various pktdatacopy opcodes */
726 u32 imm = 0;
727 s32 signed_imm = 0;
728 u32 arith_imm;
729 s32 arith_signed_imm;
730 if (len_field != 0) {
731 imm = decode_imm(ctx, imm_len); /* 1st imm, at worst bytes 1-4 past opcode/program_len */
732 /* Sign extend imm into signed_imm. */
733 signed_imm = (s32)(imm << ((4 - imm_len) * 8));
734 signed_imm >>= (4 - imm_len) * 8;
735 }
736
737 /* See comment at ADD_OPCODE for the reason for ARITH_REG/arith_imm/arith_signed_imm. */
738 #define ARITH_REG (ctx->R[reg_num & ctx->v6])
739 arith_imm = (ctx->v6) ? (len_field ? imm : OTHER_REG) : (reg_num ? ctx->R[1] : imm);
740 arith_signed_imm = (ctx->v6) ? (len_field ? signed_imm : (s32)OTHER_REG) : (reg_num ? (s32)ctx->R[1] : signed_imm);
741
742 switch (opcode) {
743 case PASSDROP_OPCODE: { /* APFv6+ */
744 if (len_field > 2) return EXCEPTION; /* max 64K counters (ie. imm < 64K) */
745 if (imm) {
746 if (4 * imm > ctx->ram_len) return EXCEPTION;
747 counter[-(s32)imm]++;
748 }
749 return reg_num ? DROP : PASS;
750 }
751 case LDB_OPCODE:
752 case LDH_OPCODE:
753 case LDW_OPCODE:
754 case LDBX_OPCODE:
755 case LDHX_OPCODE:
756 case LDWX_OPCODE: {
757 u32 load_size = 0;
758 u32 offs = imm;
759 /* Note: this can overflow and actually decrease offs. */
760 if (opcode >= LDBX_OPCODE) offs += ctx->R[1];
761 ASSERT_IN_PACKET_BOUNDS(offs);
762 switch (opcode) {
763 case LDB_OPCODE:
764 case LDBX_OPCODE:
765 load_size = 1;
766 break;
767 case LDH_OPCODE:
768 case LDHX_OPCODE:
769 load_size = 2;
770 break;
771 case LDW_OPCODE:
772 case LDWX_OPCODE:
773 load_size = 4;
774 break;
775 /* Immediately enclosing switch statement guarantees */
776 /* opcode cannot be any other value. */
777 }
778 {
779 const u32 end_offs = offs + (load_size - 1);
780 u32 val = 0;
781 /* Catch overflow/wrap-around. */
782 ASSERT_RETURN(end_offs >= offs);
783 ASSERT_IN_PACKET_BOUNDS(end_offs);
784 while (load_size--) val = (val << 8) | ctx->packet[offs++];
785 REG = val;
786 }
787 break;
788 }
789 case JMP_OPCODE:
790 if (reg_num && !ctx->v6) { /* APFv6+ */
791 /* First invocation of APFv6 jmpdata instruction */
792 counter[-1] = 0x12345678; /* endianness marker */
793 counter[-2]++; /* total packets ++ */
794 ctx->v6 = (u8)True;
795 }
796 /* This can jump backwards. Infinite looping prevented by instructions_remaining. */
797 ctx->pc += imm;
798 break;
799 case JEQ_OPCODE:
800 case JNE_OPCODE:
801 case JGT_OPCODE:
802 case JLT_OPCODE:
803 case JSET_OPCODE: {
804 u32 cmp_imm = 0;
805 /* Load second immediate field. */
806 if (reg_num == 1) {
807 cmp_imm = ctx->R[1];
808 } else {
809 cmp_imm = decode_imm(ctx, imm_len); /* 2nd imm, at worst 8 bytes past prog_len */
810 }
811 switch (opcode) {
812 case JEQ_OPCODE: if (ctx->R[0] == cmp_imm) ctx->pc += imm; break;
813 case JNE_OPCODE: if (ctx->R[0] != cmp_imm) ctx->pc += imm; break;
814 case JGT_OPCODE: if (ctx->R[0] > cmp_imm) ctx->pc += imm; break;
815 case JLT_OPCODE: if (ctx->R[0] < cmp_imm) ctx->pc += imm; break;
816 case JSET_OPCODE: if (ctx->R[0] & cmp_imm) ctx->pc += imm; break;
817 }
818 break;
819 }
820 case JBSMATCH_OPCODE: {
821 /* Load second immediate field. */
822 u32 cmp_imm = decode_imm(ctx, imm_len); /* 2nd imm, at worst 8 bytes past prog_len */
823 u32 cnt = (cmp_imm >> 11) + 1; /* 1+, up to 32 fits in u16 */
824 u32 len = cmp_imm & 2047; /* 0..2047 */
825 u32 bytes = cnt * len;
826 const u32 last_packet_offs = ctx->R[0] + len - 1;
827 Boolean matched = False;
828 /* bytes = cnt * len is size in bytes of data to compare. */
829 /* pc is offset of program bytes to compare. */
830 /* imm is jump target offset. */
831 /* R0 is offset of packet bytes to compare. */
832 if (bytes > 0xFFFF) return EXCEPTION;
833 /* pc < program_len < ram_len < 2GiB, thus pc + bytes cannot wrap */
834 if (!IN_RAM_BOUNDS(ctx->pc + bytes - 1)) return EXCEPTION;
835 ASSERT_IN_PACKET_BOUNDS(ctx->R[0]);
836 /* Note: this will return EXCEPTION (due to wrap) if imm_len (ie. len) is 0 */
837 ASSERT_RETURN(last_packet_offs >= ctx->R[0]);
838 ASSERT_IN_PACKET_BOUNDS(last_packet_offs);
839 while (cnt--) {
840 matched |= !memcmp(ctx->program + ctx->pc, ctx->packet + ctx->R[0], len);
841 /* skip past comparison bytes */
842 ctx->pc += len;
843 }
844 if (matched ^ !reg_num) ctx->pc += imm;
845 break;
846 }
847 /* There is a difference in APFv4 and APFv6 arithmetic behaviour! */
848 /* APFv4: R[0] op= Rbit ? R[1] : imm; (and it thus doesn't make sense to have R=1 && len_field>0) */
849 /* APFv6+: REG op= len_field ? imm : OTHER_REG; (note: this is *DIFFERENT* with R=1 len_field==0) */
850 /* Furthermore APFv4 uses unsigned imm (except SH), while APFv6 uses signed_imm for ADD/AND/SH. */
851 case ADD_OPCODE: ARITH_REG += (ctx->v6) ? (u32)arith_signed_imm : arith_imm; break;
852 case MUL_OPCODE: ARITH_REG *= arith_imm; break;
853 case AND_OPCODE: ARITH_REG &= (ctx->v6) ? (u32)arith_signed_imm : arith_imm; break;
854 case OR_OPCODE: ARITH_REG |= arith_imm; break;
855 case DIV_OPCODE: { /* see above comment! */
856 const u32 div_operand = arith_imm;
857 ASSERT_RETURN(div_operand);
858 ARITH_REG /= div_operand;
859 break;
860 }
861 case SH_OPCODE: { /* see above comment! */
862 if (arith_signed_imm >= 0)
863 ARITH_REG <<= arith_signed_imm;
864 else
865 ARITH_REG >>= -arith_signed_imm;
866 break;
867 }
868 case LI_OPCODE:
869 REG = (u32)signed_imm;
870 break;
871 case PKTDATACOPY_OPCODE:
872 pktcopy_src_offset = imm;
873 imm = PKTDATACOPYIMM_EXT_OPCODE;
874 FALLTHROUGH;
875 case EXT_OPCODE:
876 if (/* imm >= LDM_EXT_OPCODE && -- but note imm is u32 and LDM_EXT_OPCODE is 0 */
877 imm < (LDM_EXT_OPCODE + MEMORY_ITEMS)) {
878 REG = ctx->mem.slot[imm - LDM_EXT_OPCODE];
879 } else if (imm >= STM_EXT_OPCODE && imm < (STM_EXT_OPCODE + MEMORY_ITEMS)) {
880 ctx->mem.slot[imm - STM_EXT_OPCODE] = REG;
881 } else switch (imm) {
882 case NOT_EXT_OPCODE: REG = ~REG; break;
883 case NEG_EXT_OPCODE: REG = -REG; break;
884 case MOV_EXT_OPCODE: REG = OTHER_REG; break;
885 case SWAP_EXT_OPCODE: {
886 u32 tmp = REG;
887 REG = OTHER_REG;
888 OTHER_REG = tmp;
889 break;
890 }
891 case ALLOCATE_EXT_OPCODE:
892 ASSERT_RETURN(ctx->tx_buf == NULL);
893 if (reg_num == 0) {
894 ctx->tx_buf_len = REG;
895 } else {
896 ctx->tx_buf_len = decode_be16(ctx); /* 2nd imm, at worst 6 B past prog_len */
897 }
898 /* checksumming functions requires minimum 266 byte buffer for correctness */
899 if (ctx->tx_buf_len < 266) ctx->tx_buf_len = 266;
900 ctx->tx_buf = apf_allocate_buffer(ctx->caller_ctx, ctx->tx_buf_len);
901 if (!ctx->tx_buf) { /* allocate failure */
902 ctx->tx_buf_len = 0;
903 counter[-3]++;
904 return EXCEPTION;
905 }
906 memset(ctx->tx_buf, 0, ctx->tx_buf_len);
907 ctx->mem.named.tx_buf_offset = 0;
908 break;
909 case TRANSMIT_EXT_OPCODE: {
910 /* tx_buf_len cannot be large because we'd run out of RAM, */
911 /* so the above unsigned comparison effectively guarantees casting pkt_len */
912 /* to a signed value does not result in it going negative. */
913 u8 ip_ofs = DECODE_U8(); /* 2nd imm, at worst 5 B past prog_len */
914 u8 csum_ofs = DECODE_U8(); /* 3rd imm, at worst 6 B past prog_len */
915 u8 csum_start = 0;
916 u16 partial_csum = 0;
917 u32 pkt_len = ctx->mem.named.tx_buf_offset;
918 ASSERT_RETURN(ctx->tx_buf);
919 /* If pkt_len > allocate_buffer_len, it means sth. wrong */
920 /* happened and the tx_buf should be deallocated. */
921 if (pkt_len > ctx->tx_buf_len) {
922 do_discard_buffer(ctx);
923 return EXCEPTION;
924 }
925 if (csum_ofs < 255) {
926 csum_start = DECODE_U8(); /* 4th imm, at worst 7 B past prog_len */
927 partial_csum = decode_be16(ctx); /* 5th imm, at worst 9 B past prog_len */
928 }
929 {
930 int dscp = apf_internal_csum_and_return_dscp(ctx->tx_buf, (s32)pkt_len, ip_ofs,
931 partial_csum, csum_start, csum_ofs,
932 (Boolean)reg_num);
933 int ret = apf_internal_do_transmit_buffer(ctx, pkt_len, dscp);
934 if (ret) { counter[-4]++; return EXCEPTION; } /* transmit failure */
935 }
936 break;
937 }
938 case EPKTDATACOPYIMM_EXT_OPCODE: /* 41 */
939 case EPKTDATACOPYR1_EXT_OPCODE: /* 42 */
940 pktcopy_src_offset = ctx->R[0];
941 FALLTHROUGH;
942 case PKTDATACOPYIMM_EXT_OPCODE: { /* 65536 */
943 u32 dst_offs = ctx->mem.named.tx_buf_offset;
944 u32 copy_len = ctx->R[1];
945 if (imm != EPKTDATACOPYR1_EXT_OPCODE) {
946 copy_len = DECODE_U8(); /* 2nd imm, at worst 8 bytes past prog_len */
947 }
948 ASSERT_RETURN(ctx->tx_buf);
949 ASSERT_IN_OUTPUT_BOUNDS(dst_offs, copy_len);
950 if (reg_num == 0) { /* copy from packet */
951 const u32 last_packet_offs = pktcopy_src_offset + copy_len - 1;
952 ASSERT_IN_PACKET_BOUNDS(pktcopy_src_offset);
953 ASSERT_RETURN(last_packet_offs >= pktcopy_src_offset);
954 ASSERT_IN_PACKET_BOUNDS(last_packet_offs);
955 memcpy(ctx->tx_buf + dst_offs, ctx->packet + pktcopy_src_offset, copy_len);
956 } else { /* copy from data */
957 ASSERT_IN_RAM_BOUNDS(pktcopy_src_offset + copy_len - 1);
958 memcpy(ctx->tx_buf + dst_offs, ctx->program + pktcopy_src_offset, copy_len);
959 }
960 dst_offs += copy_len;
961 ctx->mem.named.tx_buf_offset = dst_offs;
962 break;
963 }
964 case JDNSQMATCH_EXT_OPCODE: /* 43 */
965 case JDNSAMATCH_EXT_OPCODE: /* 44 */
966 case JDNSQMATCHSAFE_EXT_OPCODE: /* 45 */
967 case JDNSAMATCHSAFE_EXT_OPCODE: { /* 46 */
968 u32 jump_offs = decode_imm(ctx, imm_len); /* 2nd imm, at worst 8 B past prog_len */
969 int qtype = -1;
970 if (imm & 1) { /* JDNSQMATCH & JDNSQMATCHSAFE are *odd* extended opcodes */
971 qtype = DECODE_U8(); /* 3rd imm, at worst 9 bytes past prog_len */
972 }
973 {
974 u32 udp_payload_offset = ctx->R[0];
975 match_result_type match_rst = apf_internal_match_names(ctx->program + ctx->pc,
976 ctx->program + ctx->program_len,
977 ctx->packet + udp_payload_offset,
978 ctx->packet_len - udp_payload_offset,
979 qtype);
980 if (match_rst == error_program) return EXCEPTION;
981 if (match_rst == error_packet) {
982 counter[-5]++; /* increment error dns packet counter */
983 return (imm >= JDNSQMATCHSAFE_EXT_OPCODE) ? PASS : DROP;
984 }
985 while (ctx->pc + 1 < ctx->program_len &&
986 (ctx->program[ctx->pc] || ctx->program[ctx->pc + 1])) {
987 ctx->pc++;
988 }
989 ctx->pc += 2; /* skip the final double 0 needle end */
990 /* relies on reg_num in {0,1} and match_rst being {False=0, True=1} */
991 if (!(reg_num ^ (u32)match_rst)) ctx->pc += jump_offs;
992 }
993 break;
994 }
995 case EWRITE1_EXT_OPCODE:
996 case EWRITE2_EXT_OPCODE:
997 case EWRITE4_EXT_OPCODE: {
998 const u32 write_len = 1 << (imm - EWRITE1_EXT_OPCODE);
999 u32 i;
1000 ASSERT_RETURN(ctx->tx_buf);
1001 ASSERT_IN_OUTPUT_BOUNDS(ctx->mem.named.tx_buf_offset, write_len);
1002 for (i = 0; i < write_len; ++i) {
1003 ctx->tx_buf[ctx->mem.named.tx_buf_offset++] =
1004 (u8)(REG >> (write_len - 1 - i) * 8);
1005 }
1006 break;
1007 }
1008 case JONEOF_EXT_OPCODE: {
1009 u32 jump_offs = decode_imm(ctx, imm_len); /* 2nd imm, at worst 8 B past prog_len */
1010 u8 imm3 = DECODE_U8(); /* 3rd imm, at worst 9 bytes past prog_len */
1011 Boolean jmp = imm3 & 1; /* =0 jmp on match, =1 jmp on no match */
1012 u8 len = ((imm3 >> 1) & 3) + 1; /* size [1..4] in bytes of an element */
1013 u8 cnt = (imm3 >> 3) + 2; /* number [2..33] of elements in set */
1014 if (ctx->pc + cnt * len > ctx->program_len) return EXCEPTION;
1015 while (cnt--) {
1016 u32 v = 0;
1017 int i;
1018 for (i = 0; i < len; ++i) v = (v << 8) | DECODE_U8();
1019 if (REG == v) jmp ^= True;
1020 }
1021 if (jmp) ctx->pc += jump_offs;
1022 break;
1023 }
1024 case EXCEPTIONBUFFER_EXT_OPCODE: {
1025 ctx->except_buf_sz = decode_be16(ctx);
1026 break;
1027 }
1028 default: /* Unknown extended opcode */
1029 return EXCEPTION; /* Bail out */
1030 }
1031 break;
1032 case LDDW_OPCODE:
1033 case STDW_OPCODE:
1034 if (ctx->v6) {
1035 if (!imm) return EXCEPTION;
1036 if (imm > 0xFFFF) return EXCEPTION;
1037 if (imm * 4 > ctx->ram_len) return EXCEPTION;
1038 if (opcode == LDDW_OPCODE) {
1039 REG = counter[-(s32)imm];
1040 } else {
1041 counter[-(s32)imm] = REG;
1042 }
1043 } else {
1044 u32 size = 4;
1045 u32 offs = OTHER_REG + (u32)signed_imm;
1046 /* Negative offsets wrap around the end of the address space. */
1047 /* This allows us to efficiently access the end of the */
1048 /* address space with one-byte immediates without using %=. */
1049 if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */
1050 ASSERT_IN_DATA_BOUNDS(offs, size);
1051 if (opcode == LDDW_OPCODE) {
1052 u32 val = 0;
1053 while (size--) val = (val << 8) | ctx->program[offs++];
1054 REG = val;
1055 } else {
1056 u32 val = REG;
1057 while (size--) {
1058 ctx->program[offs++] = (val >> 24);
1059 val <<= 8;
1060 }
1061 }
1062 }
1063 break;
1064 case WRITE_OPCODE: {
1065 ASSERT_RETURN(ctx->tx_buf);
1066 ASSERT_RETURN(len_field);
1067 {
1068 const u32 write_len = 1 << (len_field - 1);
1069 u32 i;
1070 ASSERT_IN_OUTPUT_BOUNDS(ctx->mem.named.tx_buf_offset, write_len);
1071 for (i = 0; i < write_len; ++i) {
1072 ctx->tx_buf[ctx->mem.named.tx_buf_offset++] =
1073 (u8)(imm >> (write_len - 1 - i) * 8);
1074 }
1075 }
1076 break;
1077 }
1078 default: /* Unknown opcode */
1079 return EXCEPTION; /* Bail out */
1080 }
1081 }
1082 } while (instructions_remaining--);
1083 return EXCEPTION;
1084 }
1085
apf_runner(void * ctx,u32 * const program,const u32 program_len,const u32 ram_len,const u8 * const packet,const u32 packet_len,const u32 filter_age_16384ths)1086 static int apf_runner(void* ctx, u32* const program, const u32 program_len,
1087 const u32 ram_len, const u8* const packet,
1088 const u32 packet_len, const u32 filter_age_16384ths) {
1089 /* Due to direct 32-bit read/write access to counters at end of ram */
1090 /* APFv6 interpreter requires program & ram_len to be 4 byte aligned. */
1091 if (3 & (uintptr_t)program) return EXCEPTION;
1092 if (3 & ram_len) return EXCEPTION;
1093
1094 /* We rely on ram_len + 65536 not overflowing, so require ram_len < 2GiB */
1095 /* Similarly LDDW/STDW have special meaning for negative ram offsets. */
1096 /* We also don't want garbage like program_len == 0xFFFFFFFF */
1097 if ((program_len | ram_len) >> 31) return EXCEPTION;
1098
1099 {
1100 apf_context apf_ctx = { 0 };
1101 int ret;
1102
1103 apf_ctx.ptr_size = sizeof(void*);
1104 apf_ctx.caller_ctx = ctx;
1105 apf_ctx.program = (u8*)program;
1106 apf_ctx.program_len = program_len;
1107 apf_ctx.ram_len = ram_len;
1108 apf_ctx.packet = packet;
1109 apf_ctx.packet_len = packet_len;
1110 /* Fill in pre-filled memory slot values. */
1111 apf_ctx.mem.named.program_size = program_len;
1112 apf_ctx.mem.named.ram_len = ram_len;
1113 apf_ctx.mem.named.packet_size = packet_len;
1114 apf_ctx.mem.named.apf_version = apf_version();
1115 apf_ctx.mem.named.filter_age = filter_age_16384ths >> 14;
1116 apf_ctx.mem.named.filter_age_16384ths = filter_age_16384ths;
1117
1118 ret = do_apf_run(&apf_ctx);
1119 if (apf_ctx.tx_buf) do_discard_buffer(&apf_ctx);
1120 /* Convert any exceptions internal to the program to just normal 'PASS' */
1121 if (ret >= EXCEPTION) {
1122 u16 buf_size = apf_ctx.except_buf_sz;
1123 if (buf_size >= sizeof(apf_ctx) && apf_ctx.program_len + buf_size <= apf_ctx.ram_len) {
1124 u8* buf = apf_ctx.program + apf_ctx.program_len;
1125 memcpy(buf, &apf_ctx, sizeof(apf_ctx));
1126 buf_size -= sizeof(apf_ctx);
1127 buf += sizeof(apf_ctx);
1128 if (buf_size > apf_ctx.packet_len) buf_size = apf_ctx.packet_len;
1129 memcpy(buf, apf_ctx.packet, buf_size);
1130 }
1131 ret = PASS;
1132 }
1133 return ret;
1134 }
1135 }
1136
apf_run(void * ctx,u32 * const program,const u32 program_len,const u32 ram_len,const u8 * const packet,const u32 packet_len,const u32 filter_age_16384ths)1137 int apf_run(void* ctx, u32* const program, const u32 program_len,
1138 const u32 ram_len, const u8* const packet,
1139 const u32 packet_len, const u32 filter_age_16384ths) {
1140 /* Any valid ethernet packet should be at least ETH_HLEN long... */
1141 if (!packet) return EXCEPTION;
1142 if (packet_len < ETH_HLEN) return EXCEPTION;
1143
1144 return apf_runner(ctx, program, program_len, ram_len, packet, packet_len, filter_age_16384ths);
1145 }
1146