Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <errno.h>
9 : : #include <stdint.h>
10 : : #include <inttypes.h>
11 : :
12 : : #include <rte_common.h>
13 : :
14 : : #include "bpf_impl.h"
15 : :
16 : : #define BPF_ARG_PTR_STACK RTE_BPF_ARG_RESERVED
17 : :
18 : : struct bpf_reg_val {
19 : : struct rte_bpf_arg v;
20 : : uint64_t mask;
21 : : struct {
22 : : int64_t min;
23 : : int64_t max;
24 : : } s;
25 : : struct {
26 : : uint64_t min;
27 : : uint64_t max;
28 : : } u;
29 : : };
30 : :
31 : : struct bpf_eval_state {
32 : : SLIST_ENTRY(bpf_eval_state) next; /* for @safe list traversal */
33 : : struct bpf_reg_val rv[EBPF_REG_NUM];
34 : : struct bpf_reg_val sv[MAX_BPF_STACK_SIZE / sizeof(uint64_t)];
35 : : };
36 : :
37 : : SLIST_HEAD(bpf_evst_head, bpf_eval_state);
38 : :
39 : : /* possible instruction node colour */
40 : : enum {
41 : : WHITE,
42 : : GREY,
43 : : BLACK,
44 : : MAX_NODE_COLOUR
45 : : };
46 : :
47 : : /* possible edge types */
48 : : enum {
49 : : UNKNOWN_EDGE,
50 : : TREE_EDGE,
51 : : BACK_EDGE,
52 : : CROSS_EDGE,
53 : : MAX_EDGE_TYPE
54 : : };
55 : :
56 : : #define MAX_EDGES 2
57 : :
58 : : /* max number of 'safe' evaluated states to track per node */
59 : : #define NODE_EVST_MAX 32
60 : :
61 : : struct inst_node {
62 : : uint8_t colour;
63 : : uint8_t nb_edge:4;
64 : : uint8_t cur_edge:4;
65 : : uint8_t edge_type[MAX_EDGES];
66 : : uint32_t edge_dest[MAX_EDGES];
67 : : struct inst_node *prev_node;
68 : : struct {
69 : : struct bpf_eval_state *cur; /* save/restore for jcc targets */
70 : : struct bpf_eval_state *start;
71 : : struct bpf_evst_head safe; /* safe states for track/prune */
72 : : uint32_t nb_safe;
73 : : } evst;
74 : : };
75 : :
76 : : struct evst_pool {
77 : : uint32_t num;
78 : : uint32_t cur;
79 : : struct bpf_eval_state *ent;
80 : : };
81 : :
82 : : struct bpf_verifier {
83 : : const struct rte_bpf_prm *prm;
84 : : struct inst_node *in;
85 : : uint64_t stack_sz;
86 : : uint32_t nb_nodes;
87 : : uint32_t nb_jcc_nodes;
88 : : uint32_t nb_ldmb_nodes;
89 : : uint32_t node_colour[MAX_NODE_COLOUR];
90 : : uint32_t edge_type[MAX_EDGE_TYPE];
91 : : struct bpf_eval_state *evst;
92 : : struct inst_node *evin;
93 : : struct evst_pool evst_sr_pool; /* for evst save/restore */
94 : : struct evst_pool evst_tp_pool; /* for evst track/prune */
95 : : };
96 : :
97 : : struct bpf_ins_check {
98 : : struct {
99 : : uint16_t dreg;
100 : : uint16_t sreg;
101 : : } mask;
102 : : struct {
103 : : uint16_t min;
104 : : uint16_t max;
105 : : } off;
106 : : struct {
107 : : uint32_t min;
108 : : uint32_t max;
109 : : } imm;
110 : : const char * (*check)(const struct ebpf_insn *);
111 : : const char * (*eval)(struct bpf_verifier *, const struct ebpf_insn *);
112 : : };
113 : :
114 : : #define ALL_REGS RTE_LEN2MASK(EBPF_REG_NUM, uint16_t)
115 : : #define WRT_REGS RTE_LEN2MASK(EBPF_REG_10, uint16_t)
116 : : #define ZERO_REG RTE_LEN2MASK(EBPF_REG_1, uint16_t)
117 : :
118 : : /* For LD_IND R6 is an implicit CTX register. */
119 : : #define IND_SRC_REGS (WRT_REGS ^ 1 << EBPF_REG_6)
120 : :
121 : : /*
122 : : * check and evaluate functions for particular instruction types.
123 : : */
124 : :
125 : : static const char *
126 : 8 : check_alu_bele(const struct ebpf_insn *ins)
127 : : {
128 [ + + - + ]: 8 : if (ins->imm != 16 && ins->imm != 32 && ins->imm != 64)
129 : 0 : return "invalid imm field";
130 : : return NULL;
131 : : }
132 : :
133 : : static const char *
134 : 539 : eval_exit(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
135 : : {
136 : : RTE_SET_USED(ins);
137 [ + + ]: 539 : if (bvf->evst->rv[EBPF_REG_0].v.type == RTE_BPF_ARG_UNDEF)
138 : 1 : return "undefined return value";
139 : : return NULL;
140 : : }
141 : :
142 : : /* setup max possible with this mask bounds */
143 : : static void
144 : : eval_umax_bound(struct bpf_reg_val *rv, uint64_t mask)
145 : : {
146 : 584 : rv->u.max = mask;
147 : 584 : rv->u.min = 0;
148 : 53 : }
149 : :
150 : : static void
151 : : eval_smax_bound(struct bpf_reg_val *rv, uint64_t mask)
152 : : {
153 : 1688 : rv->s.max = mask >> 1;
154 : 1688 : rv->s.min = rv->s.max ^ UINT64_MAX;
155 : 61 : }
156 : :
157 : : static void
158 : : eval_max_bound(struct bpf_reg_val *rv, uint64_t mask)
159 : : {
160 : : eval_umax_bound(rv, mask);
161 : : eval_smax_bound(rv, mask);
162 : 113 : }
163 : :
164 : : static void
165 : : eval_fill_max_bound(struct bpf_reg_val *rv, uint64_t mask)
166 : : {
167 : : eval_max_bound(rv, mask);
168 : 386 : rv->v.type = RTE_BPF_ARG_RAW;
169 : 386 : rv->mask = mask;
170 : 104 : }
171 : :
172 : : static void
173 : : eval_fill_imm64(struct bpf_reg_val *rv, uint64_t mask, uint64_t val)
174 : : {
175 : 1205 : rv->mask = mask;
176 : 1370 : rv->s.min = val;
177 : 1360 : rv->s.max = val;
178 : 1360 : rv->u.min = val;
179 : 1360 : rv->u.max = val;
180 : 1 : }
181 : :
182 : : static void
183 : : eval_fill_imm(struct bpf_reg_val *rv, uint64_t mask, int32_t imm)
184 : : {
185 : : uint64_t v;
186 : :
187 : 1065 : v = (uint64_t)imm & mask;
188 : :
189 : 0 : rv->v.type = RTE_BPF_ARG_RAW;
190 : : eval_fill_imm64(rv, mask, v);
191 : 59 : }
192 : :
193 : : static const char *
194 : 245 : eval_ld_imm64(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
195 : : {
196 : : uint32_t i;
197 : : uint64_t val;
198 : : struct bpf_reg_val *rd;
199 : :
200 : 245 : val = (uint32_t)ins[0].imm | (uint64_t)(uint32_t)ins[1].imm << 32;
201 : :
202 : 245 : rd = bvf->evst->rv + ins->dst_reg;
203 : 245 : rd->v.type = RTE_BPF_ARG_RAW;
204 : : eval_fill_imm64(rd, UINT64_MAX, val);
205 : :
206 [ - + ]: 245 : for (i = 0; i != bvf->prm->nb_xsym; i++) {
207 : :
208 : : /* load of external variable */
209 [ # # ]: 0 : if (bvf->prm->xsym[i].type == RTE_BPF_XTYPE_VAR &&
210 [ # # ]: 0 : (uintptr_t)bvf->prm->xsym[i].var.val == val) {
211 : 0 : rd->v = bvf->prm->xsym[i].var.desc;
212 : : eval_fill_imm64(rd, UINT64_MAX, 0);
213 : : break;
214 : : }
215 : : }
216 : :
217 : 245 : return NULL;
218 : : }
219 : :
220 : : static void
221 : : eval_apply_mask(struct bpf_reg_val *rv, uint64_t mask)
222 : : {
223 : : struct bpf_reg_val rt;
224 : :
225 : 1111 : rt.u.min = rv->u.min & mask;
226 : 1111 : rt.u.max = rv->u.max & mask;
227 [ + + - + : 1110 : if (rt.u.min != rv->u.min || rt.u.max != rv->u.max) {
+ - - + +
+ + - +
+ ]
228 : 13 : rv->u.max = RTE_MAX(rt.u.max, mask);
229 : 44 : rv->u.min = 0;
230 : : }
231 : :
232 : : eval_smax_bound(&rt, mask);
233 : 1111 : rv->s.max = RTE_MIN(rt.s.max, rv->s.max);
234 : 1111 : rv->s.min = RTE_MAX(rt.s.min, rv->s.min);
235 : :
236 : 1034 : rv->mask = mask;
237 : 303 : }
238 : :
239 : : static void
240 : 235 : eval_add(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, uint64_t msk)
241 : : {
242 : : struct bpf_reg_val rv;
243 : :
244 : 235 : rv.u.min = (rd->u.min + rs->u.min) & msk;
245 : 235 : rv.u.max = (rd->u.max + rs->u.max) & msk;
246 : 235 : rv.s.min = ((uint64_t)rd->s.min + (uint64_t)rs->s.min) & msk;
247 : 235 : rv.s.max = ((uint64_t)rd->s.max + (uint64_t)rs->s.max) & msk;
248 : :
249 : : /*
250 : : * if at least one of the operands is not constant,
251 : : * then check for overflow
252 : : */
253 [ + + + + : 235 : if ((rd->u.min != rd->u.max || rs->u.min != rs->u.max) &&
+ - ]
254 [ + + ]: 63 : (rv.u.min < rd->u.min || rv.u.max < rd->u.max))
255 : : eval_umax_bound(&rv, msk);
256 : :
257 [ + + + + : 235 : if ((rd->s.min != rd->s.max || rs->s.min != rs->s.max) &&
+ + ]
258 [ + + + + ]: 63 : (((rs->s.min < 0 && rv.s.min > rd->s.min) ||
259 [ - + ]: 38 : rv.s.min < rd->s.min) ||
260 [ - - + + ]: 38 : ((rs->s.max < 0 && rv.s.max > rd->s.max) ||
261 : : rv.s.max < rd->s.max)))
262 : : eval_smax_bound(&rv, msk);
263 : :
264 : 235 : rd->s = rv.s;
265 : 235 : rd->u = rv.u;
266 : 235 : }
267 : :
268 : : static void
269 : 7 : eval_sub(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, uint64_t msk)
270 : : {
271 : : struct bpf_reg_val rv;
272 : :
273 : 7 : rv.u.min = (rd->u.min - rs->u.max) & msk;
274 : 7 : rv.u.max = (rd->u.max - rs->u.min) & msk;
275 : 7 : rv.s.min = ((uint64_t)rd->s.min - (uint64_t)rs->s.max) & msk;
276 : 7 : rv.s.max = ((uint64_t)rd->s.max - (uint64_t)rs->s.min) & msk;
277 : :
278 : : /*
279 : : * if at least one of the operands is not constant,
280 : : * then check for overflow
281 : : */
282 [ + + - + : 7 : if ((rd->u.min != rd->u.max || rs->u.min != rs->u.max) &&
- + ]
283 [ # # ]: 0 : (rv.u.min > rd->u.min || rv.u.max > rd->u.max))
284 : : eval_umax_bound(&rv, msk);
285 : :
286 [ + + - + : 7 : if ((rd->s.min != rd->s.max || rs->s.min != rs->s.max) &&
+ + ]
287 [ + - - + ]: 4 : (((rs->s.min < 0 && rv.s.min < rd->s.min) ||
288 [ # # ]: 0 : rv.s.min > rd->s.min) ||
289 [ # # # # ]: 0 : ((rs->s.max < 0 && rv.s.max < rd->s.max) ||
290 : : rv.s.max > rd->s.max)))
291 : : eval_smax_bound(&rv, msk);
292 : :
293 : 7 : rd->s = rv.s;
294 : 7 : rd->u = rv.u;
295 : 7 : }
296 : :
297 : : static void
298 : 22 : eval_lsh(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
299 : : uint64_t msk)
300 : : {
301 : : /* check if shift value is less then max result bits */
302 [ + + ]: 22 : if (rs->u.max >= opsz) {
303 : : eval_max_bound(rd, msk);
304 : 2 : return;
305 : : }
306 : :
307 : : /* check for overflow */
308 [ + + ]: 20 : if (rd->u.max > RTE_LEN2MASK(opsz - rs->u.max, uint64_t))
309 : : eval_umax_bound(rd, msk);
310 : : else {
311 : 2 : rd->u.max <<= rs->u.max;
312 : 2 : rd->u.min <<= rs->u.min;
313 : : }
314 : :
315 : : /* check that dreg values are and would remain always positive */
316 [ + + ]: 20 : if ((uint64_t)rd->s.min >> (opsz - 1) != 0 || rd->s.max >=
317 [ + - ]: 18 : RTE_LEN2MASK(opsz - rs->u.max - 1, int64_t))
318 : : eval_smax_bound(rd, msk);
319 : : else {
320 : 0 : rd->s.max <<= rs->u.max;
321 : 0 : rd->s.min <<= rs->u.min;
322 : : }
323 : : }
324 : :
325 : : static void
326 : 11 : eval_rsh(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
327 : : uint64_t msk)
328 : : {
329 : : /* check if shift value is less then max result bits */
330 [ + + ]: 11 : if (rs->u.max >= opsz) {
331 : : eval_max_bound(rd, msk);
332 : 1 : return;
333 : : }
334 : :
335 : 10 : rd->u.max >>= rs->u.min;
336 : 10 : rd->u.min >>= rs->u.max;
337 : :
338 : : /* check that dreg values are always positive */
339 [ + + ]: 10 : if ((uint64_t)rd->s.min >> (opsz - 1) != 0)
340 : : eval_smax_bound(rd, msk);
341 : : else {
342 : 5 : rd->s.max >>= rs->u.min;
343 : 5 : rd->s.min >>= rs->u.max;
344 : : }
345 : : }
346 : :
347 : : static void
348 : 2 : eval_arsh(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
349 : : uint64_t msk)
350 : : {
351 : : uint32_t shv;
352 : :
353 : : /* check if shift value is less then max result bits */
354 [ + + ]: 2 : if (rs->u.max >= opsz) {
355 : : eval_max_bound(rd, msk);
356 : 1 : return;
357 : : }
358 : :
359 : 1 : rd->u.max = (int64_t)rd->u.max >> rs->u.min;
360 : 1 : rd->u.min = (int64_t)rd->u.min >> rs->u.max;
361 : :
362 : : /* if we have 32-bit values - extend them to 64-bit */
363 [ - + ]: 1 : if (opsz == sizeof(uint32_t) * CHAR_BIT) {
364 : 0 : rd->s.min <<= opsz;
365 : 0 : rd->s.max <<= opsz;
366 : : shv = opsz;
367 : : } else
368 : : shv = 0;
369 : :
370 [ - + ]: 1 : if (rd->s.min < 0)
371 : 0 : rd->s.min = (rd->s.min >> (rs->u.min + shv)) & msk;
372 : : else
373 : 1 : rd->s.min = (rd->s.min >> (rs->u.max + shv)) & msk;
374 : :
375 [ + - ]: 1 : if (rd->s.max < 0)
376 : 1 : rd->s.max = (rd->s.max >> (rs->u.max + shv)) & msk;
377 : : else
378 : 0 : rd->s.max = (rd->s.max >> (rs->u.min + shv)) & msk;
379 : : }
380 : :
381 : : static uint64_t
382 : : eval_umax_bits(uint64_t v, size_t opsz)
383 : : {
384 [ + - + - : 121 : if (v == 0)
+ - + - +
- + - ]
385 : : return 0;
386 : :
387 : : v = rte_clz64(v);
388 : 242 : return RTE_LEN2MASK(opsz - v, uint64_t);
389 : : }
390 : :
391 : : /* estimate max possible value for (v1 & v2) */
392 : : static uint64_t
393 : : eval_uand_max(uint64_t v1, uint64_t v2, size_t opsz)
394 : : {
395 : : v1 = eval_umax_bits(v1, opsz);
396 : : v2 = eval_umax_bits(v2, opsz);
397 : 107 : return (v1 & v2);
398 : : }
399 : :
400 : : /* estimate max possible value for (v1 | v2) */
401 : : static uint64_t
402 : : eval_uor_max(uint64_t v1, uint64_t v2, size_t opsz)
403 : : {
404 : : v1 = eval_umax_bits(v1, opsz);
405 : : v2 = eval_umax_bits(v2, opsz);
406 : 14 : return (v1 | v2);
407 : : }
408 : :
409 : : static void
410 : 54 : eval_and(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
411 : : uint64_t msk)
412 : : {
413 : : /* both operands are constants */
414 [ - + - - ]: 54 : if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
415 : 0 : rd->u.min &= rs->u.min;
416 : 0 : rd->u.max &= rs->u.max;
417 : : } else {
418 [ + - ]: 54 : rd->u.max = eval_uand_max(rd->u.max, rs->u.max, opsz);
419 : 54 : rd->u.min &= rs->u.min;
420 : : }
421 : :
422 : : /* both operands are constants */
423 [ - + - - ]: 54 : if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
424 : 0 : rd->s.min &= rs->s.min;
425 : 0 : rd->s.max &= rs->s.max;
426 : : /* at least one of operand is non-negative */
427 [ + + + + ]: 54 : } else if (rd->s.min >= 0 || rs->s.min >= 0) {
428 : 106 : rd->s.max = eval_uand_max(rd->s.max & (msk >> 1),
429 [ + - ]: 53 : rs->s.max & (msk >> 1), opsz);
430 : 53 : rd->s.min &= rs->s.min;
431 : : } else
432 : : eval_smax_bound(rd, msk);
433 : 54 : }
434 : :
435 : : static void
436 : 259 : eval_or(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
437 : : uint64_t msk)
438 : : {
439 : : /* both operands are constants */
440 [ + + + - ]: 259 : if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
441 : 255 : rd->u.min |= rs->u.min;
442 : 255 : rd->u.max |= rs->u.max;
443 : : } else {
444 [ + - ]: 4 : rd->u.max = eval_uor_max(rd->u.max, rs->u.max, opsz);
445 : 4 : rd->u.min |= rs->u.min;
446 : : }
447 : :
448 : : /* both operands are constants */
449 [ + + + - ]: 259 : if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
450 : 255 : rd->s.min |= rs->s.min;
451 : 255 : rd->s.max |= rs->s.max;
452 : :
453 : : /* both operands are non-negative */
454 [ - + - - ]: 4 : } else if (rd->s.min >= 0 || rs->s.min >= 0) {
455 [ + - ]: 4 : rd->s.max = eval_uor_max(rd->s.max, rs->s.max, opsz);
456 : 4 : rd->s.min |= rs->s.min;
457 : : } else
458 : : eval_smax_bound(rd, msk);
459 : 259 : }
460 : :
461 : : static void
462 : 62 : eval_xor(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
463 : : uint64_t msk)
464 : : {
465 : : /* both operands are constants */
466 [ + + + - ]: 62 : if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
467 : 59 : rd->u.min ^= rs->u.min;
468 : 59 : rd->u.max ^= rs->u.max;
469 : : } else {
470 [ + - ]: 3 : rd->u.max = eval_uor_max(rd->u.max, rs->u.max, opsz);
471 : 3 : rd->u.min = 0;
472 : : }
473 : :
474 : : /* both operands are constants */
475 [ + + + - ]: 62 : if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
476 : 59 : rd->s.min ^= rs->s.min;
477 : 59 : rd->s.max ^= rs->s.max;
478 : :
479 : : /* both operands are non-negative */
480 [ + + + - ]: 3 : } else if (rd->s.min >= 0 || rs->s.min >= 0) {
481 [ + - ]: 3 : rd->s.max = eval_uor_max(rd->s.max, rs->s.max, opsz);
482 : 3 : rd->s.min = 0;
483 : : } else
484 : : eval_smax_bound(rd, msk);
485 : 62 : }
486 : :
487 : : static void
488 : 9 : eval_mul(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
489 : : uint64_t msk)
490 : : {
491 : : /* both operands are constants */
492 [ + + - + ]: 9 : if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
493 : 0 : rd->u.min = (rd->u.min * rs->u.min) & msk;
494 : 0 : rd->u.max = (rd->u.max * rs->u.max) & msk;
495 : : /* check for overflow */
496 [ + + + + ]: 9 : } else if (rd->u.max <= msk >> opsz / 2 && rs->u.max <= msk >> opsz) {
497 : 1 : rd->u.max *= rs->u.max;
498 : 1 : rd->u.min *= rd->u.min;
499 : : } else
500 : : eval_umax_bound(rd, msk);
501 : :
502 : : /* both operands are constants */
503 [ + + - + ]: 9 : if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
504 : 0 : rd->s.min = (rd->s.min * rs->s.min) & msk;
505 : 0 : rd->s.max = (rd->s.max * rs->s.max) & msk;
506 : : /* check that both operands are positive and no overflow */
507 [ + - + + ]: 9 : } else if (rd->s.min >= 0 && rs->s.min >= 0) {
508 : 7 : rd->s.max *= rs->s.max;
509 : 7 : rd->s.min *= rd->s.min;
510 : : } else
511 : : eval_smax_bound(rd, msk);
512 : 9 : }
513 : :
514 : : static const char *
515 : 5 : eval_divmod(uint32_t op, struct bpf_reg_val *rd, struct bpf_reg_val *rs,
516 : : size_t opsz, uint64_t msk)
517 : : {
518 : : /* both operands are constants */
519 [ - + - - ]: 5 : if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
520 [ # # ]: 0 : if (rs->u.max == 0)
521 : : return "division by 0";
522 [ # # ]: 0 : if (op == BPF_DIV) {
523 : 0 : rd->u.min /= rs->u.min;
524 : 0 : rd->u.max /= rs->u.max;
525 : : } else {
526 : 0 : rd->u.min %= rs->u.min;
527 : 0 : rd->u.max %= rs->u.max;
528 : : }
529 : : } else {
530 [ + + ]: 5 : if (op == BPF_MOD)
531 : 2 : rd->u.max = RTE_MIN(rd->u.max, rs->u.max - 1);
532 : : else
533 : : rd->u.max = rd->u.max;
534 : 5 : rd->u.min = 0;
535 : : }
536 : :
537 : : /* if we have 32-bit values - extend them to 64-bit */
538 [ + + ]: 5 : if (opsz == sizeof(uint32_t) * CHAR_BIT) {
539 : 3 : rd->s.min = (int32_t)rd->s.min;
540 : 3 : rd->s.max = (int32_t)rd->s.max;
541 : 3 : rs->s.min = (int32_t)rs->s.min;
542 : 3 : rs->s.max = (int32_t)rs->s.max;
543 : : }
544 : :
545 : : /* both operands are constants */
546 [ - + - - ]: 5 : if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
547 [ # # ]: 0 : if (rs->s.max == 0)
548 : : return "division by 0";
549 [ # # ]: 0 : if (op == BPF_DIV) {
550 : 0 : rd->s.min /= rs->s.min;
551 : 0 : rd->s.max /= rs->s.max;
552 : : } else {
553 : 0 : rd->s.min %= rs->s.min;
554 : 0 : rd->s.max %= rs->s.max;
555 : : }
556 [ + + ]: 5 : } else if (op == BPF_MOD) {
557 : : rd->s.min = RTE_MAX(rd->s.max, 0);
558 : 2 : rd->s.min = RTE_MIN(rd->s.min, 0);
559 : : } else
560 : : eval_smax_bound(rd, msk);
561 : :
562 : 5 : rd->s.max &= msk;
563 : 5 : rd->s.min &= msk;
564 : :
565 : 5 : return NULL;
566 : : }
567 : :
568 : : static void
569 : 6 : eval_neg(struct bpf_reg_val *rd, size_t opsz, uint64_t msk)
570 : : {
571 : : uint64_t ux, uy;
572 : : int64_t sx, sy;
573 : :
574 : : /* if we have 32-bit values - extend them to 64-bit */
575 [ + + ]: 6 : if (opsz == sizeof(uint32_t) * CHAR_BIT) {
576 : 1 : rd->u.min = (int32_t)rd->u.min;
577 : 1 : rd->u.max = (int32_t)rd->u.max;
578 : : }
579 : :
580 : 6 : ux = -(int64_t)rd->u.min & msk;
581 : 6 : uy = -(int64_t)rd->u.max & msk;
582 : :
583 : 6 : rd->u.max = RTE_MAX(ux, uy);
584 : 6 : rd->u.min = RTE_MIN(ux, uy);
585 : :
586 : : /* if we have 32-bit values - extend them to 64-bit */
587 [ + + ]: 6 : if (opsz == sizeof(uint32_t) * CHAR_BIT) {
588 : 1 : rd->s.min = (int32_t)rd->s.min;
589 : 1 : rd->s.max = (int32_t)rd->s.max;
590 : : }
591 : :
592 : 6 : sx = -rd->s.min & msk;
593 : 6 : sy = -rd->s.max & msk;
594 : :
595 : 6 : rd->s.max = RTE_MAX(sx, sy);
596 : 6 : rd->s.min = RTE_MIN(sx, sy);
597 : 6 : }
598 : :
599 : : static const char *
600 : 277 : eval_ld_mbuf(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
601 : : {
602 : : uint32_t i, mode;
603 : : struct bpf_reg_val *rv, ri, rs;
604 : :
605 : 277 : mode = BPF_MODE(ins->code);
606 : :
607 : : /* R6 is an implicit input that must contain pointer to mbuf */
608 [ + - ]: 277 : if (bvf->evst->rv[EBPF_REG_6].v.type != RTE_BPF_ARG_PTR_MBUF)
609 : : return "invalid type for implicit ctx register";
610 : :
611 [ + + ]: 277 : if (mode == BPF_IND) {
612 : 39 : rs = bvf->evst->rv[ins->src_reg];
613 [ + - ]: 39 : if (rs.v.type != RTE_BPF_ARG_RAW)
614 : : return "unexpected type for src register";
615 : :
616 : 39 : eval_fill_imm(&ri, UINT64_MAX, ins->imm);
617 : 39 : eval_add(&rs, &ri, UINT64_MAX);
618 : :
619 [ + - + - ]: 39 : if (rs.s.max < 0 || rs.u.min > UINT32_MAX)
620 : : return "mbuf boundary violation";
621 : : }
622 : :
623 : : /* R1-R5 scratch registers */
624 [ + + ]: 1662 : for (i = EBPF_REG_1; i != EBPF_REG_6; i++)
625 : 1385 : bvf->evst->rv[i].v.type = RTE_BPF_ARG_UNDEF;
626 : :
627 : : /* R0 is an implicit output, contains data fetched from the packet */
628 : : rv = bvf->evst->rv + EBPF_REG_0;
629 [ + + ]: 277 : rv->v.size = bpf_size(BPF_SIZE(ins->code));
630 : 277 : eval_fill_max_bound(rv, RTE_LEN2MASK(rv->v.size * CHAR_BIT, uint64_t));
631 : :
632 : 277 : return NULL;
633 : : }
634 : :
635 : : /*
636 : : * check that destination and source operand are in defined state.
637 : : */
638 : : static const char *
639 : : eval_defined(const struct bpf_reg_val *dst, const struct bpf_reg_val *src)
640 : : {
641 [ + - + - ]: 1041 : if (dst != NULL && dst->v.type == RTE_BPF_ARG_UNDEF)
642 : : return "dest reg value is undefined";
643 [ - + + - : 1458 : if (src != NULL && src->v.type == RTE_BPF_ARG_UNDEF)
+ + - + ]
644 : : return "src reg value is undefined";
645 : : return NULL;
646 : : }
647 : :
648 : : static const char *
649 : 808 : eval_alu(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
650 : : {
651 : : uint64_t msk;
652 : : uint32_t op;
653 : : size_t opsz, sz;
654 : : const char *err;
655 : : struct bpf_eval_state *st;
656 : : struct bpf_reg_val *rd, rs;
657 : :
658 : 808 : sz = (BPF_CLASS(ins->code) == BPF_ALU) ?
659 [ + + ]: 808 : sizeof(uint32_t) : sizeof(uint64_t);
660 : 808 : opsz = sz * CHAR_BIT;
661 : 808 : msk = RTE_LEN2MASK(opsz, uint64_t);
662 : :
663 : 808 : st = bvf->evst;
664 : 808 : rd = st->rv + ins->dst_reg;
665 : :
666 [ + + ]: 808 : if (BPF_SRC(ins->code) == BPF_X) {
667 [ + + ]: 223 : rs = st->rv[ins->src_reg];
668 : : eval_apply_mask(&rs, msk);
669 : : } else {
670 : 585 : rs = (struct bpf_reg_val){.v = {.size = sz,},};
671 : 585 : eval_fill_imm(&rs, msk, ins->imm);
672 : : }
673 : :
674 : : eval_apply_mask(rd, msk);
675 : :
676 : 808 : op = BPF_OP(ins->code);
677 : :
678 : : /* Allow self-xor as way to zero register */
679 [ + + + + ]: 808 : if (op == BPF_XOR && BPF_SRC(ins->code) == BPF_X &&
680 [ + + ]: 60 : ins->src_reg == ins->dst_reg) {
681 : : eval_fill_imm(&rs, UINT64_MAX, 0);
682 : : eval_fill_imm(rd, UINT64_MAX, 0);
683 : : }
684 : :
685 [ + + + + ]: 814 : err = eval_defined((op != EBPF_MOV) ? rd : NULL,
686 : : (op != BPF_NEG) ? &rs : NULL);
687 : : if (err != NULL)
688 : 0 : return err;
689 : :
690 [ + + ]: 808 : if (op == BPF_ADD)
691 : 41 : eval_add(rd, &rs, msk);
692 : : else if (op == BPF_SUB)
693 : 7 : eval_sub(rd, &rs, msk);
694 : : else if (op == BPF_LSH)
695 : 22 : eval_lsh(rd, &rs, opsz, msk);
696 : : else if (op == BPF_RSH)
697 : 11 : eval_rsh(rd, &rs, opsz, msk);
698 : : else if (op == EBPF_ARSH)
699 : 2 : eval_arsh(rd, &rs, opsz, msk);
700 : : else if (op == BPF_AND)
701 : 54 : eval_and(rd, &rs, opsz, msk);
702 : : else if (op == BPF_OR)
703 : 259 : eval_or(rd, &rs, opsz, msk);
704 : : else if (op == BPF_XOR)
705 : 62 : eval_xor(rd, &rs, opsz, msk);
706 : : else if (op == BPF_MUL)
707 : 9 : eval_mul(rd, &rs, opsz, msk);
708 : : else if (op == BPF_DIV || op == BPF_MOD)
709 : 5 : err = eval_divmod(op, rd, &rs, opsz, msk);
710 : : else if (op == BPF_NEG)
711 : 6 : eval_neg(rd, opsz, msk);
712 : : else if (op == EBPF_MOV)
713 : 330 : *rd = rs;
714 : : else
715 : : eval_max_bound(rd, msk);
716 : :
717 : : return err;
718 : : }
719 : :
720 : : static const char *
721 : 10 : eval_bele(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
722 : : {
723 : : uint64_t msk;
724 : : struct bpf_eval_state *st;
725 : : struct bpf_reg_val *rd;
726 : : const char *err;
727 : :
728 : 10 : msk = RTE_LEN2MASK(ins->imm, uint64_t);
729 : :
730 : 10 : st = bvf->evst;
731 [ + - ]: 10 : rd = st->rv + ins->dst_reg;
732 : :
733 : : err = eval_defined(rd, NULL);
734 : : if (err != NULL)
735 : : return err;
736 : :
737 : : #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
738 [ + + ]: 10 : if (ins->code == (BPF_ALU | EBPF_END | EBPF_TO_BE))
739 : : eval_max_bound(rd, msk);
740 : : else
741 : : eval_apply_mask(rd, msk);
742 : : #else
743 : : if (ins->code == (BPF_ALU | EBPF_END | EBPF_TO_LE))
744 : : eval_max_bound(rd, msk);
745 : : else
746 : : eval_apply_mask(rd, msk);
747 : : #endif
748 : :
749 : : return NULL;
750 : : }
751 : :
752 : : static const char *
753 : 155 : eval_ptr(struct bpf_verifier *bvf, struct bpf_reg_val *rm, uint32_t opsz,
754 : : uint32_t align, int16_t off)
755 : : {
756 : : struct bpf_reg_val rv;
757 : :
758 : : /* calculate reg + offset */
759 : 155 : eval_fill_imm(&rv, rm->mask, off);
760 : 155 : eval_add(rm, &rv, rm->mask);
761 : :
762 [ + + ]: 155 : if (RTE_BPF_ARG_PTR_TYPE(rm->v.type) == 0)
763 : : return "destination is not a pointer";
764 : :
765 [ + - ]: 153 : if (rm->mask != UINT64_MAX)
766 : : return "pointer truncation";
767 : :
768 [ + - ]: 153 : if (rm->u.max + opsz > rm->v.size ||
769 [ + - ]: 153 : (uint64_t)rm->s.max + opsz > rm->v.size ||
770 [ + - ]: 153 : rm->s.min < 0)
771 : : return "memory boundary violation";
772 : :
773 [ + - ]: 153 : if (rm->u.max % align != 0)
774 : : return "unaligned memory access";
775 : :
776 [ + + ]: 153 : if (rm->v.type == BPF_ARG_PTR_STACK) {
777 : :
778 [ + - + - : 39 : if (rm->u.max != rm->u.min || rm->s.max != rm->s.min ||
+ - ]
779 : : rm->u.max != (uint64_t)rm->s.max)
780 : : return "stack access with variable offset";
781 : :
782 : 39 : bvf->stack_sz = RTE_MAX(bvf->stack_sz, rm->v.size - rm->u.max);
783 : :
784 : : /* pointer to mbuf */
785 [ + + ]: 114 : } else if (rm->v.type == RTE_BPF_ARG_PTR_MBUF) {
786 : :
787 [ + - + - : 1 : if (rm->u.max != rm->u.min || rm->s.max != rm->s.min ||
- + ]
788 : : rm->u.max != (uint64_t)rm->s.max)
789 : 0 : return "mbuf access with variable offset";
790 : : }
791 : :
792 : : return NULL;
793 : : }
794 : :
795 : : static void
796 : : eval_max_load(struct bpf_reg_val *rv, uint64_t mask)
797 : : {
798 : : eval_umax_bound(rv, mask);
799 : :
800 : : /* full 64-bit load */
801 : : if (mask == UINT64_MAX)
802 : : eval_smax_bound(rv, mask);
803 : :
804 : : /* zero-extend load */
805 : 42 : rv->s.min = rv->u.min;
806 : 42 : rv->s.max = rv->u.max;
807 : : }
808 : :
809 : :
810 : : static const char *
811 : 57 : eval_load(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
812 : : {
813 : : uint32_t opsz;
814 : : uint64_t msk;
815 : : const char *err;
816 : : struct bpf_eval_state *st;
817 : : struct bpf_reg_val *rd, rs;
818 : : const struct bpf_reg_val *sv;
819 : :
820 : 57 : st = bvf->evst;
821 : 57 : rd = st->rv + ins->dst_reg;
822 : 57 : rs = st->rv[ins->src_reg];
823 [ + + ]: 57 : opsz = bpf_size(BPF_SIZE(ins->code));
824 : 57 : msk = RTE_LEN2MASK(opsz * CHAR_BIT, uint64_t);
825 : :
826 : 57 : err = eval_ptr(bvf, &rs, opsz, 1, ins->off);
827 [ + - ]: 57 : if (err != NULL)
828 : : return err;
829 : :
830 [ + + ]: 57 : if (rs.v.type == BPF_ARG_PTR_STACK) {
831 : :
832 : 15 : sv = st->sv + rs.u.max / sizeof(uint64_t);
833 [ + - + - ]: 15 : if (sv->v.type == RTE_BPF_ARG_UNDEF || sv->mask < msk)
834 : : return "undefined value on the stack";
835 : :
836 : 15 : *rd = *sv;
837 : :
838 : : /* pointer to mbuf */
839 [ + + ]: 42 : } else if (rs.v.type == RTE_BPF_ARG_PTR_MBUF) {
840 : :
841 [ - + ]: 1 : if (rs.u.max == offsetof(struct rte_mbuf, next)) {
842 : : eval_fill_imm(rd, msk, 0);
843 : 0 : rd->v = rs.v;
844 [ - + ]: 1 : } else if (rs.u.max == offsetof(struct rte_mbuf, buf_addr)) {
845 : : eval_fill_imm(rd, msk, 0);
846 : 0 : rd->v.type = RTE_BPF_ARG_PTR;
847 : 0 : rd->v.size = rs.v.buf_size;
848 [ - + ]: 1 : } else if (rs.u.max == offsetof(struct rte_mbuf, data_off)) {
849 : : eval_fill_imm(rd, msk, RTE_PKTMBUF_HEADROOM);
850 : : rd->v.type = RTE_BPF_ARG_RAW;
851 : : } else {
852 : : eval_max_load(rd, msk);
853 : 1 : rd->v.type = RTE_BPF_ARG_RAW;
854 : : }
855 : :
856 : : /* pointer to raw data */
857 : : } else {
858 : : eval_max_load(rd, msk);
859 : 41 : rd->v.type = RTE_BPF_ARG_RAW;
860 : : }
861 : :
862 : : return NULL;
863 : : }
864 : :
865 : : static const char *
866 : : eval_mbuf_store(const struct bpf_reg_val *rv, uint32_t opsz)
867 : : {
868 : : uint32_t i;
869 : :
870 : : static const struct {
871 : : size_t off;
872 : : size_t sz;
873 : : } mbuf_ro_fileds[] = {
874 : : { .off = offsetof(struct rte_mbuf, buf_addr), },
875 : : { .off = offsetof(struct rte_mbuf, refcnt), },
876 : : { .off = offsetof(struct rte_mbuf, nb_segs), },
877 : : { .off = offsetof(struct rte_mbuf, buf_len), },
878 : : { .off = offsetof(struct rte_mbuf, pool), },
879 : : { .off = offsetof(struct rte_mbuf, next), },
880 : : { .off = offsetof(struct rte_mbuf, priv_size), },
881 : : };
882 : :
883 [ # # ]: 0 : for (i = 0; i != RTE_DIM(mbuf_ro_fileds) &&
884 : 0 : (mbuf_ro_fileds[i].off + mbuf_ro_fileds[i].sz <=
885 [ # # # # ]: 0 : rv->u.max || rv->u.max + opsz <= mbuf_ro_fileds[i].off);
886 : 0 : i++)
887 : : ;
888 : :
889 [ # # ]: 0 : if (i != RTE_DIM(mbuf_ro_fileds))
890 : : return "store to the read-only mbuf field";
891 : :
892 : : return NULL;
893 : :
894 : : }
895 : :
896 : : static const char *
897 : 311 : eval_store(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
898 : : {
899 : : uint32_t opsz;
900 : : uint64_t msk;
901 : : const char *err;
902 : : struct bpf_eval_state *st;
903 : : struct bpf_reg_val rd, rs, *sv;
904 : :
905 [ + + ]: 311 : opsz = bpf_size(BPF_SIZE(ins->code));
906 : 311 : msk = RTE_LEN2MASK(opsz * CHAR_BIT, uint64_t);
907 : :
908 : 311 : st = bvf->evst;
909 : 311 : rd = st->rv[ins->dst_reg];
910 : :
911 [ + + ]: 311 : if (BPF_CLASS(ins->code) == BPF_STX) {
912 : 301 : rs = st->rv[ins->src_reg];
913 [ + + ]: 301 : if (BPF_MODE(ins->code) == EBPF_ATOMIC)
914 [ + + + ]: 260 : switch (ins->imm) {
915 : : case BPF_ATOMIC_ADD:
916 : : break;
917 : 13 : case BPF_ATOMIC_XCHG:
918 : : eval_max_bound(&st->rv[ins->src_reg], msk);
919 : : break;
920 : : default:
921 : : return "unsupported atomic operation";
922 : : }
923 : : eval_apply_mask(&rs, msk);
924 : : } else
925 : 10 : eval_fill_imm(&rs, msk, ins->imm);
926 : :
927 : : err = eval_defined(NULL, &rs);
928 : : if (err != NULL)
929 : : return err;
930 : :
931 : 87 : err = eval_ptr(bvf, &rd, opsz, 1, ins->off);
932 [ + + ]: 87 : if (err != NULL)
933 : : return err;
934 : :
935 [ + + ]: 85 : if (rd.v.type == BPF_ARG_PTR_STACK) {
936 : :
937 : 15 : sv = st->sv + rd.u.max / sizeof(uint64_t);
938 [ - + ]: 15 : if (BPF_CLASS(ins->code) == BPF_STX &&
939 : : BPF_MODE(ins->code) == EBPF_ATOMIC)
940 : : eval_max_bound(sv, msk);
941 : : else
942 : 15 : *sv = rs;
943 : :
944 : : /* pointer to mbuf */
945 [ - + ]: 70 : } else if (rd.v.type == RTE_BPF_ARG_PTR_MBUF) {
946 : : err = eval_mbuf_store(&rd, opsz);
947 : : if (err != NULL)
948 : 0 : return err;
949 : : }
950 : :
951 : : return NULL;
952 : : }
953 : :
954 : : static const char *
955 : 116 : eval_func_arg(struct bpf_verifier *bvf, const struct rte_bpf_arg *arg,
956 : : struct bpf_reg_val *rv)
957 : : {
958 : : uint32_t i, n;
959 : : struct bpf_eval_state *st;
960 : : const char *err;
961 : :
962 : 116 : st = bvf->evst;
963 : :
964 [ + - ]: 116 : if (rv->v.type == RTE_BPF_ARG_UNDEF)
965 : : return "Undefined argument type";
966 : :
967 [ + + + - ]: 116 : if (arg->type != rv->v.type &&
968 [ + - ]: 9 : arg->type != RTE_BPF_ARG_RAW &&
969 : 9 : (arg->type != RTE_BPF_ARG_PTR ||
970 [ + - ]: 9 : RTE_BPF_ARG_PTR_TYPE(rv->v.type) == 0))
971 : : return "Invalid argument type";
972 : :
973 : : err = NULL;
974 : :
975 : : /* argument is a pointer */
976 [ + + ]: 116 : if (RTE_BPF_ARG_PTR_TYPE(arg->type) != 0) {
977 : :
978 : 11 : err = eval_ptr(bvf, rv, arg->size, 1, 0);
979 : :
980 : : /*
981 : : * pointer to the variable on the stack is passed
982 : : * as an argument, mark stack space it occupies as initialized.
983 : : */
984 [ + - + + ]: 11 : if (err == NULL && rv->v.type == BPF_ARG_PTR_STACK) {
985 : :
986 : 9 : i = rv->u.max / sizeof(uint64_t);
987 : 9 : n = i + arg->size / sizeof(uint64_t);
988 [ + + ]: 14 : while (i != n) {
989 : 5 : eval_fill_max_bound(st->sv + i, UINT64_MAX);
990 : 5 : i++;
991 : : };
992 : : }
993 : : }
994 : :
995 : : return err;
996 : : }
997 : :
998 : : static const char *
999 : 107 : eval_call(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
1000 : : {
1001 : : uint32_t i, idx;
1002 : : struct bpf_reg_val *rv;
1003 : : const struct rte_bpf_xsym *xsym;
1004 : : const char *err;
1005 : :
1006 : 107 : idx = ins->imm;
1007 : :
1008 [ + - ]: 107 : if (idx >= bvf->prm->nb_xsym ||
1009 [ + - ]: 107 : bvf->prm->xsym[idx].type != RTE_BPF_XTYPE_FUNC)
1010 : : return "invalid external function index";
1011 : :
1012 : : /* for now don't support function calls on 32 bit platform */
1013 : : if (sizeof(uint64_t) != sizeof(uintptr_t))
1014 : : return "function calls are supported only for 64 bit apps";
1015 : :
1016 : : xsym = bvf->prm->xsym + idx;
1017 : :
1018 : : /* evaluate function arguments */
1019 : : err = NULL;
1020 [ + + + - ]: 223 : for (i = 0; i != xsym->func.nb_args && err == NULL; i++) {
1021 : 116 : err = eval_func_arg(bvf, xsym->func.args + i,
1022 : 116 : bvf->evst->rv + EBPF_REG_1 + i);
1023 : : }
1024 : :
1025 : : /* R1-R5 argument/scratch registers */
1026 [ + + ]: 642 : for (i = EBPF_REG_1; i != EBPF_REG_6; i++)
1027 : 535 : bvf->evst->rv[i].v.type = RTE_BPF_ARG_UNDEF;
1028 : :
1029 : : /* update return value */
1030 : :
1031 : 107 : rv = bvf->evst->rv + EBPF_REG_0;
1032 : 107 : rv->v = xsym->func.ret;
1033 [ + + ]: 107 : if (rv->v.type == RTE_BPF_ARG_RAW)
1034 : 104 : eval_fill_max_bound(rv,
1035 : 104 : RTE_LEN2MASK(rv->v.size * CHAR_BIT, uint64_t));
1036 [ + + ]: 3 : else if (RTE_BPF_ARG_PTR_TYPE(rv->v.type) != 0)
1037 : : eval_fill_imm64(rv, UINTPTR_MAX, 0);
1038 : :
1039 : : return err;
1040 : : }
1041 : :
1042 : : static void
1043 : 292 : eval_jeq_jne(struct bpf_reg_val *trd, struct bpf_reg_val *trs)
1044 : : {
1045 : : /* sreg is constant */
1046 [ + + ]: 292 : if (trs->u.min == trs->u.max) {
1047 : 274 : trd->u = trs->u;
1048 : : /* dreg is constant */
1049 [ + + ]: 18 : } else if (trd->u.min == trd->u.max) {
1050 : 8 : trs->u = trd->u;
1051 : : } else {
1052 : 10 : trd->u.max = RTE_MIN(trd->u.max, trs->u.max);
1053 : 10 : trd->u.min = RTE_MAX(trd->u.min, trs->u.min);
1054 : 10 : trs->u = trd->u;
1055 : : }
1056 : :
1057 : : /* sreg is constant */
1058 [ + + ]: 292 : if (trs->s.min == trs->s.max) {
1059 : 274 : trd->s = trs->s;
1060 : : /* dreg is constant */
1061 [ + + ]: 18 : } else if (trd->s.min == trd->s.max) {
1062 : 8 : trs->s = trd->s;
1063 : : } else {
1064 : 10 : trd->s.max = RTE_MIN(trd->s.max, trs->s.max);
1065 : 10 : trd->s.min = RTE_MAX(trd->s.min, trs->s.min);
1066 : 10 : trs->s = trd->s;
1067 : : }
1068 : 292 : }
1069 : :
1070 : : static void
1071 : : eval_jgt_jle(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
1072 : : struct bpf_reg_val *frd, struct bpf_reg_val *frs)
1073 : : {
1074 : 72 : frd->u.max = RTE_MIN(frd->u.max, frs->u.min);
1075 : 72 : trd->u.min = RTE_MAX(trd->u.min, trs->u.min + 1);
1076 : 72 : }
1077 : :
1078 : : static void
1079 : : eval_jlt_jge(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
1080 : : struct bpf_reg_val *frd, struct bpf_reg_val *frs)
1081 : : {
1082 : 4 : frd->u.min = RTE_MAX(frd->u.min, frs->u.min);
1083 : 4 : trd->u.max = RTE_MIN(trd->u.max, trs->u.max - 1);
1084 : 4 : }
1085 : :
1086 : : static void
1087 : : eval_jsgt_jsle(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
1088 : : struct bpf_reg_val *frd, struct bpf_reg_val *frs)
1089 : : {
1090 : 34 : frd->s.max = RTE_MIN(frd->s.max, frs->s.min);
1091 : 34 : trd->s.min = RTE_MAX(trd->s.min, trs->s.min + 1);
1092 : 34 : }
1093 : :
1094 : : static void
1095 : : eval_jslt_jsge(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
1096 : : struct bpf_reg_val *frd, struct bpf_reg_val *frs)
1097 : : {
1098 : 0 : frd->s.min = RTE_MAX(frd->s.min, frs->s.min);
1099 : 0 : trd->s.max = RTE_MIN(trd->s.max, trs->s.max - 1);
1100 : 0 : }
1101 : :
1102 : : static const char *
1103 : 563 : eval_jcc(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
1104 : : {
1105 : : uint32_t op;
1106 : : const char *err;
1107 : : struct bpf_eval_state *fst, *tst;
1108 : : struct bpf_reg_val *frd, *frs, *trd, *trs;
1109 : : struct bpf_reg_val rvf, rvt;
1110 : :
1111 : 563 : tst = bvf->evst;
1112 : 563 : fst = bvf->evin->evst.cur;
1113 : :
1114 : 563 : frd = fst->rv + ins->dst_reg;
1115 : 563 : trd = tst->rv + ins->dst_reg;
1116 : :
1117 [ + + ]: 563 : if (BPF_SRC(ins->code) == BPF_X) {
1118 : 287 : frs = fst->rv + ins->src_reg;
1119 : 287 : trs = tst->rv + ins->src_reg;
1120 : : } else {
1121 : : frs = &rvf;
1122 : : trs = &rvt;
1123 : 276 : eval_fill_imm(frs, UINT64_MAX, ins->imm);
1124 : : eval_fill_imm(trs, UINT64_MAX, ins->imm);
1125 : : }
1126 : :
1127 : : err = eval_defined(trd, trs);
1128 : : if (err != NULL)
1129 : 0 : return err;
1130 : :
1131 : 563 : op = BPF_OP(ins->code);
1132 : :
1133 [ + + ]: 563 : if (op == BPF_JEQ)
1134 : 112 : eval_jeq_jne(trd, trs);
1135 [ + + ]: 451 : else if (op == EBPF_JNE)
1136 : 180 : eval_jeq_jne(frd, frs);
1137 [ + + ]: 271 : else if (op == BPF_JGT)
1138 : : eval_jgt_jle(trd, trs, frd, frs);
1139 [ + + ]: 263 : else if (op == EBPF_JLE)
1140 : : eval_jgt_jle(frd, frs, trd, trs);
1141 [ - + ]: 199 : else if (op == EBPF_JLT)
1142 : : eval_jlt_jge(trd, trs, frd, frs);
1143 [ + + ]: 199 : else if (op == BPF_JGE)
1144 : : eval_jlt_jge(frd, frs, trd, trs);
1145 [ + + ]: 195 : else if (op == EBPF_JSGT)
1146 : : eval_jsgt_jsle(trd, trs, frd, frs);
1147 [ + + ]: 163 : else if (op == EBPF_JSLE)
1148 : : eval_jsgt_jsle(frd, frs, trd, trs);
1149 [ - + ]: 161 : else if (op == EBPF_JSLT)
1150 : : eval_jslt_jsge(trd, trs, frd, frs);
1151 [ - + ]: 161 : else if (op == EBPF_JSGE)
1152 : : eval_jslt_jsge(frd, frs, trd, trs);
1153 : :
1154 : : return NULL;
1155 : : }
1156 : :
1157 : : /*
1158 : : * validate parameters for each instruction type.
1159 : : */
1160 : : static const struct bpf_ins_check ins_chk[UINT8_MAX + 1] = {
1161 : : /* ALU IMM 32-bit instructions */
1162 : : [(BPF_ALU | BPF_ADD | BPF_K)] = {
1163 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1164 : : .off = { .min = 0, .max = 0},
1165 : : .imm = { .min = 0, .max = UINT32_MAX,},
1166 : : .eval = eval_alu,
1167 : : },
1168 : : [(BPF_ALU | BPF_SUB | BPF_K)] = {
1169 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1170 : : .off = { .min = 0, .max = 0},
1171 : : .imm = { .min = 0, .max = UINT32_MAX,},
1172 : : .eval = eval_alu,
1173 : : },
1174 : : [(BPF_ALU | BPF_AND | BPF_K)] = {
1175 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1176 : : .off = { .min = 0, .max = 0},
1177 : : .imm = { .min = 0, .max = UINT32_MAX,},
1178 : : .eval = eval_alu,
1179 : : },
1180 : : [(BPF_ALU | BPF_OR | BPF_K)] = {
1181 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1182 : : .off = { .min = 0, .max = 0},
1183 : : .imm = { .min = 0, .max = UINT32_MAX,},
1184 : : .eval = eval_alu,
1185 : : },
1186 : : [(BPF_ALU | BPF_LSH | BPF_K)] = {
1187 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1188 : : .off = { .min = 0, .max = 0},
1189 : : .imm = { .min = 0, .max = UINT32_MAX,},
1190 : : .eval = eval_alu,
1191 : : },
1192 : : [(BPF_ALU | BPF_RSH | BPF_K)] = {
1193 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1194 : : .off = { .min = 0, .max = 0},
1195 : : .imm = { .min = 0, .max = UINT32_MAX,},
1196 : : .eval = eval_alu,
1197 : : },
1198 : : [(BPF_ALU | BPF_XOR | BPF_K)] = {
1199 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1200 : : .off = { .min = 0, .max = 0},
1201 : : .imm = { .min = 0, .max = UINT32_MAX,},
1202 : : .eval = eval_alu,
1203 : : },
1204 : : [(BPF_ALU | BPF_MUL | BPF_K)] = {
1205 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1206 : : .off = { .min = 0, .max = 0},
1207 : : .imm = { .min = 0, .max = UINT32_MAX,},
1208 : : .eval = eval_alu,
1209 : : },
1210 : : [(BPF_ALU | EBPF_MOV | BPF_K)] = {
1211 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1212 : : .off = { .min = 0, .max = 0},
1213 : : .imm = { .min = 0, .max = UINT32_MAX,},
1214 : : .eval = eval_alu,
1215 : : },
1216 : : [(BPF_ALU | BPF_DIV | BPF_K)] = {
1217 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1218 : : .off = { .min = 0, .max = 0},
1219 : : .imm = { .min = 1, .max = UINT32_MAX},
1220 : : .eval = eval_alu,
1221 : : },
1222 : : [(BPF_ALU | BPF_MOD | BPF_K)] = {
1223 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1224 : : .off = { .min = 0, .max = 0},
1225 : : .imm = { .min = 1, .max = UINT32_MAX},
1226 : : .eval = eval_alu,
1227 : : },
1228 : : /* ALU IMM 64-bit instructions */
1229 : : [(EBPF_ALU64 | BPF_ADD | BPF_K)] = {
1230 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1231 : : .off = { .min = 0, .max = 0},
1232 : : .imm = { .min = 0, .max = UINT32_MAX,},
1233 : : .eval = eval_alu,
1234 : : },
1235 : : [(EBPF_ALU64 | BPF_SUB | BPF_K)] = {
1236 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1237 : : .off = { .min = 0, .max = 0},
1238 : : .imm = { .min = 0, .max = UINT32_MAX,},
1239 : : .eval = eval_alu,
1240 : : },
1241 : : [(EBPF_ALU64 | BPF_AND | BPF_K)] = {
1242 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1243 : : .off = { .min = 0, .max = 0},
1244 : : .imm = { .min = 0, .max = UINT32_MAX,},
1245 : : .eval = eval_alu,
1246 : : },
1247 : : [(EBPF_ALU64 | BPF_OR | BPF_K)] = {
1248 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1249 : : .off = { .min = 0, .max = 0},
1250 : : .imm = { .min = 0, .max = UINT32_MAX,},
1251 : : .eval = eval_alu,
1252 : : },
1253 : : [(EBPF_ALU64 | BPF_LSH | BPF_K)] = {
1254 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1255 : : .off = { .min = 0, .max = 0},
1256 : : .imm = { .min = 0, .max = UINT32_MAX,},
1257 : : .eval = eval_alu,
1258 : : },
1259 : : [(EBPF_ALU64 | BPF_RSH | BPF_K)] = {
1260 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1261 : : .off = { .min = 0, .max = 0},
1262 : : .imm = { .min = 0, .max = UINT32_MAX,},
1263 : : .eval = eval_alu,
1264 : : },
1265 : : [(EBPF_ALU64 | EBPF_ARSH | BPF_K)] = {
1266 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1267 : : .off = { .min = 0, .max = 0},
1268 : : .imm = { .min = 0, .max = UINT32_MAX,},
1269 : : .eval = eval_alu,
1270 : : },
1271 : : [(EBPF_ALU64 | BPF_XOR | BPF_K)] = {
1272 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1273 : : .off = { .min = 0, .max = 0},
1274 : : .imm = { .min = 0, .max = UINT32_MAX,},
1275 : : .eval = eval_alu,
1276 : : },
1277 : : [(EBPF_ALU64 | BPF_MUL | BPF_K)] = {
1278 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1279 : : .off = { .min = 0, .max = 0},
1280 : : .imm = { .min = 0, .max = UINT32_MAX,},
1281 : : .eval = eval_alu,
1282 : : },
1283 : : [(EBPF_ALU64 | EBPF_MOV | BPF_K)] = {
1284 : : .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
1285 : : .off = { .min = 0, .max = 0},
1286 : : .imm = { .min = 0, .max = UINT32_MAX,},
1287 : : .eval = eval_alu,
1288 : : },
1289 : : [(EBPF_ALU64 | BPF_DIV | BPF_K)] = {
1290 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1291 : : .off = { .min = 0, .max = 0},
1292 : : .imm = { .min = 1, .max = UINT32_MAX},
1293 : : .eval = eval_alu,
1294 : : },
1295 : : [(EBPF_ALU64 | BPF_MOD | BPF_K)] = {
1296 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1297 : : .off = { .min = 0, .max = 0},
1298 : : .imm = { .min = 1, .max = UINT32_MAX},
1299 : : .eval = eval_alu,
1300 : : },
1301 : : /* ALU REG 32-bit instructions */
1302 : : [(BPF_ALU | BPF_ADD | BPF_X)] = {
1303 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1304 : : .off = { .min = 0, .max = 0},
1305 : : .imm = { .min = 0, .max = 0},
1306 : : .eval = eval_alu,
1307 : : },
1308 : : [(BPF_ALU | BPF_SUB | BPF_X)] = {
1309 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1310 : : .off = { .min = 0, .max = 0},
1311 : : .imm = { .min = 0, .max = 0},
1312 : : .eval = eval_alu,
1313 : : },
1314 : : [(BPF_ALU | BPF_AND | BPF_X)] = {
1315 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1316 : : .off = { .min = 0, .max = 0},
1317 : : .imm = { .min = 0, .max = 0},
1318 : : .eval = eval_alu,
1319 : : },
1320 : : [(BPF_ALU | BPF_OR | BPF_X)] = {
1321 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1322 : : .off = { .min = 0, .max = 0},
1323 : : .imm = { .min = 0, .max = 0},
1324 : : .eval = eval_alu,
1325 : : },
1326 : : [(BPF_ALU | BPF_LSH | BPF_X)] = {
1327 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1328 : : .off = { .min = 0, .max = 0},
1329 : : .imm = { .min = 0, .max = 0},
1330 : : .eval = eval_alu,
1331 : : },
1332 : : [(BPF_ALU | BPF_RSH | BPF_X)] = {
1333 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1334 : : .off = { .min = 0, .max = 0},
1335 : : .imm = { .min = 0, .max = 0},
1336 : : .eval = eval_alu,
1337 : : },
1338 : : [(BPF_ALU | BPF_XOR | BPF_X)] = {
1339 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1340 : : .off = { .min = 0, .max = 0},
1341 : : .imm = { .min = 0, .max = 0},
1342 : : .eval = eval_alu,
1343 : : },
1344 : : [(BPF_ALU | BPF_MUL | BPF_X)] = {
1345 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1346 : : .off = { .min = 0, .max = 0},
1347 : : .imm = { .min = 0, .max = 0},
1348 : : .eval = eval_alu,
1349 : : },
1350 : : [(BPF_ALU | BPF_DIV | BPF_X)] = {
1351 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1352 : : .off = { .min = 0, .max = 0},
1353 : : .imm = { .min = 0, .max = 0},
1354 : : .eval = eval_alu,
1355 : : },
1356 : : [(BPF_ALU | BPF_MOD | BPF_X)] = {
1357 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1358 : : .off = { .min = 0, .max = 0},
1359 : : .imm = { .min = 0, .max = 0},
1360 : : .eval = eval_alu,
1361 : : },
1362 : : [(BPF_ALU | EBPF_MOV | BPF_X)] = {
1363 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1364 : : .off = { .min = 0, .max = 0},
1365 : : .imm = { .min = 0, .max = 0},
1366 : : .eval = eval_alu,
1367 : : },
1368 : : [(BPF_ALU | BPF_NEG)] = {
1369 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1370 : : .off = { .min = 0, .max = 0},
1371 : : .imm = { .min = 0, .max = 0},
1372 : : .eval = eval_alu,
1373 : : },
1374 : : [(BPF_ALU | EBPF_END | EBPF_TO_BE)] = {
1375 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1376 : : .off = { .min = 0, .max = 0},
1377 : : .imm = { .min = 16, .max = 64},
1378 : : .check = check_alu_bele,
1379 : : .eval = eval_bele,
1380 : : },
1381 : : [(BPF_ALU | EBPF_END | EBPF_TO_LE)] = {
1382 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1383 : : .off = { .min = 0, .max = 0},
1384 : : .imm = { .min = 16, .max = 64},
1385 : : .check = check_alu_bele,
1386 : : .eval = eval_bele,
1387 : : },
1388 : : /* ALU REG 64-bit instructions */
1389 : : [(EBPF_ALU64 | BPF_ADD | BPF_X)] = {
1390 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1391 : : .off = { .min = 0, .max = 0},
1392 : : .imm = { .min = 0, .max = 0},
1393 : : .eval = eval_alu,
1394 : : },
1395 : : [(EBPF_ALU64 | BPF_SUB | BPF_X)] = {
1396 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1397 : : .off = { .min = 0, .max = 0},
1398 : : .imm = { .min = 0, .max = 0},
1399 : : .eval = eval_alu,
1400 : : },
1401 : : [(EBPF_ALU64 | BPF_AND | BPF_X)] = {
1402 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1403 : : .off = { .min = 0, .max = 0},
1404 : : .imm = { .min = 0, .max = 0},
1405 : : .eval = eval_alu,
1406 : : },
1407 : : [(EBPF_ALU64 | BPF_OR | BPF_X)] = {
1408 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1409 : : .off = { .min = 0, .max = 0},
1410 : : .imm = { .min = 0, .max = 0},
1411 : : .eval = eval_alu,
1412 : : },
1413 : : [(EBPF_ALU64 | BPF_LSH | BPF_X)] = {
1414 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1415 : : .off = { .min = 0, .max = 0},
1416 : : .imm = { .min = 0, .max = 0},
1417 : : .eval = eval_alu,
1418 : : },
1419 : : [(EBPF_ALU64 | BPF_RSH | BPF_X)] = {
1420 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1421 : : .off = { .min = 0, .max = 0},
1422 : : .imm = { .min = 0, .max = 0},
1423 : : .eval = eval_alu,
1424 : : },
1425 : : [(EBPF_ALU64 | EBPF_ARSH | BPF_X)] = {
1426 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1427 : : .off = { .min = 0, .max = 0},
1428 : : .imm = { .min = 0, .max = 0},
1429 : : .eval = eval_alu,
1430 : : },
1431 : : [(EBPF_ALU64 | BPF_XOR | BPF_X)] = {
1432 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1433 : : .off = { .min = 0, .max = 0},
1434 : : .imm = { .min = 0, .max = 0},
1435 : : .eval = eval_alu,
1436 : : },
1437 : : [(EBPF_ALU64 | BPF_MUL | BPF_X)] = {
1438 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1439 : : .off = { .min = 0, .max = 0},
1440 : : .imm = { .min = 0, .max = 0},
1441 : : .eval = eval_alu,
1442 : : },
1443 : : [(EBPF_ALU64 | BPF_DIV | BPF_X)] = {
1444 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1445 : : .off = { .min = 0, .max = 0},
1446 : : .imm = { .min = 0, .max = 0},
1447 : : .eval = eval_alu,
1448 : : },
1449 : : [(EBPF_ALU64 | BPF_MOD | BPF_X)] = {
1450 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1451 : : .off = { .min = 0, .max = 0},
1452 : : .imm = { .min = 0, .max = 0},
1453 : : .eval = eval_alu,
1454 : : },
1455 : : [(EBPF_ALU64 | EBPF_MOV | BPF_X)] = {
1456 : : .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
1457 : : .off = { .min = 0, .max = 0},
1458 : : .imm = { .min = 0, .max = 0},
1459 : : .eval = eval_alu,
1460 : : },
1461 : : [(EBPF_ALU64 | BPF_NEG)] = {
1462 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1463 : : .off = { .min = 0, .max = 0},
1464 : : .imm = { .min = 0, .max = 0},
1465 : : .eval = eval_alu,
1466 : : },
1467 : : /* load instructions */
1468 : : [(BPF_LDX | BPF_MEM | BPF_B)] = {
1469 : : .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
1470 : : .off = { .min = 0, .max = UINT16_MAX},
1471 : : .imm = { .min = 0, .max = 0},
1472 : : .eval = eval_load,
1473 : : },
1474 : : [(BPF_LDX | BPF_MEM | BPF_H)] = {
1475 : : .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
1476 : : .off = { .min = 0, .max = UINT16_MAX},
1477 : : .imm = { .min = 0, .max = 0},
1478 : : .eval = eval_load,
1479 : : },
1480 : : [(BPF_LDX | BPF_MEM | BPF_W)] = {
1481 : : .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
1482 : : .off = { .min = 0, .max = UINT16_MAX},
1483 : : .imm = { .min = 0, .max = 0},
1484 : : .eval = eval_load,
1485 : : },
1486 : : [(BPF_LDX | BPF_MEM | EBPF_DW)] = {
1487 : : .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
1488 : : .off = { .min = 0, .max = UINT16_MAX},
1489 : : .imm = { .min = 0, .max = 0},
1490 : : .eval = eval_load,
1491 : : },
1492 : : /* load 64 bit immediate value */
1493 : : [(BPF_LD | BPF_IMM | EBPF_DW)] = {
1494 : : .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
1495 : : .off = { .min = 0, .max = 0},
1496 : : .imm = { .min = 0, .max = UINT32_MAX},
1497 : : .eval = eval_ld_imm64,
1498 : : },
1499 : : /* load absolute instructions */
1500 : : [(BPF_LD | BPF_ABS | BPF_B)] = {
1501 : : .mask = {. dreg = ZERO_REG, .sreg = ZERO_REG},
1502 : : .off = { .min = 0, .max = 0},
1503 : : .imm = { .min = 0, .max = INT32_MAX},
1504 : : .eval = eval_ld_mbuf,
1505 : : },
1506 : : [(BPF_LD | BPF_ABS | BPF_H)] = {
1507 : : .mask = {. dreg = ZERO_REG, .sreg = ZERO_REG},
1508 : : .off = { .min = 0, .max = 0},
1509 : : .imm = { .min = 0, .max = INT32_MAX},
1510 : : .eval = eval_ld_mbuf,
1511 : : },
1512 : : [(BPF_LD | BPF_ABS | BPF_W)] = {
1513 : : .mask = {. dreg = ZERO_REG, .sreg = ZERO_REG},
1514 : : .off = { .min = 0, .max = 0},
1515 : : .imm = { .min = 0, .max = INT32_MAX},
1516 : : .eval = eval_ld_mbuf,
1517 : : },
1518 : : /* load indirect instructions */
1519 : : [(BPF_LD | BPF_IND | BPF_B)] = {
1520 : : .mask = {. dreg = ZERO_REG, .sreg = IND_SRC_REGS},
1521 : : .off = { .min = 0, .max = 0},
1522 : : .imm = { .min = 0, .max = UINT32_MAX},
1523 : : .eval = eval_ld_mbuf,
1524 : : },
1525 : : [(BPF_LD | BPF_IND | BPF_H)] = {
1526 : : .mask = {. dreg = ZERO_REG, .sreg = IND_SRC_REGS},
1527 : : .off = { .min = 0, .max = 0},
1528 : : .imm = { .min = 0, .max = UINT32_MAX},
1529 : : .eval = eval_ld_mbuf,
1530 : : },
1531 : : [(BPF_LD | BPF_IND | BPF_W)] = {
1532 : : .mask = {. dreg = ZERO_REG, .sreg = IND_SRC_REGS},
1533 : : .off = { .min = 0, .max = 0},
1534 : : .imm = { .min = 0, .max = UINT32_MAX},
1535 : : .eval = eval_ld_mbuf,
1536 : : },
1537 : : /* store REG instructions */
1538 : : [(BPF_STX | BPF_MEM | BPF_B)] = {
1539 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1540 : : .off = { .min = 0, .max = UINT16_MAX},
1541 : : .imm = { .min = 0, .max = 0},
1542 : : .eval = eval_store,
1543 : : },
1544 : : [(BPF_STX | BPF_MEM | BPF_H)] = {
1545 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1546 : : .off = { .min = 0, .max = UINT16_MAX},
1547 : : .imm = { .min = 0, .max = 0},
1548 : : .eval = eval_store,
1549 : : },
1550 : : [(BPF_STX | BPF_MEM | BPF_W)] = {
1551 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1552 : : .off = { .min = 0, .max = UINT16_MAX},
1553 : : .imm = { .min = 0, .max = 0},
1554 : : .eval = eval_store,
1555 : : },
1556 : : [(BPF_STX | BPF_MEM | EBPF_DW)] = {
1557 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1558 : : .off = { .min = 0, .max = UINT16_MAX},
1559 : : .imm = { .min = 0, .max = 0},
1560 : : .eval = eval_store,
1561 : : },
1562 : : /* atomic instructions */
1563 : : [(BPF_STX | EBPF_ATOMIC | BPF_W)] = {
1564 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1565 : : .off = { .min = 0, .max = UINT16_MAX},
1566 : : .imm = { .min = BPF_ATOMIC_ADD, .max = BPF_ATOMIC_XCHG},
1567 : : .eval = eval_store,
1568 : : },
1569 : : [(BPF_STX | EBPF_ATOMIC | EBPF_DW)] = {
1570 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1571 : : .off = { .min = 0, .max = UINT16_MAX},
1572 : : .imm = { .min = BPF_ATOMIC_ADD, .max = BPF_ATOMIC_XCHG},
1573 : : .eval = eval_store,
1574 : : },
1575 : : /* store IMM instructions */
1576 : : [(BPF_ST | BPF_MEM | BPF_B)] = {
1577 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1578 : : .off = { .min = 0, .max = UINT16_MAX},
1579 : : .imm = { .min = 0, .max = UINT32_MAX},
1580 : : .eval = eval_store,
1581 : : },
1582 : : [(BPF_ST | BPF_MEM | BPF_H)] = {
1583 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1584 : : .off = { .min = 0, .max = UINT16_MAX},
1585 : : .imm = { .min = 0, .max = UINT32_MAX},
1586 : : .eval = eval_store,
1587 : : },
1588 : : [(BPF_ST | BPF_MEM | BPF_W)] = {
1589 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1590 : : .off = { .min = 0, .max = UINT16_MAX},
1591 : : .imm = { .min = 0, .max = UINT32_MAX},
1592 : : .eval = eval_store,
1593 : : },
1594 : : [(BPF_ST | BPF_MEM | EBPF_DW)] = {
1595 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1596 : : .off = { .min = 0, .max = UINT16_MAX},
1597 : : .imm = { .min = 0, .max = UINT32_MAX},
1598 : : .eval = eval_store,
1599 : : },
1600 : : /* jump instruction */
1601 : : [(BPF_JMP | BPF_JA)] = {
1602 : : .mask = { .dreg = ZERO_REG, .sreg = ZERO_REG},
1603 : : .off = { .min = 0, .max = UINT16_MAX},
1604 : : .imm = { .min = 0, .max = 0},
1605 : : },
1606 : : /* jcc IMM instructions */
1607 : : [(BPF_JMP | BPF_JEQ | BPF_K)] = {
1608 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1609 : : .off = { .min = 0, .max = UINT16_MAX},
1610 : : .imm = { .min = 0, .max = UINT32_MAX},
1611 : : .eval = eval_jcc,
1612 : : },
1613 : : [(BPF_JMP | EBPF_JNE | BPF_K)] = {
1614 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1615 : : .off = { .min = 0, .max = UINT16_MAX},
1616 : : .imm = { .min = 0, .max = UINT32_MAX},
1617 : : .eval = eval_jcc,
1618 : : },
1619 : : [(BPF_JMP | BPF_JGT | BPF_K)] = {
1620 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1621 : : .off = { .min = 0, .max = UINT16_MAX},
1622 : : .imm = { .min = 0, .max = UINT32_MAX},
1623 : : .eval = eval_jcc,
1624 : : },
1625 : : [(BPF_JMP | EBPF_JLT | BPF_K)] = {
1626 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1627 : : .off = { .min = 0, .max = UINT16_MAX},
1628 : : .imm = { .min = 0, .max = UINT32_MAX},
1629 : : .eval = eval_jcc,
1630 : : },
1631 : : [(BPF_JMP | BPF_JGE | BPF_K)] = {
1632 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1633 : : .off = { .min = 0, .max = UINT16_MAX},
1634 : : .imm = { .min = 0, .max = UINT32_MAX},
1635 : : .eval = eval_jcc,
1636 : : },
1637 : : [(BPF_JMP | EBPF_JLE | BPF_K)] = {
1638 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1639 : : .off = { .min = 0, .max = UINT16_MAX},
1640 : : .imm = { .min = 0, .max = UINT32_MAX},
1641 : : .eval = eval_jcc,
1642 : : },
1643 : : [(BPF_JMP | EBPF_JSGT | BPF_K)] = {
1644 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1645 : : .off = { .min = 0, .max = UINT16_MAX},
1646 : : .imm = { .min = 0, .max = UINT32_MAX},
1647 : : .eval = eval_jcc,
1648 : : },
1649 : : [(BPF_JMP | EBPF_JSLT | BPF_K)] = {
1650 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1651 : : .off = { .min = 0, .max = UINT16_MAX},
1652 : : .imm = { .min = 0, .max = UINT32_MAX},
1653 : : .eval = eval_jcc,
1654 : : },
1655 : : [(BPF_JMP | EBPF_JSGE | BPF_K)] = {
1656 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1657 : : .off = { .min = 0, .max = UINT16_MAX},
1658 : : .imm = { .min = 0, .max = UINT32_MAX},
1659 : : .eval = eval_jcc,
1660 : : },
1661 : : [(BPF_JMP | EBPF_JSLE | BPF_K)] = {
1662 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1663 : : .off = { .min = 0, .max = UINT16_MAX},
1664 : : .imm = { .min = 0, .max = UINT32_MAX},
1665 : : .eval = eval_jcc,
1666 : : },
1667 : : [(BPF_JMP | BPF_JSET | BPF_K)] = {
1668 : : .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
1669 : : .off = { .min = 0, .max = UINT16_MAX},
1670 : : .imm = { .min = 0, .max = UINT32_MAX},
1671 : : .eval = eval_jcc,
1672 : : },
1673 : : /* jcc REG instructions */
1674 : : [(BPF_JMP | BPF_JEQ | BPF_X)] = {
1675 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1676 : : .off = { .min = 0, .max = UINT16_MAX},
1677 : : .imm = { .min = 0, .max = 0},
1678 : : .eval = eval_jcc,
1679 : : },
1680 : : [(BPF_JMP | EBPF_JNE | BPF_X)] = {
1681 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1682 : : .off = { .min = 0, .max = UINT16_MAX},
1683 : : .imm = { .min = 0, .max = 0},
1684 : : .eval = eval_jcc,
1685 : : },
1686 : : [(BPF_JMP | BPF_JGT | BPF_X)] = {
1687 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1688 : : .off = { .min = 0, .max = UINT16_MAX},
1689 : : .imm = { .min = 0, .max = 0},
1690 : : .eval = eval_jcc,
1691 : : },
1692 : : [(BPF_JMP | EBPF_JLT | BPF_X)] = {
1693 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1694 : : .off = { .min = 0, .max = UINT16_MAX},
1695 : : .imm = { .min = 0, .max = 0},
1696 : : .eval = eval_jcc,
1697 : : },
1698 : : [(BPF_JMP | BPF_JGE | BPF_X)] = {
1699 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1700 : : .off = { .min = 0, .max = UINT16_MAX},
1701 : : .imm = { .min = 0, .max = 0},
1702 : : .eval = eval_jcc,
1703 : : },
1704 : : [(BPF_JMP | EBPF_JLE | BPF_X)] = {
1705 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1706 : : .off = { .min = 0, .max = UINT16_MAX},
1707 : : .imm = { .min = 0, .max = 0},
1708 : : .eval = eval_jcc,
1709 : : },
1710 : : [(BPF_JMP | EBPF_JSGT | BPF_X)] = {
1711 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1712 : : .off = { .min = 0, .max = UINT16_MAX},
1713 : : .imm = { .min = 0, .max = 0},
1714 : : .eval = eval_jcc,
1715 : : },
1716 : : [(BPF_JMP | EBPF_JSLT | BPF_X)] = {
1717 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1718 : : .off = { .min = 0, .max = UINT16_MAX},
1719 : : .imm = { .min = 0, .max = 0},
1720 : : },
1721 : : [(BPF_JMP | EBPF_JSGE | BPF_X)] = {
1722 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1723 : : .off = { .min = 0, .max = UINT16_MAX},
1724 : : .imm = { .min = 0, .max = 0},
1725 : : .eval = eval_jcc,
1726 : : },
1727 : : [(BPF_JMP | EBPF_JSLE | BPF_X)] = {
1728 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1729 : : .off = { .min = 0, .max = UINT16_MAX},
1730 : : .imm = { .min = 0, .max = 0},
1731 : : .eval = eval_jcc,
1732 : : },
1733 : : [(BPF_JMP | BPF_JSET | BPF_X)] = {
1734 : : .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
1735 : : .off = { .min = 0, .max = UINT16_MAX},
1736 : : .imm = { .min = 0, .max = 0},
1737 : : .eval = eval_jcc,
1738 : : },
1739 : : /* call instruction */
1740 : : [(BPF_JMP | EBPF_CALL)] = {
1741 : : .mask = { .dreg = ZERO_REG, .sreg = ZERO_REG},
1742 : : .off = { .min = 0, .max = 0},
1743 : : .imm = { .min = 0, .max = UINT32_MAX},
1744 : : .eval = eval_call,
1745 : : },
1746 : : /* ret instruction */
1747 : : [(BPF_JMP | EBPF_EXIT)] = {
1748 : : .mask = { .dreg = ZERO_REG, .sreg = ZERO_REG},
1749 : : .off = { .min = 0, .max = 0},
1750 : : .imm = { .min = 0, .max = 0},
1751 : : .eval = eval_exit,
1752 : : },
1753 : : };
1754 : :
1755 : : /*
1756 : : * make sure that instruction syntax is valid,
1757 : : * and its fields don't violate particular instruction type restrictions.
1758 : : */
1759 : : static const char *
1760 : 2413 : check_syntax(const struct ebpf_insn *ins)
1761 : : {
1762 : :
1763 : : uint8_t op;
1764 : : uint16_t off;
1765 : : uint32_t imm;
1766 : :
1767 : 2413 : op = ins->code;
1768 : :
1769 [ + - ]: 2413 : if (ins_chk[op].mask.dreg == 0)
1770 : : return "invalid opcode";
1771 : :
1772 [ + - ]: 2413 : if ((ins_chk[op].mask.dreg & 1 << ins->dst_reg) == 0)
1773 : : return "invalid dst-reg field";
1774 : :
1775 [ + - ]: 2413 : if ((ins_chk[op].mask.sreg & 1 << ins->src_reg) == 0)
1776 : : return "invalid src-reg field";
1777 : :
1778 : 2413 : off = ins->off;
1779 [ + - + - ]: 2413 : if (ins_chk[op].off.min > off || ins_chk[op].off.max < off)
1780 : : return "invalid off field";
1781 : :
1782 : 2413 : imm = ins->imm;
1783 [ + - + + ]: 2413 : if (ins_chk[op].imm.min > imm || ins_chk[op].imm.max < imm)
1784 : : return "invalid imm field";
1785 : :
1786 [ + + ]: 2409 : if (ins_chk[op].check != NULL)
1787 : 8 : return ins_chk[op].check(ins);
1788 : :
1789 : : return NULL;
1790 : : }
1791 : :
1792 : : /*
1793 : : * helper function, return instruction index for the given node.
1794 : : */
1795 : : static uint32_t
1796 : : get_node_idx(const struct bpf_verifier *bvf, const struct inst_node *node)
1797 : : {
1798 : 5889 : return node - bvf->in;
1799 : : }
1800 : :
1801 : : /*
1802 : : * helper function, used to walk through constructed CFG.
1803 : : */
1804 : : static struct inst_node *
1805 : : get_next_node(struct bpf_verifier *bvf, struct inst_node *node)
1806 : : {
1807 : : uint32_t ce, ne, dst;
1808 : :
1809 : 10617 : ne = node->nb_edge;
1810 : 10617 : ce = node->cur_edge;
1811 [ + + + + ]: 10617 : if (ce == ne)
1812 : : return NULL;
1813 : :
1814 : 5482 : node->cur_edge++;
1815 : 5482 : dst = node->edge_dest[ce];
1816 : 5482 : return bvf->in + dst;
1817 : : }
1818 : :
1819 : : static void
1820 : : set_node_colour(struct bpf_verifier *bvf, struct inst_node *node,
1821 : : uint32_t new)
1822 : : {
1823 : : uint32_t prev;
1824 : :
1825 : : prev = node->colour;
1826 : 4792 : node->colour = new;
1827 : :
1828 : 4792 : bvf->node_colour[prev]--;
1829 : 4792 : bvf->node_colour[new]++;
1830 : 2396 : }
1831 : :
1832 : : /*
1833 : : * helper function, add new edge between two nodes.
1834 : : */
1835 : : static int
1836 : 2279 : add_edge(struct bpf_verifier *bvf, struct inst_node *node, uint32_t nidx)
1837 : : {
1838 : : uint32_t ne;
1839 : :
1840 [ + + ]: 2279 : if (nidx >= bvf->prm->nb_ins) {
1841 : 1 : RTE_BPF_LOG_LINE(ERR,
1842 : : "%s: program boundary violation at pc: %u, next pc: %u",
1843 : : __func__, get_node_idx(bvf, node), nidx);
1844 : 1 : return -EINVAL;
1845 : : }
1846 : :
1847 : 2278 : ne = node->nb_edge;
1848 [ - + ]: 2278 : if (ne >= RTE_DIM(node->edge_dest)) {
1849 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: internal error at pc: %u",
1850 : : __func__, get_node_idx(bvf, node));
1851 : 0 : return -EINVAL;
1852 : : }
1853 : :
1854 : 2278 : node->edge_dest[ne] = nidx;
1855 : 2278 : node->nb_edge = ne + 1;
1856 : 2278 : return 0;
1857 : : }
1858 : :
1859 : : /*
1860 : : * helper function, determine type of edge between two nodes.
1861 : : */
1862 : : static void
1863 : : set_edge_type(struct bpf_verifier *bvf, struct inst_node *node,
1864 : : const struct inst_node *next)
1865 : : {
1866 : : uint32_t ce, clr, type;
1867 : :
1868 : 2266 : ce = node->cur_edge - 1;
1869 : 2266 : clr = next->colour;
1870 : :
1871 : : type = UNKNOWN_EDGE;
1872 : :
1873 [ + + ]: 2266 : if (clr == WHITE)
1874 : : type = TREE_EDGE;
1875 [ + - ]: 258 : else if (clr == GREY)
1876 : : type = BACK_EDGE;
1877 [ + - ]: 258 : else if (clr == BLACK)
1878 : : /*
1879 : : * in fact it could be either direct or cross edge,
1880 : : * but for now, we don't need to distinguish between them.
1881 : : */
1882 : : type = CROSS_EDGE;
1883 : :
1884 : 2266 : node->edge_type[ce] = type;
1885 : 2266 : bvf->edge_type[type]++;
1886 : : }
1887 : :
1888 : : /*
1889 : : * Depth-First Search (DFS) through previously constructed
1890 : : * Control Flow Graph (CFG).
1891 : : * Information collected at this path would be used later
1892 : : * to determine is there any loops, and/or unreachable instructions.
1893 : : * PREREQUISITE: there is at least one node.
1894 : : */
1895 : : static void
1896 : 388 : dfs(struct bpf_verifier *bvf)
1897 : : {
1898 : : struct inst_node *next, *node;
1899 : :
1900 : : RTE_ASSERT(bvf->nb_nodes != 0);
1901 : : /*
1902 : : * Since there is at least one node, node with index 0 always exists;
1903 : : * it is our program entry point.
1904 : : */
1905 : 388 : node = &bvf->in[0];
1906 : : do {
1907 : :
1908 [ + + ]: 4404 : if (node->colour == WHITE)
1909 : : set_node_colour(bvf, node, GREY);
1910 : :
1911 [ + - ]: 4404 : if (node->colour == GREY) {
1912 : :
1913 : : /* find next unprocessed child node */
1914 : : do {
1915 : : next = get_next_node(bvf, node);
1916 [ + - ]: 2266 : if (next == NULL)
1917 : : break;
1918 : : set_edge_type(bvf, node, next);
1919 [ + + ]: 2266 : } while (next->colour != WHITE);
1920 : :
1921 [ + + ]: 4404 : if (next != NULL) {
1922 : : /* proceed with next child */
1923 : 2008 : next->prev_node = node;
1924 : : node = next;
1925 : : } else {
1926 : : /*
1927 : : * finished with current node and all it's kids,
1928 : : * proceed with parent
1929 : : */
1930 : : set_node_colour(bvf, node, BLACK);
1931 : 2396 : node->cur_edge = 0;
1932 : 2396 : node = node->prev_node;
1933 : : }
1934 : : } else
1935 : : node = NULL;
1936 [ + + ]: 4404 : } while (node != NULL);
1937 : 388 : }
1938 : :
1939 : : /*
1940 : : * report unreachable instructions.
1941 : : */
1942 : : static void
1943 : 0 : log_unreachable(const struct bpf_verifier *bvf)
1944 : : {
1945 : : uint32_t i;
1946 : : struct inst_node *node;
1947 : : const struct ebpf_insn *ins;
1948 : :
1949 [ # # ]: 0 : for (i = 0; i != bvf->prm->nb_ins; i++) {
1950 : :
1951 : 0 : node = bvf->in + i;
1952 : 0 : ins = bvf->prm->ins + i;
1953 : :
1954 [ # # ]: 0 : if (node->colour == WHITE &&
1955 [ # # ]: 0 : ins->code != (BPF_LD | BPF_IMM | EBPF_DW))
1956 : 0 : RTE_BPF_LOG_LINE(ERR, "unreachable code at pc: %u;", i);
1957 : : }
1958 : 0 : }
1959 : :
1960 : : /*
1961 : : * report loops detected.
1962 : : */
1963 : : static void
1964 : 0 : log_loop(const struct bpf_verifier *bvf)
1965 : : {
1966 : : uint32_t i, j;
1967 : : struct inst_node *node;
1968 : :
1969 [ # # ]: 0 : for (i = 0; i != bvf->prm->nb_ins; i++) {
1970 : :
1971 : 0 : node = bvf->in + i;
1972 [ # # ]: 0 : if (node->colour != BLACK)
1973 : 0 : continue;
1974 : :
1975 [ # # ]: 0 : for (j = 0; j != node->nb_edge; j++) {
1976 [ # # ]: 0 : if (node->edge_type[j] == BACK_EDGE)
1977 : 0 : RTE_BPF_LOG_LINE(ERR,
1978 : : "loop at pc:%u --> pc:%u;",
1979 : : i, node->edge_dest[j]);
1980 : : }
1981 : : }
1982 : 0 : }
1983 : :
1984 : : /*
1985 : : * First pass goes though all instructions in the set, checks that each
1986 : : * instruction is a valid one (correct syntax, valid field values, etc.)
1987 : : * and constructs control flow graph (CFG).
1988 : : * Then depth-first search is performed over the constructed graph.
1989 : : * Programs with unreachable instructions and/or loops will be rejected.
1990 : : */
1991 : : static int
1992 : 393 : validate(struct bpf_verifier *bvf)
1993 : : {
1994 : : int32_t rc;
1995 : : uint32_t i;
1996 : : struct inst_node *node;
1997 : : const struct ebpf_insn *ins;
1998 : : const char *err;
1999 : :
2000 : : rc = 0;
2001 [ + + ]: 2806 : for (i = 0; i < bvf->prm->nb_ins; i++) {
2002 : :
2003 : 2413 : ins = bvf->prm->ins + i;
2004 : 2413 : node = bvf->in + i;
2005 : :
2006 : 2413 : err = check_syntax(ins);
2007 [ + + ]: 2413 : if (err != 0) {
2008 : 4 : RTE_BPF_LOG_LINE(ERR, "%s: %s at pc: %u",
2009 : : __func__, err, i);
2010 : 4 : rc |= -EINVAL;
2011 : : }
2012 : :
2013 : : /*
2014 : : * construct CFG, jcc nodes have to outgoing edges,
2015 : : * 'exit' nodes - none, all other nodes have exactly one
2016 : : * outgoing edge.
2017 : : */
2018 [ + + + + : 2413 : switch (ins->code) {
+ + ]
2019 : : case (BPF_JMP | EBPF_EXIT):
2020 : : break;
2021 : 289 : case (BPF_JMP | BPF_JEQ | BPF_K):
2022 : : case (BPF_JMP | EBPF_JNE | BPF_K):
2023 : : case (BPF_JMP | BPF_JGT | BPF_K):
2024 : : case (BPF_JMP | EBPF_JLT | BPF_K):
2025 : : case (BPF_JMP | BPF_JGE | BPF_K):
2026 : : case (BPF_JMP | EBPF_JLE | BPF_K):
2027 : : case (BPF_JMP | EBPF_JSGT | BPF_K):
2028 : : case (BPF_JMP | EBPF_JSLT | BPF_K):
2029 : : case (BPF_JMP | EBPF_JSGE | BPF_K):
2030 : : case (BPF_JMP | EBPF_JSLE | BPF_K):
2031 : : case (BPF_JMP | BPF_JSET | BPF_K):
2032 : : case (BPF_JMP | BPF_JEQ | BPF_X):
2033 : : case (BPF_JMP | EBPF_JNE | BPF_X):
2034 : : case (BPF_JMP | BPF_JGT | BPF_X):
2035 : : case (BPF_JMP | EBPF_JLT | BPF_X):
2036 : : case (BPF_JMP | BPF_JGE | BPF_X):
2037 : : case (BPF_JMP | EBPF_JLE | BPF_X):
2038 : : case (BPF_JMP | EBPF_JSGT | BPF_X):
2039 : : case (BPF_JMP | EBPF_JSLT | BPF_X):
2040 : : case (BPF_JMP | EBPF_JSGE | BPF_X):
2041 : : case (BPF_JMP | EBPF_JSLE | BPF_X):
2042 : : case (BPF_JMP | BPF_JSET | BPF_X):
2043 : 289 : rc |= add_edge(bvf, node, i + ins->off + 1);
2044 : 289 : rc |= add_edge(bvf, node, i + 1);
2045 : 289 : bvf->nb_jcc_nodes++;
2046 : 289 : break;
2047 : 28 : case (BPF_JMP | BPF_JA):
2048 : 28 : rc |= add_edge(bvf, node, i + ins->off + 1);
2049 : 28 : break;
2050 : : /* load 64 bit immediate value */
2051 : 249 : case (BPF_LD | BPF_IMM | EBPF_DW):
2052 : 249 : rc |= add_edge(bvf, node, i + 2);
2053 : 249 : i++;
2054 : 249 : break;
2055 : 253 : case (BPF_LD | BPF_ABS | BPF_B):
2056 : : case (BPF_LD | BPF_ABS | BPF_H):
2057 : : case (BPF_LD | BPF_ABS | BPF_W):
2058 : : case (BPF_LD | BPF_IND | BPF_B):
2059 : : case (BPF_LD | BPF_IND | BPF_H):
2060 : : case (BPF_LD | BPF_IND | BPF_W):
2061 : 253 : bvf->nb_ldmb_nodes++;
2062 : : /* fallthrough */
2063 : 1424 : default:
2064 : 1424 : rc |= add_edge(bvf, node, i + 1);
2065 : 1424 : break;
2066 : : }
2067 : :
2068 : 2413 : bvf->nb_nodes++;
2069 : 2413 : bvf->node_colour[WHITE]++;
2070 : : }
2071 : :
2072 [ + + ]: 393 : if (rc != 0)
2073 : : return rc;
2074 : :
2075 [ - + ]: 388 : if (bvf->nb_nodes == 0) {
2076 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%p) the program is empty",
2077 : : __func__, bvf);
2078 : 0 : return -EINVAL;
2079 : : }
2080 : :
2081 : 388 : dfs(bvf);
2082 : :
2083 : 388 : RTE_LOG(DEBUG, BPF, "%s(%p) stats:\n"
2084 : : "nb_nodes=%u;\n"
2085 : : "nb_jcc_nodes=%u;\n"
2086 : : "node_color={[WHITE]=%u, [GREY]=%u,, [BLACK]=%u};\n"
2087 : : "edge_type={[UNKNOWN]=%u, [TREE]=%u, [BACK]=%u, [CROSS]=%u};\n",
2088 : : __func__, bvf,
2089 : : bvf->nb_nodes,
2090 : : bvf->nb_jcc_nodes,
2091 : : bvf->node_colour[WHITE], bvf->node_colour[GREY],
2092 : : bvf->node_colour[BLACK],
2093 : : bvf->edge_type[UNKNOWN_EDGE], bvf->edge_type[TREE_EDGE],
2094 : : bvf->edge_type[BACK_EDGE], bvf->edge_type[CROSS_EDGE]);
2095 : :
2096 [ - + ]: 388 : if (bvf->node_colour[BLACK] != bvf->nb_nodes) {
2097 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%p) unreachable instructions;",
2098 : : __func__, bvf);
2099 : 0 : log_unreachable(bvf);
2100 : 0 : return -EINVAL;
2101 : : }
2102 : :
2103 [ + - + - ]: 388 : if (bvf->node_colour[GREY] != 0 || bvf->node_colour[WHITE] != 0 ||
2104 [ - + ]: 388 : bvf->edge_type[UNKNOWN_EDGE] != 0) {
2105 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%p) DFS internal error;",
2106 : : __func__, bvf);
2107 : 0 : return -EINVAL;
2108 : : }
2109 : :
2110 [ - + ]: 388 : if (bvf->edge_type[BACK_EDGE] != 0) {
2111 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%p) loops detected;",
2112 : : __func__, bvf);
2113 : 0 : log_loop(bvf);
2114 : 0 : return -EINVAL;
2115 : : }
2116 : :
2117 : : return 0;
2118 : : }
2119 : :
2120 : : /*
2121 : : * helper functions get/free eval states.
2122 : : */
2123 : : static struct bpf_eval_state *
2124 : : pull_eval_state(struct evst_pool *pool)
2125 : : {
2126 : : uint32_t n;
2127 : :
2128 : 1503 : n = pool->cur;
2129 [ + + ]: 940 : if (n == pool->num)
2130 : : return NULL;
2131 : :
2132 : 1397 : pool->cur = n + 1;
2133 : 834 : return pool->ent + n;
2134 : : }
2135 : :
2136 : : static void
2137 : : push_eval_state(struct evst_pool *pool)
2138 : : {
2139 : : RTE_ASSERT(pool->cur != 0);
2140 : 563 : pool->cur--;
2141 : : }
2142 : :
2143 : : static void
2144 : 388 : evst_pool_fini(struct bpf_verifier *bvf)
2145 : : {
2146 : 388 : bvf->evst = NULL;
2147 : 388 : free(bvf->evst_sr_pool.ent);
2148 : 388 : memset(&bvf->evst_sr_pool, 0, sizeof(bvf->evst_sr_pool));
2149 : 388 : memset(&bvf->evst_tp_pool, 0, sizeof(bvf->evst_tp_pool));
2150 : 388 : }
2151 : :
2152 : : static int
2153 : 388 : evst_pool_init(struct bpf_verifier *bvf)
2154 : : {
2155 : : uint32_t k, n;
2156 : :
2157 : : /*
2158 : : * We need nb_jcc_nodes + 1 for save_cur/restore_cur
2159 : : * remaining ones will be used for state tracking/pruning.
2160 : : */
2161 : 388 : k = bvf->nb_jcc_nodes + 1;
2162 : 388 : n = k * 3;
2163 : :
2164 : 388 : bvf->evst_sr_pool.ent = calloc(n, sizeof(bvf->evst_sr_pool.ent[0]));
2165 [ + - ]: 388 : if (bvf->evst_sr_pool.ent == NULL)
2166 : : return -ENOMEM;
2167 : :
2168 : 388 : bvf->evst_sr_pool.num = k;
2169 : 388 : bvf->evst_sr_pool.cur = 0;
2170 : :
2171 : 388 : bvf->evst_tp_pool.ent = bvf->evst_sr_pool.ent + k;
2172 : 388 : bvf->evst_tp_pool.num = n - k;
2173 [ + - ]: 388 : bvf->evst_tp_pool.cur = 0;
2174 : :
2175 : 388 : bvf->evst = pull_eval_state(&bvf->evst_sr_pool);
2176 : 388 : return 0;
2177 : : }
2178 : :
2179 : : /*
2180 : : * try to allocate and initialise new eval state for given node.
2181 : : * later if no errors will be encountered, this state will be accepted as
2182 : : * one of the possible 'safe' states for that node.
2183 : : */
2184 : : static void
2185 : 940 : save_start_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
2186 : : {
2187 : : RTE_ASSERT(node->evst.start == NULL);
2188 : :
2189 : : /* limit number of states for one node with some reasonable value */
2190 [ + - ]: 940 : if (node->evst.nb_safe >= NODE_EVST_MAX)
2191 : : return;
2192 : :
2193 : : /* try to get new eval_state */
2194 : 940 : node->evst.start = pull_eval_state(&bvf->evst_tp_pool);
2195 : :
2196 : : /* make a copy of current state */
2197 [ + + ]: 940 : if (node->evst.start != NULL) {
2198 : 446 : memcpy(node->evst.start, bvf->evst, sizeof(*node->evst.start));
2199 : 446 : SLIST_NEXT(node->evst.start, next) = NULL;
2200 : : }
2201 : : }
2202 : :
2203 : : /*
2204 : : * add @start state to the list of @safe states.
2205 : : */
2206 : : static void
2207 : 2739 : save_safe_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
2208 : : {
2209 [ + + ]: 2739 : if (node->evst.start == NULL)
2210 : : return;
2211 : :
2212 : 444 : SLIST_INSERT_HEAD(&node->evst.safe, node->evst.start, next);
2213 : 444 : node->evst.nb_safe++;
2214 : :
2215 : 444 : RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u,state=%p): nb_safe=%u;",
2216 : : __func__, bvf, get_node_idx(bvf, node), node->evst.start,
2217 : : node->evst.nb_safe);
2218 : :
2219 : 444 : node->evst.start = NULL;
2220 : : }
2221 : :
2222 : : /*
2223 : : * Save current eval state.
2224 : : */
2225 : : static int
2226 [ + - ]: 563 : save_cur_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
2227 : : {
2228 : : struct bpf_eval_state *st;
2229 : :
2230 : : /* get new eval_state for this node */
2231 : : st = pull_eval_state(&bvf->evst_sr_pool);
2232 [ - + ]: 563 : if (st == NULL) {
2233 : 0 : RTE_BPF_LOG_LINE(ERR,
2234 : : "%s: internal error (out of space) at pc: %u",
2235 : : __func__, get_node_idx(bvf, node));
2236 : 0 : return -ENOMEM;
2237 : : }
2238 : :
2239 : : /* make a copy of current state */
2240 : 563 : memcpy(st, bvf->evst, sizeof(*st));
2241 : :
2242 : : /* swap current state with new one */
2243 : : RTE_ASSERT(node->evst.cur == NULL);
2244 : 563 : node->evst.cur = bvf->evst;
2245 : 563 : bvf->evst = st;
2246 : :
2247 : 563 : RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u) old/new states: %p/%p;",
2248 : : __func__, bvf, get_node_idx(bvf, node), node->evst.cur,
2249 : : bvf->evst);
2250 : :
2251 : 563 : return 0;
2252 : : }
2253 : :
2254 : : /*
2255 : : * Restore previous eval state and mark current eval state as free.
2256 : : */
2257 : : static void
2258 : 563 : restore_cur_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
2259 : : {
2260 : 563 : RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u) old/new states: %p/%p;",
2261 : : __func__, bvf, get_node_idx(bvf, node), bvf->evst,
2262 : : node->evst.cur);
2263 : :
2264 : 563 : bvf->evst = node->evst.cur;
2265 : 563 : node->evst.cur = NULL;
2266 : : push_eval_state(&bvf->evst_sr_pool);
2267 : 563 : }
2268 : :
2269 : : static void
2270 : 3192 : log_dbg_eval_state(const struct bpf_verifier *bvf, const struct ebpf_insn *ins,
2271 : : uint32_t pc)
2272 : : {
2273 : : const struct bpf_eval_state *st;
2274 : : const struct bpf_reg_val *rv;
2275 : :
2276 : 3192 : RTE_BPF_LOG_LINE(DEBUG, "%s(pc=%u):", __func__, pc);
2277 : :
2278 : 3192 : st = bvf->evst;
2279 : 3192 : rv = st->rv + ins->dst_reg;
2280 : :
2281 : 3192 : RTE_LOG(DEBUG, BPF,
2282 : : "r%u={\n"
2283 : : "\tv={type=%u, size=%zu, buf_size=%zu},\n"
2284 : : "\tmask=0x%" PRIx64 ",\n"
2285 : : "\tu={min=0x%" PRIx64 ", max=0x%" PRIx64 "},\n"
2286 : : "\ts={min=%" PRId64 ", max=%" PRId64 "},\n"
2287 : : "};\n",
2288 : : ins->dst_reg,
2289 : : rv->v.type, rv->v.size, rv->v.buf_size,
2290 : : rv->mask,
2291 : : rv->u.min, rv->u.max,
2292 : : rv->s.min, rv->s.max);
2293 : 3192 : }
2294 : :
2295 : : /*
2296 : : * compare two evaluation states.
2297 : : * returns zero if @lv is more conservative (safer) then @rv.
2298 : : * returns non-zero value otherwise.
2299 : : */
2300 : : static int
2301 : 1463 : cmp_reg_val_within(const struct bpf_reg_val *lv, const struct bpf_reg_val *rv)
2302 : : {
2303 : : /* expect @v and @mask to be identical */
2304 [ + + + + ]: 1463 : if (memcmp(&lv->v, &rv->v, sizeof(lv->v)) != 0 || lv->mask != rv->mask)
2305 : : return -1;
2306 : :
2307 : : /* exact match only for mbuf and stack pointers */
2308 [ + - ]: 1305 : if (lv->v.type == RTE_BPF_ARG_PTR_MBUF ||
2309 : : lv->v.type == BPF_ARG_PTR_STACK)
2310 : : return -1;
2311 : :
2312 [ + + + + ]: 1305 : if (lv->u.min <= rv->u.min && lv->u.max >= rv->u.max &&
2313 [ + - + - ]: 14 : lv->s.min <= rv->s.min && lv->s.max >= rv->s.max)
2314 : 14 : return 0;
2315 : :
2316 : : return -1;
2317 : : }
2318 : :
2319 : : /*
2320 : : * compare two evaluation states.
2321 : : * returns zero if they are identical.
2322 : : * returns positive value if @lv is more conservative (safer) then @rv.
2323 : : * returns negative value otherwise.
2324 : : */
2325 : : static int
2326 : 1635 : cmp_eval_state(const struct bpf_eval_state *lv, const struct bpf_eval_state *rv)
2327 : : {
2328 : : int32_t rc;
2329 : : uint32_t i, k;
2330 : :
2331 : : /* for stack expect identical values */
2332 : 1635 : rc = memcmp(lv->sv, rv->sv, sizeof(lv->sv));
2333 [ + - ]: 1635 : if (rc != 0)
2334 : : return -(2 * EBPF_REG_NUM);
2335 : :
2336 : : k = 0;
2337 : : /* check register values */
2338 [ + + ]: 3861 : for (i = 0; i != RTE_DIM(lv->rv); i++) {
2339 : 3675 : rc = memcmp(&lv->rv[i], &rv->rv[i], sizeof(lv->rv[i]));
2340 [ + + + + ]: 3675 : if (rc != 0 && cmp_reg_val_within(&lv->rv[i], &rv->rv[i]) != 0)
2341 : 1449 : return -(i + 1);
2342 : 2226 : k += (rc != 0);
2343 : : }
2344 : :
2345 : 186 : return k;
2346 : : }
2347 : :
2348 : : /*
2349 : : * check did we already evaluated that path and can it be pruned that time.
2350 : : */
2351 : : static int
2352 : 1126 : prune_eval_state(struct bpf_verifier *bvf, const struct inst_node *node,
2353 : : struct inst_node *next)
2354 : : {
2355 : : int32_t rc;
2356 : : struct bpf_eval_state *safe;
2357 : :
2358 : : rc = INT32_MIN;
2359 [ + + ]: 2575 : SLIST_FOREACH(safe, &next->evst.safe, next) {
2360 : 1635 : rc = cmp_eval_state(safe, bvf->evst);
2361 [ + + ]: 1635 : if (rc >= 0)
2362 : : break;
2363 : : }
2364 : :
2365 [ + + ]: 1126 : rc = (rc >= 0) ? 0 : -1;
2366 : :
2367 : : /*
2368 : : * current state doesn't match any safe states,
2369 : : * so no prunning is possible right now,
2370 : : * track current state for future references.
2371 : : */
2372 : : if (rc != 0)
2373 : 940 : save_start_eval_state(bvf, next);
2374 : :
2375 : 1126 : RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u,next=%u) returns %d, "
2376 : : "next->evst.start=%p, next->evst.nb_safe=%u",
2377 : : __func__, bvf, get_node_idx(bvf, node),
2378 : : get_node_idx(bvf, next), rc,
2379 : : next->evst.start, next->evst.nb_safe);
2380 : 1126 : return rc;
2381 : : }
2382 : :
2383 : : /* Do second pass through CFG and try to evaluate instructions
2384 : : * via each possible path. The verifier will try all paths, tracking types of
2385 : : * registers used as input to instructions, and updating resulting type via
2386 : : * register state values. Plus for each register and possible stack value it
2387 : : * tries to estimate possible max/min value.
2388 : : * For conditional jumps, a stack is used to save evaluation state, so one
2389 : : * path is explored while the state for the other path is pushed onto the stack.
2390 : : * Then later, we backtrack to the first pushed instruction and repeat the cycle
2391 : : * until the stack is empty and we're done.
2392 : : * For program with many conditional branches walking through all possible path
2393 : : * could be very excessive. So to minimize number of evaluations we use
2394 : : * heuristic similar to what Linux kernel does - state pruning:
2395 : : * If from given instruction for given program state we explore all possible
2396 : : * paths and for each of them reach _exit() without any complaints and a valid
2397 : : * R0 value, then for that instruction, that program state can be marked as
2398 : : * 'safe'. When we later arrive at the same instruction with a state
2399 : : * equivalent to an earlier instruction's 'safe' state, we can prune the search.
2400 : : * For now, only states for JCC targets are saved/examined.
2401 : : */
2402 : : static int
2403 : 388 : evaluate(struct bpf_verifier *bvf)
2404 : : {
2405 : : int32_t rc;
2406 : : uint32_t idx, op;
2407 : : const char *err;
2408 : : const struct ebpf_insn *ins;
2409 : : struct inst_node *next, *node;
2410 : :
2411 : : struct {
2412 : : uint32_t nb_eval;
2413 : : uint32_t nb_prune;
2414 : : uint32_t nb_save;
2415 : : uint32_t nb_restore;
2416 : : } stats;
2417 : :
2418 : : /* initial state of frame pointer */
2419 : : static const struct bpf_reg_val rvfp = {
2420 : : .v = {
2421 : : .type = BPF_ARG_PTR_STACK,
2422 : : .size = MAX_BPF_STACK_SIZE,
2423 : : },
2424 : : .mask = UINT64_MAX,
2425 : : .u = {.min = MAX_BPF_STACK_SIZE, .max = MAX_BPF_STACK_SIZE},
2426 : : .s = {.min = MAX_BPF_STACK_SIZE, .max = MAX_BPF_STACK_SIZE},
2427 : : };
2428 : :
2429 : 388 : bvf->evst->rv[EBPF_REG_1].v = bvf->prm->prog_arg;
2430 : 388 : bvf->evst->rv[EBPF_REG_1].mask = UINT64_MAX;
2431 [ + + ]: 388 : if (bvf->prm->prog_arg.type == RTE_BPF_ARG_RAW)
2432 : : eval_max_bound(bvf->evst->rv + EBPF_REG_1, UINT64_MAX);
2433 : :
2434 : 388 : bvf->evst->rv[EBPF_REG_10] = rvfp;
2435 : :
2436 : 388 : ins = bvf->prm->ins;
2437 : 388 : node = bvf->in;
2438 : : next = node;
2439 : : rc = 0;
2440 : :
2441 : : memset(&stats, 0, sizeof(stats));
2442 : :
2443 [ + + ]: 6343 : while (node != NULL && rc == 0) {
2444 : :
2445 : : /*
2446 : : * current node evaluation, make sure we evaluate
2447 : : * each node only once.
2448 : : */
2449 [ + + ]: 5955 : if (next != NULL) {
2450 : :
2451 : 3192 : bvf->evin = node;
2452 : : idx = get_node_idx(bvf, node);
2453 : 3192 : op = ins[idx].code;
2454 : :
2455 : : /* for jcc node make a copy of evaluation state */
2456 [ + + ]: 3192 : if (node->nb_edge > 1) {
2457 : 563 : rc |= save_cur_eval_state(bvf, node);
2458 : 563 : stats.nb_save++;
2459 : : }
2460 : :
2461 [ + + + - ]: 3192 : if (ins_chk[op].eval != NULL && rc == 0) {
2462 : 2917 : err = ins_chk[op].eval(bvf, ins + idx);
2463 : 2917 : stats.nb_eval++;
2464 [ + + ]: 2917 : if (err != NULL) {
2465 : 227 : RTE_BPF_LOG_LINE(ERR, "%s: %s at pc: %u",
2466 : : __func__, err, idx);
2467 : : rc = -EINVAL;
2468 : : }
2469 : : }
2470 : :
2471 : 3192 : log_dbg_eval_state(bvf, ins + idx, idx);
2472 : 3192 : bvf->evin = NULL;
2473 : : }
2474 : :
2475 : : /* proceed through CFG */
2476 : : next = get_next_node(bvf, node);
2477 : :
2478 [ + - ]: 3216 : if (next != NULL) {
2479 : :
2480 : : /* proceed with next child */
2481 [ + + ]: 3216 : if (node->cur_edge == node->nb_edge &&
2482 [ + + ]: 2653 : node->evst.cur != NULL) {
2483 : 563 : restore_cur_eval_state(bvf, node);
2484 : 563 : stats.nb_restore++;
2485 : : }
2486 : :
2487 : : /*
2488 : : * for jcc targets: check did we already evaluated
2489 : : * that path and can it's evaluation be skipped that
2490 : : * time.
2491 : : */
2492 [ + + + + ]: 3216 : if (node->nb_edge > 1 && prune_eval_state(bvf, node,
2493 : : next) == 0) {
2494 : : next = NULL;
2495 : 186 : stats.nb_prune++;
2496 : : } else {
2497 : 3030 : next->prev_node = node;
2498 : : node = next;
2499 : : }
2500 : : } else {
2501 : : /*
2502 : : * finished with current node and all it's kids,
2503 : : * mark it's @start state as safe for future references,
2504 : : * and proceed with parent.
2505 : : */
2506 : 2739 : node->cur_edge = 0;
2507 : 2739 : save_safe_eval_state(bvf, node);
2508 : 2739 : node = node->prev_node;
2509 : :
2510 : : /* first node will not have prev, signalling finish */
2511 : : }
2512 : : }
2513 : :
2514 : 388 : RTE_LOG(DEBUG, BPF, "%s(%p) returns %d, stats:\n"
2515 : : "node evaluations=%u;\n"
2516 : : "state pruned=%u;\n"
2517 : : "state saves=%u;\n"
2518 : : "state restores=%u;\n",
2519 : : __func__, bvf, rc,
2520 : : stats.nb_eval, stats.nb_prune, stats.nb_save, stats.nb_restore);
2521 : :
2522 : 388 : return rc;
2523 : : }
2524 : :
2525 : : int
2526 : 393 : __rte_bpf_validate(struct rte_bpf *bpf)
2527 : : {
2528 : : int32_t rc;
2529 : : struct bpf_verifier bvf;
2530 : :
2531 : : /* check input argument type, don't allow mbuf ptr on 32-bit */
2532 [ + + ]: 393 : if (bpf->prm.prog_arg.type != RTE_BPF_ARG_RAW &&
2533 [ - + ]: 31 : bpf->prm.prog_arg.type != RTE_BPF_ARG_PTR &&
2534 : : (sizeof(uint64_t) != sizeof(uintptr_t) ||
2535 : : bpf->prm.prog_arg.type != RTE_BPF_ARG_PTR_MBUF)) {
2536 : 0 : RTE_BPF_LOG_LINE(ERR, "%s: unsupported argument type", __func__);
2537 : 0 : return -ENOTSUP;
2538 : : }
2539 : :
2540 : : memset(&bvf, 0, sizeof(bvf));
2541 : 393 : bvf.prm = &bpf->prm;
2542 : 393 : bvf.in = calloc(bpf->prm.nb_ins, sizeof(bvf.in[0]));
2543 [ + - ]: 393 : if (bvf.in == NULL)
2544 : : return -ENOMEM;
2545 : :
2546 : 393 : rc = validate(&bvf);
2547 : :
2548 [ + + ]: 393 : if (rc == 0) {
2549 : 388 : rc = evst_pool_init(&bvf);
2550 [ + - ]: 388 : if (rc == 0)
2551 : 388 : rc = evaluate(&bvf);
2552 : 388 : evst_pool_fini(&bvf);
2553 : : }
2554 : :
2555 : 393 : free(bvf.in);
2556 : :
2557 : : /* copy collected info */
2558 [ + + ]: 393 : if (rc == 0) {
2559 : 161 : bpf->stack_sz = bvf.stack_sz;
2560 : :
2561 : : /* for LD_ABS/LD_IND, we'll need extra space on the stack */
2562 [ + + ]: 161 : if (bvf.nb_ldmb_nodes != 0)
2563 : 30 : bpf->stack_sz = RTE_ALIGN_CEIL(bpf->stack_sz +
2564 : : sizeof(uint64_t), sizeof(uint64_t));
2565 : : }
2566 : :
2567 : : return rc;
2568 : : }
|