199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2018 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <stdio.h>
672b452c5SDmitry Kozlyuk #include <stdlib.h>
799a2dd95SBruce Richardson #include <string.h>
899a2dd95SBruce Richardson #include <errno.h>
999a2dd95SBruce Richardson #include <stdint.h>
1099a2dd95SBruce Richardson #include <inttypes.h>
1199a2dd95SBruce Richardson
1299a2dd95SBruce Richardson #include <rte_common.h>
1399a2dd95SBruce Richardson
1499a2dd95SBruce Richardson #include "bpf_impl.h"
1599a2dd95SBruce Richardson
1699a2dd95SBruce Richardson #define BPF_ARG_PTR_STACK RTE_BPF_ARG_RESERVED
1799a2dd95SBruce Richardson
1899a2dd95SBruce Richardson struct bpf_reg_val {
1999a2dd95SBruce Richardson struct rte_bpf_arg v;
2099a2dd95SBruce Richardson uint64_t mask;
2199a2dd95SBruce Richardson struct {
2299a2dd95SBruce Richardson int64_t min;
2399a2dd95SBruce Richardson int64_t max;
2499a2dd95SBruce Richardson } s;
2599a2dd95SBruce Richardson struct {
2699a2dd95SBruce Richardson uint64_t min;
2799a2dd95SBruce Richardson uint64_t max;
2899a2dd95SBruce Richardson } u;
2999a2dd95SBruce Richardson };
3099a2dd95SBruce Richardson
3199a2dd95SBruce Richardson struct bpf_eval_state {
32*a258eebdSKonstantin Ananyev SLIST_ENTRY(bpf_eval_state) next; /* for @safe list traversal */
3399a2dd95SBruce Richardson struct bpf_reg_val rv[EBPF_REG_NUM];
3499a2dd95SBruce Richardson struct bpf_reg_val sv[MAX_BPF_STACK_SIZE / sizeof(uint64_t)];
3599a2dd95SBruce Richardson };
3699a2dd95SBruce Richardson
37*a258eebdSKonstantin Ananyev SLIST_HEAD(bpf_evst_head, bpf_eval_state);
38*a258eebdSKonstantin Ananyev
3999a2dd95SBruce Richardson /* possible instruction node colour */
4099a2dd95SBruce Richardson enum {
4199a2dd95SBruce Richardson WHITE,
4299a2dd95SBruce Richardson GREY,
4399a2dd95SBruce Richardson BLACK,
4499a2dd95SBruce Richardson MAX_NODE_COLOUR
4599a2dd95SBruce Richardson };
4699a2dd95SBruce Richardson
4799a2dd95SBruce Richardson /* possible edge types */
4899a2dd95SBruce Richardson enum {
4999a2dd95SBruce Richardson UNKNOWN_EDGE,
5099a2dd95SBruce Richardson TREE_EDGE,
5199a2dd95SBruce Richardson BACK_EDGE,
5299a2dd95SBruce Richardson CROSS_EDGE,
5399a2dd95SBruce Richardson MAX_EDGE_TYPE
5499a2dd95SBruce Richardson };
5599a2dd95SBruce Richardson
5699a2dd95SBruce Richardson #define MAX_EDGES 2
5799a2dd95SBruce Richardson
58*a258eebdSKonstantin Ananyev /* max number of 'safe' evaluated states to track per node */
59*a258eebdSKonstantin Ananyev #define NODE_EVST_MAX 32
60*a258eebdSKonstantin Ananyev
6199a2dd95SBruce Richardson struct inst_node {
6299a2dd95SBruce Richardson uint8_t colour;
6399a2dd95SBruce Richardson uint8_t nb_edge:4;
6499a2dd95SBruce Richardson uint8_t cur_edge:4;
6599a2dd95SBruce Richardson uint8_t edge_type[MAX_EDGES];
6699a2dd95SBruce Richardson uint32_t edge_dest[MAX_EDGES];
6799a2dd95SBruce Richardson uint32_t prev_node;
68*a258eebdSKonstantin Ananyev struct {
69*a258eebdSKonstantin Ananyev struct bpf_eval_state *cur; /* save/restore for jcc targets */
70*a258eebdSKonstantin Ananyev struct bpf_eval_state *start;
71*a258eebdSKonstantin Ananyev struct bpf_evst_head safe; /* safe states for track/prune */
72*a258eebdSKonstantin Ananyev uint32_t nb_safe;
73*a258eebdSKonstantin Ananyev } evst;
74*a258eebdSKonstantin Ananyev };
75*a258eebdSKonstantin Ananyev
76*a258eebdSKonstantin Ananyev struct evst_pool {
77*a258eebdSKonstantin Ananyev uint32_t num;
78*a258eebdSKonstantin Ananyev uint32_t cur;
79*a258eebdSKonstantin Ananyev struct bpf_eval_state *ent;
8099a2dd95SBruce Richardson };
8199a2dd95SBruce Richardson
8299a2dd95SBruce Richardson struct bpf_verifier {
8399a2dd95SBruce Richardson const struct rte_bpf_prm *prm;
8499a2dd95SBruce Richardson struct inst_node *in;
8599a2dd95SBruce Richardson uint64_t stack_sz;
8699a2dd95SBruce Richardson uint32_t nb_nodes;
8799a2dd95SBruce Richardson uint32_t nb_jcc_nodes;
8899a2dd95SBruce Richardson uint32_t nb_ldmb_nodes;
8999a2dd95SBruce Richardson uint32_t node_colour[MAX_NODE_COLOUR];
9099a2dd95SBruce Richardson uint32_t edge_type[MAX_EDGE_TYPE];
9199a2dd95SBruce Richardson struct bpf_eval_state *evst;
9299a2dd95SBruce Richardson struct inst_node *evin;
93*a258eebdSKonstantin Ananyev struct evst_pool evst_sr_pool; /* for evst save/restore */
94*a258eebdSKonstantin Ananyev struct evst_pool evst_tp_pool; /* for evst track/prune */
9599a2dd95SBruce Richardson };
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson struct bpf_ins_check {
9899a2dd95SBruce Richardson struct {
9999a2dd95SBruce Richardson uint16_t dreg;
10099a2dd95SBruce Richardson uint16_t sreg;
10199a2dd95SBruce Richardson } mask;
10299a2dd95SBruce Richardson struct {
10399a2dd95SBruce Richardson uint16_t min;
10499a2dd95SBruce Richardson uint16_t max;
10599a2dd95SBruce Richardson } off;
10699a2dd95SBruce Richardson struct {
10799a2dd95SBruce Richardson uint32_t min;
10899a2dd95SBruce Richardson uint32_t max;
10999a2dd95SBruce Richardson } imm;
11099a2dd95SBruce Richardson const char * (*check)(const struct ebpf_insn *);
11199a2dd95SBruce Richardson const char * (*eval)(struct bpf_verifier *, const struct ebpf_insn *);
11299a2dd95SBruce Richardson };
11399a2dd95SBruce Richardson
11499a2dd95SBruce Richardson #define ALL_REGS RTE_LEN2MASK(EBPF_REG_NUM, uint16_t)
11599a2dd95SBruce Richardson #define WRT_REGS RTE_LEN2MASK(EBPF_REG_10, uint16_t)
11699a2dd95SBruce Richardson #define ZERO_REG RTE_LEN2MASK(EBPF_REG_1, uint16_t)
11799a2dd95SBruce Richardson
11899a2dd95SBruce Richardson /* For LD_IND R6 is an implicit CTX register. */
11999a2dd95SBruce Richardson #define IND_SRC_REGS (WRT_REGS ^ 1 << EBPF_REG_6)
12099a2dd95SBruce Richardson
12199a2dd95SBruce Richardson /*
12299a2dd95SBruce Richardson * check and evaluate functions for particular instruction types.
12399a2dd95SBruce Richardson */
12499a2dd95SBruce Richardson
12599a2dd95SBruce Richardson static const char *
check_alu_bele(const struct ebpf_insn * ins)12699a2dd95SBruce Richardson check_alu_bele(const struct ebpf_insn *ins)
12799a2dd95SBruce Richardson {
12899a2dd95SBruce Richardson if (ins->imm != 16 && ins->imm != 32 && ins->imm != 64)
12999a2dd95SBruce Richardson return "invalid imm field";
13099a2dd95SBruce Richardson return NULL;
13199a2dd95SBruce Richardson }
13299a2dd95SBruce Richardson
13399a2dd95SBruce Richardson static const char *
eval_exit(struct bpf_verifier * bvf,const struct ebpf_insn * ins)13499a2dd95SBruce Richardson eval_exit(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
13599a2dd95SBruce Richardson {
13699a2dd95SBruce Richardson RTE_SET_USED(ins);
13799a2dd95SBruce Richardson if (bvf->evst->rv[EBPF_REG_0].v.type == RTE_BPF_ARG_UNDEF)
13899a2dd95SBruce Richardson return "undefined return value";
13999a2dd95SBruce Richardson return NULL;
14099a2dd95SBruce Richardson }
14199a2dd95SBruce Richardson
14299a2dd95SBruce Richardson /* setup max possible with this mask bounds */
14399a2dd95SBruce Richardson static void
eval_umax_bound(struct bpf_reg_val * rv,uint64_t mask)14499a2dd95SBruce Richardson eval_umax_bound(struct bpf_reg_val *rv, uint64_t mask)
14599a2dd95SBruce Richardson {
14699a2dd95SBruce Richardson rv->u.max = mask;
14799a2dd95SBruce Richardson rv->u.min = 0;
14899a2dd95SBruce Richardson }
14999a2dd95SBruce Richardson
15099a2dd95SBruce Richardson static void
eval_smax_bound(struct bpf_reg_val * rv,uint64_t mask)15199a2dd95SBruce Richardson eval_smax_bound(struct bpf_reg_val *rv, uint64_t mask)
15299a2dd95SBruce Richardson {
15399a2dd95SBruce Richardson rv->s.max = mask >> 1;
15499a2dd95SBruce Richardson rv->s.min = rv->s.max ^ UINT64_MAX;
15599a2dd95SBruce Richardson }
15699a2dd95SBruce Richardson
15799a2dd95SBruce Richardson static void
eval_max_bound(struct bpf_reg_val * rv,uint64_t mask)15899a2dd95SBruce Richardson eval_max_bound(struct bpf_reg_val *rv, uint64_t mask)
15999a2dd95SBruce Richardson {
16099a2dd95SBruce Richardson eval_umax_bound(rv, mask);
16199a2dd95SBruce Richardson eval_smax_bound(rv, mask);
16299a2dd95SBruce Richardson }
16399a2dd95SBruce Richardson
16499a2dd95SBruce Richardson static void
eval_fill_max_bound(struct bpf_reg_val * rv,uint64_t mask)16599a2dd95SBruce Richardson eval_fill_max_bound(struct bpf_reg_val *rv, uint64_t mask)
16699a2dd95SBruce Richardson {
16799a2dd95SBruce Richardson eval_max_bound(rv, mask);
16899a2dd95SBruce Richardson rv->v.type = RTE_BPF_ARG_RAW;
16999a2dd95SBruce Richardson rv->mask = mask;
17099a2dd95SBruce Richardson }
17199a2dd95SBruce Richardson
17299a2dd95SBruce Richardson static void
eval_fill_imm64(struct bpf_reg_val * rv,uint64_t mask,uint64_t val)17399a2dd95SBruce Richardson eval_fill_imm64(struct bpf_reg_val *rv, uint64_t mask, uint64_t val)
17499a2dd95SBruce Richardson {
17599a2dd95SBruce Richardson rv->mask = mask;
17699a2dd95SBruce Richardson rv->s.min = val;
17799a2dd95SBruce Richardson rv->s.max = val;
17899a2dd95SBruce Richardson rv->u.min = val;
17999a2dd95SBruce Richardson rv->u.max = val;
18099a2dd95SBruce Richardson }
18199a2dd95SBruce Richardson
18299a2dd95SBruce Richardson static void
eval_fill_imm(struct bpf_reg_val * rv,uint64_t mask,int32_t imm)18399a2dd95SBruce Richardson eval_fill_imm(struct bpf_reg_val *rv, uint64_t mask, int32_t imm)
18499a2dd95SBruce Richardson {
18599a2dd95SBruce Richardson uint64_t v;
18699a2dd95SBruce Richardson
18799a2dd95SBruce Richardson v = (uint64_t)imm & mask;
18899a2dd95SBruce Richardson
18999a2dd95SBruce Richardson rv->v.type = RTE_BPF_ARG_RAW;
19099a2dd95SBruce Richardson eval_fill_imm64(rv, mask, v);
19199a2dd95SBruce Richardson }
19299a2dd95SBruce Richardson
19399a2dd95SBruce Richardson static const char *
eval_ld_imm64(struct bpf_verifier * bvf,const struct ebpf_insn * ins)19499a2dd95SBruce Richardson eval_ld_imm64(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
19599a2dd95SBruce Richardson {
19699a2dd95SBruce Richardson uint32_t i;
19799a2dd95SBruce Richardson uint64_t val;
19899a2dd95SBruce Richardson struct bpf_reg_val *rd;
19999a2dd95SBruce Richardson
20099a2dd95SBruce Richardson val = (uint32_t)ins[0].imm | (uint64_t)(uint32_t)ins[1].imm << 32;
20199a2dd95SBruce Richardson
20299a2dd95SBruce Richardson rd = bvf->evst->rv + ins->dst_reg;
20399a2dd95SBruce Richardson rd->v.type = RTE_BPF_ARG_RAW;
20499a2dd95SBruce Richardson eval_fill_imm64(rd, UINT64_MAX, val);
20599a2dd95SBruce Richardson
20699a2dd95SBruce Richardson for (i = 0; i != bvf->prm->nb_xsym; i++) {
20799a2dd95SBruce Richardson
20899a2dd95SBruce Richardson /* load of external variable */
20999a2dd95SBruce Richardson if (bvf->prm->xsym[i].type == RTE_BPF_XTYPE_VAR &&
21099a2dd95SBruce Richardson (uintptr_t)bvf->prm->xsym[i].var.val == val) {
21199a2dd95SBruce Richardson rd->v = bvf->prm->xsym[i].var.desc;
21299a2dd95SBruce Richardson eval_fill_imm64(rd, UINT64_MAX, 0);
21399a2dd95SBruce Richardson break;
21499a2dd95SBruce Richardson }
21599a2dd95SBruce Richardson }
21699a2dd95SBruce Richardson
21799a2dd95SBruce Richardson return NULL;
21899a2dd95SBruce Richardson }
21999a2dd95SBruce Richardson
22099a2dd95SBruce Richardson static void
eval_apply_mask(struct bpf_reg_val * rv,uint64_t mask)22199a2dd95SBruce Richardson eval_apply_mask(struct bpf_reg_val *rv, uint64_t mask)
22299a2dd95SBruce Richardson {
22399a2dd95SBruce Richardson struct bpf_reg_val rt;
22499a2dd95SBruce Richardson
22599a2dd95SBruce Richardson rt.u.min = rv->u.min & mask;
22699a2dd95SBruce Richardson rt.u.max = rv->u.max & mask;
22799a2dd95SBruce Richardson if (rt.u.min != rv->u.min || rt.u.max != rv->u.max) {
22899a2dd95SBruce Richardson rv->u.max = RTE_MAX(rt.u.max, mask);
22999a2dd95SBruce Richardson rv->u.min = 0;
23099a2dd95SBruce Richardson }
23199a2dd95SBruce Richardson
23299a2dd95SBruce Richardson eval_smax_bound(&rt, mask);
23399a2dd95SBruce Richardson rv->s.max = RTE_MIN(rt.s.max, rv->s.max);
23499a2dd95SBruce Richardson rv->s.min = RTE_MAX(rt.s.min, rv->s.min);
23599a2dd95SBruce Richardson
23699a2dd95SBruce Richardson rv->mask = mask;
23799a2dd95SBruce Richardson }
23899a2dd95SBruce Richardson
23999a2dd95SBruce Richardson static void
eval_add(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,uint64_t msk)24099a2dd95SBruce Richardson eval_add(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, uint64_t msk)
24199a2dd95SBruce Richardson {
24299a2dd95SBruce Richardson struct bpf_reg_val rv;
24399a2dd95SBruce Richardson
24499a2dd95SBruce Richardson rv.u.min = (rd->u.min + rs->u.min) & msk;
24599a2dd95SBruce Richardson rv.u.max = (rd->u.max + rs->u.max) & msk;
24699a2dd95SBruce Richardson rv.s.min = (rd->s.min + rs->s.min) & msk;
24799a2dd95SBruce Richardson rv.s.max = (rd->s.max + rs->s.max) & msk;
24899a2dd95SBruce Richardson
24999a2dd95SBruce Richardson /*
25099a2dd95SBruce Richardson * if at least one of the operands is not constant,
25199a2dd95SBruce Richardson * then check for overflow
25299a2dd95SBruce Richardson */
25399a2dd95SBruce Richardson if ((rd->u.min != rd->u.max || rs->u.min != rs->u.max) &&
25499a2dd95SBruce Richardson (rv.u.min < rd->u.min || rv.u.max < rd->u.max))
25599a2dd95SBruce Richardson eval_umax_bound(&rv, msk);
25699a2dd95SBruce Richardson
25799a2dd95SBruce Richardson if ((rd->s.min != rd->s.max || rs->s.min != rs->s.max) &&
25899a2dd95SBruce Richardson (((rs->s.min < 0 && rv.s.min > rd->s.min) ||
25999a2dd95SBruce Richardson rv.s.min < rd->s.min) ||
26099a2dd95SBruce Richardson ((rs->s.max < 0 && rv.s.max > rd->s.max) ||
26199a2dd95SBruce Richardson rv.s.max < rd->s.max)))
26299a2dd95SBruce Richardson eval_smax_bound(&rv, msk);
26399a2dd95SBruce Richardson
26499a2dd95SBruce Richardson rd->s = rv.s;
26599a2dd95SBruce Richardson rd->u = rv.u;
26699a2dd95SBruce Richardson }
26799a2dd95SBruce Richardson
26899a2dd95SBruce Richardson static void
eval_sub(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,uint64_t msk)26999a2dd95SBruce Richardson eval_sub(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, uint64_t msk)
27099a2dd95SBruce Richardson {
27199a2dd95SBruce Richardson struct bpf_reg_val rv;
27299a2dd95SBruce Richardson
27399a2dd95SBruce Richardson rv.u.min = (rd->u.min - rs->u.max) & msk;
27499a2dd95SBruce Richardson rv.u.max = (rd->u.max - rs->u.min) & msk;
27599a2dd95SBruce Richardson rv.s.min = (rd->s.min - rs->s.max) & msk;
27699a2dd95SBruce Richardson rv.s.max = (rd->s.max - rs->s.min) & msk;
27799a2dd95SBruce Richardson
27899a2dd95SBruce Richardson /*
27999a2dd95SBruce Richardson * if at least one of the operands is not constant,
28099a2dd95SBruce Richardson * then check for overflow
28199a2dd95SBruce Richardson */
28299a2dd95SBruce Richardson if ((rd->u.min != rd->u.max || rs->u.min != rs->u.max) &&
28399a2dd95SBruce Richardson (rv.u.min > rd->u.min || rv.u.max > rd->u.max))
28499a2dd95SBruce Richardson eval_umax_bound(&rv, msk);
28599a2dd95SBruce Richardson
28699a2dd95SBruce Richardson if ((rd->s.min != rd->s.max || rs->s.min != rs->s.max) &&
28799a2dd95SBruce Richardson (((rs->s.min < 0 && rv.s.min < rd->s.min) ||
28899a2dd95SBruce Richardson rv.s.min > rd->s.min) ||
28999a2dd95SBruce Richardson ((rs->s.max < 0 && rv.s.max < rd->s.max) ||
29099a2dd95SBruce Richardson rv.s.max > rd->s.max)))
29199a2dd95SBruce Richardson eval_smax_bound(&rv, msk);
29299a2dd95SBruce Richardson
29399a2dd95SBruce Richardson rd->s = rv.s;
29499a2dd95SBruce Richardson rd->u = rv.u;
29599a2dd95SBruce Richardson }
29699a2dd95SBruce Richardson
29799a2dd95SBruce Richardson static void
eval_lsh(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)29899a2dd95SBruce Richardson eval_lsh(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
29999a2dd95SBruce Richardson uint64_t msk)
30099a2dd95SBruce Richardson {
30199a2dd95SBruce Richardson /* check if shift value is less then max result bits */
30299a2dd95SBruce Richardson if (rs->u.max >= opsz) {
30399a2dd95SBruce Richardson eval_max_bound(rd, msk);
30499a2dd95SBruce Richardson return;
30599a2dd95SBruce Richardson }
30699a2dd95SBruce Richardson
30799a2dd95SBruce Richardson /* check for overflow */
30899a2dd95SBruce Richardson if (rd->u.max > RTE_LEN2MASK(opsz - rs->u.max, uint64_t))
30999a2dd95SBruce Richardson eval_umax_bound(rd, msk);
31099a2dd95SBruce Richardson else {
31199a2dd95SBruce Richardson rd->u.max <<= rs->u.max;
31299a2dd95SBruce Richardson rd->u.min <<= rs->u.min;
31399a2dd95SBruce Richardson }
31499a2dd95SBruce Richardson
31599a2dd95SBruce Richardson /* check that dreg values are and would remain always positive */
31699a2dd95SBruce Richardson if ((uint64_t)rd->s.min >> (opsz - 1) != 0 || rd->s.max >=
31799a2dd95SBruce Richardson RTE_LEN2MASK(opsz - rs->u.max - 1, int64_t))
31899a2dd95SBruce Richardson eval_smax_bound(rd, msk);
31999a2dd95SBruce Richardson else {
32099a2dd95SBruce Richardson rd->s.max <<= rs->u.max;
32199a2dd95SBruce Richardson rd->s.min <<= rs->u.min;
32299a2dd95SBruce Richardson }
32399a2dd95SBruce Richardson }
32499a2dd95SBruce Richardson
32599a2dd95SBruce Richardson static void
eval_rsh(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)32699a2dd95SBruce Richardson eval_rsh(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
32799a2dd95SBruce Richardson uint64_t msk)
32899a2dd95SBruce Richardson {
32999a2dd95SBruce Richardson /* check if shift value is less then max result bits */
33099a2dd95SBruce Richardson if (rs->u.max >= opsz) {
33199a2dd95SBruce Richardson eval_max_bound(rd, msk);
33299a2dd95SBruce Richardson return;
33399a2dd95SBruce Richardson }
33499a2dd95SBruce Richardson
33599a2dd95SBruce Richardson rd->u.max >>= rs->u.min;
33699a2dd95SBruce Richardson rd->u.min >>= rs->u.max;
33799a2dd95SBruce Richardson
33899a2dd95SBruce Richardson /* check that dreg values are always positive */
33999a2dd95SBruce Richardson if ((uint64_t)rd->s.min >> (opsz - 1) != 0)
34099a2dd95SBruce Richardson eval_smax_bound(rd, msk);
34199a2dd95SBruce Richardson else {
34299a2dd95SBruce Richardson rd->s.max >>= rs->u.min;
34399a2dd95SBruce Richardson rd->s.min >>= rs->u.max;
34499a2dd95SBruce Richardson }
34599a2dd95SBruce Richardson }
34699a2dd95SBruce Richardson
34799a2dd95SBruce Richardson static void
eval_arsh(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)34899a2dd95SBruce Richardson eval_arsh(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
34999a2dd95SBruce Richardson uint64_t msk)
35099a2dd95SBruce Richardson {
35199a2dd95SBruce Richardson uint32_t shv;
35299a2dd95SBruce Richardson
35399a2dd95SBruce Richardson /* check if shift value is less then max result bits */
35499a2dd95SBruce Richardson if (rs->u.max >= opsz) {
35599a2dd95SBruce Richardson eval_max_bound(rd, msk);
35699a2dd95SBruce Richardson return;
35799a2dd95SBruce Richardson }
35899a2dd95SBruce Richardson
35999a2dd95SBruce Richardson rd->u.max = (int64_t)rd->u.max >> rs->u.min;
36099a2dd95SBruce Richardson rd->u.min = (int64_t)rd->u.min >> rs->u.max;
36199a2dd95SBruce Richardson
36299a2dd95SBruce Richardson /* if we have 32-bit values - extend them to 64-bit */
36399a2dd95SBruce Richardson if (opsz == sizeof(uint32_t) * CHAR_BIT) {
36499a2dd95SBruce Richardson rd->s.min <<= opsz;
36599a2dd95SBruce Richardson rd->s.max <<= opsz;
36699a2dd95SBruce Richardson shv = opsz;
36799a2dd95SBruce Richardson } else
36899a2dd95SBruce Richardson shv = 0;
36999a2dd95SBruce Richardson
37099a2dd95SBruce Richardson if (rd->s.min < 0)
37199a2dd95SBruce Richardson rd->s.min = (rd->s.min >> (rs->u.min + shv)) & msk;
37299a2dd95SBruce Richardson else
37399a2dd95SBruce Richardson rd->s.min = (rd->s.min >> (rs->u.max + shv)) & msk;
37499a2dd95SBruce Richardson
37599a2dd95SBruce Richardson if (rd->s.max < 0)
37699a2dd95SBruce Richardson rd->s.max = (rd->s.max >> (rs->u.max + shv)) & msk;
37799a2dd95SBruce Richardson else
37899a2dd95SBruce Richardson rd->s.max = (rd->s.max >> (rs->u.min + shv)) & msk;
37999a2dd95SBruce Richardson }
38099a2dd95SBruce Richardson
38199a2dd95SBruce Richardson static uint64_t
eval_umax_bits(uint64_t v,size_t opsz)38299a2dd95SBruce Richardson eval_umax_bits(uint64_t v, size_t opsz)
38399a2dd95SBruce Richardson {
38499a2dd95SBruce Richardson if (v == 0)
38599a2dd95SBruce Richardson return 0;
38699a2dd95SBruce Richardson
3873d4e27fdSDavid Marchand v = rte_clz64(v);
38899a2dd95SBruce Richardson return RTE_LEN2MASK(opsz - v, uint64_t);
38999a2dd95SBruce Richardson }
39099a2dd95SBruce Richardson
39199a2dd95SBruce Richardson /* estimate max possible value for (v1 & v2) */
39299a2dd95SBruce Richardson static uint64_t
eval_uand_max(uint64_t v1,uint64_t v2,size_t opsz)39399a2dd95SBruce Richardson eval_uand_max(uint64_t v1, uint64_t v2, size_t opsz)
39499a2dd95SBruce Richardson {
39599a2dd95SBruce Richardson v1 = eval_umax_bits(v1, opsz);
39699a2dd95SBruce Richardson v2 = eval_umax_bits(v2, opsz);
39799a2dd95SBruce Richardson return (v1 & v2);
39899a2dd95SBruce Richardson }
39999a2dd95SBruce Richardson
40099a2dd95SBruce Richardson /* estimate max possible value for (v1 | v2) */
40199a2dd95SBruce Richardson static uint64_t
eval_uor_max(uint64_t v1,uint64_t v2,size_t opsz)40299a2dd95SBruce Richardson eval_uor_max(uint64_t v1, uint64_t v2, size_t opsz)
40399a2dd95SBruce Richardson {
40499a2dd95SBruce Richardson v1 = eval_umax_bits(v1, opsz);
40599a2dd95SBruce Richardson v2 = eval_umax_bits(v2, opsz);
40699a2dd95SBruce Richardson return (v1 | v2);
40799a2dd95SBruce Richardson }
40899a2dd95SBruce Richardson
40999a2dd95SBruce Richardson static void
eval_and(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)41099a2dd95SBruce Richardson eval_and(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
41199a2dd95SBruce Richardson uint64_t msk)
41299a2dd95SBruce Richardson {
41399a2dd95SBruce Richardson /* both operands are constants */
41499a2dd95SBruce Richardson if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
41599a2dd95SBruce Richardson rd->u.min &= rs->u.min;
41699a2dd95SBruce Richardson rd->u.max &= rs->u.max;
41799a2dd95SBruce Richardson } else {
41899a2dd95SBruce Richardson rd->u.max = eval_uand_max(rd->u.max, rs->u.max, opsz);
41999a2dd95SBruce Richardson rd->u.min &= rs->u.min;
42099a2dd95SBruce Richardson }
42199a2dd95SBruce Richardson
42299a2dd95SBruce Richardson /* both operands are constants */
42399a2dd95SBruce Richardson if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
42499a2dd95SBruce Richardson rd->s.min &= rs->s.min;
42599a2dd95SBruce Richardson rd->s.max &= rs->s.max;
42699a2dd95SBruce Richardson /* at least one of operand is non-negative */
42799a2dd95SBruce Richardson } else if (rd->s.min >= 0 || rs->s.min >= 0) {
42899a2dd95SBruce Richardson rd->s.max = eval_uand_max(rd->s.max & (msk >> 1),
42999a2dd95SBruce Richardson rs->s.max & (msk >> 1), opsz);
43099a2dd95SBruce Richardson rd->s.min &= rs->s.min;
43199a2dd95SBruce Richardson } else
43299a2dd95SBruce Richardson eval_smax_bound(rd, msk);
43399a2dd95SBruce Richardson }
43499a2dd95SBruce Richardson
43599a2dd95SBruce Richardson static void
eval_or(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)43699a2dd95SBruce Richardson eval_or(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
43799a2dd95SBruce Richardson uint64_t msk)
43899a2dd95SBruce Richardson {
43999a2dd95SBruce Richardson /* both operands are constants */
44099a2dd95SBruce Richardson if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
44199a2dd95SBruce Richardson rd->u.min |= rs->u.min;
44299a2dd95SBruce Richardson rd->u.max |= rs->u.max;
44399a2dd95SBruce Richardson } else {
44499a2dd95SBruce Richardson rd->u.max = eval_uor_max(rd->u.max, rs->u.max, opsz);
44599a2dd95SBruce Richardson rd->u.min |= rs->u.min;
44699a2dd95SBruce Richardson }
44799a2dd95SBruce Richardson
44899a2dd95SBruce Richardson /* both operands are constants */
44999a2dd95SBruce Richardson if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
45099a2dd95SBruce Richardson rd->s.min |= rs->s.min;
45199a2dd95SBruce Richardson rd->s.max |= rs->s.max;
45299a2dd95SBruce Richardson
45399a2dd95SBruce Richardson /* both operands are non-negative */
45499a2dd95SBruce Richardson } else if (rd->s.min >= 0 || rs->s.min >= 0) {
45599a2dd95SBruce Richardson rd->s.max = eval_uor_max(rd->s.max, rs->s.max, opsz);
45699a2dd95SBruce Richardson rd->s.min |= rs->s.min;
45799a2dd95SBruce Richardson } else
45899a2dd95SBruce Richardson eval_smax_bound(rd, msk);
45999a2dd95SBruce Richardson }
46099a2dd95SBruce Richardson
46199a2dd95SBruce Richardson static void
eval_xor(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)46299a2dd95SBruce Richardson eval_xor(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
46399a2dd95SBruce Richardson uint64_t msk)
46499a2dd95SBruce Richardson {
46599a2dd95SBruce Richardson /* both operands are constants */
46699a2dd95SBruce Richardson if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
46799a2dd95SBruce Richardson rd->u.min ^= rs->u.min;
46899a2dd95SBruce Richardson rd->u.max ^= rs->u.max;
46999a2dd95SBruce Richardson } else {
47099a2dd95SBruce Richardson rd->u.max = eval_uor_max(rd->u.max, rs->u.max, opsz);
47199a2dd95SBruce Richardson rd->u.min = 0;
47299a2dd95SBruce Richardson }
47399a2dd95SBruce Richardson
47499a2dd95SBruce Richardson /* both operands are constants */
47599a2dd95SBruce Richardson if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
47699a2dd95SBruce Richardson rd->s.min ^= rs->s.min;
47799a2dd95SBruce Richardson rd->s.max ^= rs->s.max;
47899a2dd95SBruce Richardson
47999a2dd95SBruce Richardson /* both operands are non-negative */
48099a2dd95SBruce Richardson } else if (rd->s.min >= 0 || rs->s.min >= 0) {
48199a2dd95SBruce Richardson rd->s.max = eval_uor_max(rd->s.max, rs->s.max, opsz);
48299a2dd95SBruce Richardson rd->s.min = 0;
48399a2dd95SBruce Richardson } else
48499a2dd95SBruce Richardson eval_smax_bound(rd, msk);
48599a2dd95SBruce Richardson }
48699a2dd95SBruce Richardson
48799a2dd95SBruce Richardson static void
eval_mul(struct bpf_reg_val * rd,const struct bpf_reg_val * rs,size_t opsz,uint64_t msk)48899a2dd95SBruce Richardson eval_mul(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, size_t opsz,
48999a2dd95SBruce Richardson uint64_t msk)
49099a2dd95SBruce Richardson {
49199a2dd95SBruce Richardson /* both operands are constants */
49299a2dd95SBruce Richardson if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
49399a2dd95SBruce Richardson rd->u.min = (rd->u.min * rs->u.min) & msk;
49499a2dd95SBruce Richardson rd->u.max = (rd->u.max * rs->u.max) & msk;
49599a2dd95SBruce Richardson /* check for overflow */
49699a2dd95SBruce Richardson } else if (rd->u.max <= msk >> opsz / 2 && rs->u.max <= msk >> opsz) {
49799a2dd95SBruce Richardson rd->u.max *= rs->u.max;
49899a2dd95SBruce Richardson rd->u.min *= rd->u.min;
49999a2dd95SBruce Richardson } else
50099a2dd95SBruce Richardson eval_umax_bound(rd, msk);
50199a2dd95SBruce Richardson
50299a2dd95SBruce Richardson /* both operands are constants */
50399a2dd95SBruce Richardson if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
50499a2dd95SBruce Richardson rd->s.min = (rd->s.min * rs->s.min) & msk;
50599a2dd95SBruce Richardson rd->s.max = (rd->s.max * rs->s.max) & msk;
50699a2dd95SBruce Richardson /* check that both operands are positive and no overflow */
50799a2dd95SBruce Richardson } else if (rd->s.min >= 0 && rs->s.min >= 0) {
50899a2dd95SBruce Richardson rd->s.max *= rs->s.max;
50999a2dd95SBruce Richardson rd->s.min *= rd->s.min;
51099a2dd95SBruce Richardson } else
51199a2dd95SBruce Richardson eval_smax_bound(rd, msk);
51299a2dd95SBruce Richardson }
51399a2dd95SBruce Richardson
51499a2dd95SBruce Richardson static const char *
eval_divmod(uint32_t op,struct bpf_reg_val * rd,struct bpf_reg_val * rs,size_t opsz,uint64_t msk)51599a2dd95SBruce Richardson eval_divmod(uint32_t op, struct bpf_reg_val *rd, struct bpf_reg_val *rs,
51699a2dd95SBruce Richardson size_t opsz, uint64_t msk)
51799a2dd95SBruce Richardson {
51899a2dd95SBruce Richardson /* both operands are constants */
51999a2dd95SBruce Richardson if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) {
52099a2dd95SBruce Richardson if (rs->u.max == 0)
52199a2dd95SBruce Richardson return "division by 0";
52299a2dd95SBruce Richardson if (op == BPF_DIV) {
52399a2dd95SBruce Richardson rd->u.min /= rs->u.min;
52499a2dd95SBruce Richardson rd->u.max /= rs->u.max;
52599a2dd95SBruce Richardson } else {
52699a2dd95SBruce Richardson rd->u.min %= rs->u.min;
52799a2dd95SBruce Richardson rd->u.max %= rs->u.max;
52899a2dd95SBruce Richardson }
52999a2dd95SBruce Richardson } else {
53099a2dd95SBruce Richardson if (op == BPF_MOD)
53199a2dd95SBruce Richardson rd->u.max = RTE_MIN(rd->u.max, rs->u.max - 1);
53299a2dd95SBruce Richardson else
53399a2dd95SBruce Richardson rd->u.max = rd->u.max;
53499a2dd95SBruce Richardson rd->u.min = 0;
53599a2dd95SBruce Richardson }
53699a2dd95SBruce Richardson
53799a2dd95SBruce Richardson /* if we have 32-bit values - extend them to 64-bit */
53899a2dd95SBruce Richardson if (opsz == sizeof(uint32_t) * CHAR_BIT) {
53999a2dd95SBruce Richardson rd->s.min = (int32_t)rd->s.min;
54099a2dd95SBruce Richardson rd->s.max = (int32_t)rd->s.max;
54199a2dd95SBruce Richardson rs->s.min = (int32_t)rs->s.min;
54299a2dd95SBruce Richardson rs->s.max = (int32_t)rs->s.max;
54399a2dd95SBruce Richardson }
54499a2dd95SBruce Richardson
54599a2dd95SBruce Richardson /* both operands are constants */
54699a2dd95SBruce Richardson if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) {
54799a2dd95SBruce Richardson if (rs->s.max == 0)
54899a2dd95SBruce Richardson return "division by 0";
54999a2dd95SBruce Richardson if (op == BPF_DIV) {
55099a2dd95SBruce Richardson rd->s.min /= rs->s.min;
55199a2dd95SBruce Richardson rd->s.max /= rs->s.max;
55299a2dd95SBruce Richardson } else {
55399a2dd95SBruce Richardson rd->s.min %= rs->s.min;
55499a2dd95SBruce Richardson rd->s.max %= rs->s.max;
55599a2dd95SBruce Richardson }
55699a2dd95SBruce Richardson } else if (op == BPF_MOD) {
55799a2dd95SBruce Richardson rd->s.min = RTE_MAX(rd->s.max, 0);
55899a2dd95SBruce Richardson rd->s.min = RTE_MIN(rd->s.min, 0);
55999a2dd95SBruce Richardson } else
56099a2dd95SBruce Richardson eval_smax_bound(rd, msk);
56199a2dd95SBruce Richardson
56299a2dd95SBruce Richardson rd->s.max &= msk;
56399a2dd95SBruce Richardson rd->s.min &= msk;
56499a2dd95SBruce Richardson
56599a2dd95SBruce Richardson return NULL;
56699a2dd95SBruce Richardson }
56799a2dd95SBruce Richardson
56899a2dd95SBruce Richardson static void
eval_neg(struct bpf_reg_val * rd,size_t opsz,uint64_t msk)56999a2dd95SBruce Richardson eval_neg(struct bpf_reg_val *rd, size_t opsz, uint64_t msk)
57099a2dd95SBruce Richardson {
57199a2dd95SBruce Richardson uint64_t ux, uy;
57299a2dd95SBruce Richardson int64_t sx, sy;
57399a2dd95SBruce Richardson
57499a2dd95SBruce Richardson /* if we have 32-bit values - extend them to 64-bit */
57599a2dd95SBruce Richardson if (opsz == sizeof(uint32_t) * CHAR_BIT) {
57699a2dd95SBruce Richardson rd->u.min = (int32_t)rd->u.min;
57799a2dd95SBruce Richardson rd->u.max = (int32_t)rd->u.max;
57899a2dd95SBruce Richardson }
57999a2dd95SBruce Richardson
58099a2dd95SBruce Richardson ux = -(int64_t)rd->u.min & msk;
58199a2dd95SBruce Richardson uy = -(int64_t)rd->u.max & msk;
58299a2dd95SBruce Richardson
58399a2dd95SBruce Richardson rd->u.max = RTE_MAX(ux, uy);
58499a2dd95SBruce Richardson rd->u.min = RTE_MIN(ux, uy);
58599a2dd95SBruce Richardson
58699a2dd95SBruce Richardson /* if we have 32-bit values - extend them to 64-bit */
58799a2dd95SBruce Richardson if (opsz == sizeof(uint32_t) * CHAR_BIT) {
58899a2dd95SBruce Richardson rd->s.min = (int32_t)rd->s.min;
58999a2dd95SBruce Richardson rd->s.max = (int32_t)rd->s.max;
59099a2dd95SBruce Richardson }
59199a2dd95SBruce Richardson
59299a2dd95SBruce Richardson sx = -rd->s.min & msk;
59399a2dd95SBruce Richardson sy = -rd->s.max & msk;
59499a2dd95SBruce Richardson
59599a2dd95SBruce Richardson rd->s.max = RTE_MAX(sx, sy);
59699a2dd95SBruce Richardson rd->s.min = RTE_MIN(sx, sy);
59799a2dd95SBruce Richardson }
59899a2dd95SBruce Richardson
59999a2dd95SBruce Richardson static const char *
eval_ld_mbuf(struct bpf_verifier * bvf,const struct ebpf_insn * ins)60099a2dd95SBruce Richardson eval_ld_mbuf(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
60199a2dd95SBruce Richardson {
60299a2dd95SBruce Richardson uint32_t i, mode;
60399a2dd95SBruce Richardson struct bpf_reg_val *rv, ri, rs;
60499a2dd95SBruce Richardson
60599a2dd95SBruce Richardson mode = BPF_MODE(ins->code);
60699a2dd95SBruce Richardson
60799a2dd95SBruce Richardson /* R6 is an implicit input that must contain pointer to mbuf */
60899a2dd95SBruce Richardson if (bvf->evst->rv[EBPF_REG_6].v.type != RTE_BPF_ARG_PTR_MBUF)
60999a2dd95SBruce Richardson return "invalid type for implicit ctx register";
61099a2dd95SBruce Richardson
61199a2dd95SBruce Richardson if (mode == BPF_IND) {
61299a2dd95SBruce Richardson rs = bvf->evst->rv[ins->src_reg];
61399a2dd95SBruce Richardson if (rs.v.type != RTE_BPF_ARG_RAW)
61499a2dd95SBruce Richardson return "unexpected type for src register";
61599a2dd95SBruce Richardson
61699a2dd95SBruce Richardson eval_fill_imm(&ri, UINT64_MAX, ins->imm);
61799a2dd95SBruce Richardson eval_add(&rs, &ri, UINT64_MAX);
61899a2dd95SBruce Richardson
61999a2dd95SBruce Richardson if (rs.s.max < 0 || rs.u.min > UINT32_MAX)
62099a2dd95SBruce Richardson return "mbuf boundary violation";
62199a2dd95SBruce Richardson }
62299a2dd95SBruce Richardson
62399a2dd95SBruce Richardson /* R1-R5 scratch registers */
62499a2dd95SBruce Richardson for (i = EBPF_REG_1; i != EBPF_REG_6; i++)
62599a2dd95SBruce Richardson bvf->evst->rv[i].v.type = RTE_BPF_ARG_UNDEF;
62699a2dd95SBruce Richardson
62799a2dd95SBruce Richardson /* R0 is an implicit output, contains data fetched from the packet */
62899a2dd95SBruce Richardson rv = bvf->evst->rv + EBPF_REG_0;
62999a2dd95SBruce Richardson rv->v.size = bpf_size(BPF_SIZE(ins->code));
63099a2dd95SBruce Richardson eval_fill_max_bound(rv, RTE_LEN2MASK(rv->v.size * CHAR_BIT, uint64_t));
63199a2dd95SBruce Richardson
63299a2dd95SBruce Richardson return NULL;
63399a2dd95SBruce Richardson }
63499a2dd95SBruce Richardson
63599a2dd95SBruce Richardson /*
63699a2dd95SBruce Richardson * check that destination and source operand are in defined state.
63799a2dd95SBruce Richardson */
63899a2dd95SBruce Richardson static const char *
eval_defined(const struct bpf_reg_val * dst,const struct bpf_reg_val * src)63999a2dd95SBruce Richardson eval_defined(const struct bpf_reg_val *dst, const struct bpf_reg_val *src)
64099a2dd95SBruce Richardson {
64199a2dd95SBruce Richardson if (dst != NULL && dst->v.type == RTE_BPF_ARG_UNDEF)
64299a2dd95SBruce Richardson return "dest reg value is undefined";
64399a2dd95SBruce Richardson if (src != NULL && src->v.type == RTE_BPF_ARG_UNDEF)
64499a2dd95SBruce Richardson return "src reg value is undefined";
64599a2dd95SBruce Richardson return NULL;
64699a2dd95SBruce Richardson }
64799a2dd95SBruce Richardson
64899a2dd95SBruce Richardson static const char *
eval_alu(struct bpf_verifier * bvf,const struct ebpf_insn * ins)64999a2dd95SBruce Richardson eval_alu(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
65099a2dd95SBruce Richardson {
65199a2dd95SBruce Richardson uint64_t msk;
65299a2dd95SBruce Richardson uint32_t op;
6533eef6465SKonstantin Ananyev size_t opsz, sz;
65499a2dd95SBruce Richardson const char *err;
65599a2dd95SBruce Richardson struct bpf_eval_state *st;
65699a2dd95SBruce Richardson struct bpf_reg_val *rd, rs;
65799a2dd95SBruce Richardson
6583eef6465SKonstantin Ananyev sz = (BPF_CLASS(ins->code) == BPF_ALU) ?
65999a2dd95SBruce Richardson sizeof(uint32_t) : sizeof(uint64_t);
6603eef6465SKonstantin Ananyev opsz = sz * CHAR_BIT;
66199a2dd95SBruce Richardson msk = RTE_LEN2MASK(opsz, uint64_t);
66299a2dd95SBruce Richardson
66399a2dd95SBruce Richardson st = bvf->evst;
66499a2dd95SBruce Richardson rd = st->rv + ins->dst_reg;
66599a2dd95SBruce Richardson
66699a2dd95SBruce Richardson if (BPF_SRC(ins->code) == BPF_X) {
66799a2dd95SBruce Richardson rs = st->rv[ins->src_reg];
66899a2dd95SBruce Richardson eval_apply_mask(&rs, msk);
6693eef6465SKonstantin Ananyev } else {
6703eef6465SKonstantin Ananyev rs = (struct bpf_reg_val){.v = {.size = sz,},};
67199a2dd95SBruce Richardson eval_fill_imm(&rs, msk, ins->imm);
6723eef6465SKonstantin Ananyev }
67399a2dd95SBruce Richardson
67499a2dd95SBruce Richardson eval_apply_mask(rd, msk);
67599a2dd95SBruce Richardson
67699a2dd95SBruce Richardson op = BPF_OP(ins->code);
67799a2dd95SBruce Richardson
67880da6119SStephen Hemminger /* Allow self-xor as way to zero register */
67980da6119SStephen Hemminger if (op == BPF_XOR && BPF_SRC(ins->code) == BPF_X &&
68080da6119SStephen Hemminger ins->src_reg == ins->dst_reg) {
68180da6119SStephen Hemminger eval_fill_imm(&rs, UINT64_MAX, 0);
68280da6119SStephen Hemminger eval_fill_imm(rd, UINT64_MAX, 0);
68380da6119SStephen Hemminger }
68480da6119SStephen Hemminger
68599a2dd95SBruce Richardson err = eval_defined((op != EBPF_MOV) ? rd : NULL,
68699a2dd95SBruce Richardson (op != BPF_NEG) ? &rs : NULL);
68799a2dd95SBruce Richardson if (err != NULL)
68899a2dd95SBruce Richardson return err;
68999a2dd95SBruce Richardson
69099a2dd95SBruce Richardson if (op == BPF_ADD)
69199a2dd95SBruce Richardson eval_add(rd, &rs, msk);
69299a2dd95SBruce Richardson else if (op == BPF_SUB)
69399a2dd95SBruce Richardson eval_sub(rd, &rs, msk);
69499a2dd95SBruce Richardson else if (op == BPF_LSH)
69599a2dd95SBruce Richardson eval_lsh(rd, &rs, opsz, msk);
69699a2dd95SBruce Richardson else if (op == BPF_RSH)
69799a2dd95SBruce Richardson eval_rsh(rd, &rs, opsz, msk);
69899a2dd95SBruce Richardson else if (op == EBPF_ARSH)
69999a2dd95SBruce Richardson eval_arsh(rd, &rs, opsz, msk);
70099a2dd95SBruce Richardson else if (op == BPF_AND)
70199a2dd95SBruce Richardson eval_and(rd, &rs, opsz, msk);
70299a2dd95SBruce Richardson else if (op == BPF_OR)
70399a2dd95SBruce Richardson eval_or(rd, &rs, opsz, msk);
70499a2dd95SBruce Richardson else if (op == BPF_XOR)
70599a2dd95SBruce Richardson eval_xor(rd, &rs, opsz, msk);
70699a2dd95SBruce Richardson else if (op == BPF_MUL)
70799a2dd95SBruce Richardson eval_mul(rd, &rs, opsz, msk);
70899a2dd95SBruce Richardson else if (op == BPF_DIV || op == BPF_MOD)
70999a2dd95SBruce Richardson err = eval_divmod(op, rd, &rs, opsz, msk);
71099a2dd95SBruce Richardson else if (op == BPF_NEG)
71199a2dd95SBruce Richardson eval_neg(rd, opsz, msk);
71299a2dd95SBruce Richardson else if (op == EBPF_MOV)
71399a2dd95SBruce Richardson *rd = rs;
71499a2dd95SBruce Richardson else
71599a2dd95SBruce Richardson eval_max_bound(rd, msk);
71699a2dd95SBruce Richardson
71799a2dd95SBruce Richardson return err;
71899a2dd95SBruce Richardson }
71999a2dd95SBruce Richardson
72099a2dd95SBruce Richardson static const char *
eval_bele(struct bpf_verifier * bvf,const struct ebpf_insn * ins)72199a2dd95SBruce Richardson eval_bele(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
72299a2dd95SBruce Richardson {
72399a2dd95SBruce Richardson uint64_t msk;
72499a2dd95SBruce Richardson struct bpf_eval_state *st;
72599a2dd95SBruce Richardson struct bpf_reg_val *rd;
72699a2dd95SBruce Richardson const char *err;
72799a2dd95SBruce Richardson
72899a2dd95SBruce Richardson msk = RTE_LEN2MASK(ins->imm, uint64_t);
72999a2dd95SBruce Richardson
73099a2dd95SBruce Richardson st = bvf->evst;
73199a2dd95SBruce Richardson rd = st->rv + ins->dst_reg;
73299a2dd95SBruce Richardson
73399a2dd95SBruce Richardson err = eval_defined(rd, NULL);
73499a2dd95SBruce Richardson if (err != NULL)
73599a2dd95SBruce Richardson return err;
73699a2dd95SBruce Richardson
73799a2dd95SBruce Richardson #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
73899a2dd95SBruce Richardson if (ins->code == (BPF_ALU | EBPF_END | EBPF_TO_BE))
73999a2dd95SBruce Richardson eval_max_bound(rd, msk);
74099a2dd95SBruce Richardson else
74199a2dd95SBruce Richardson eval_apply_mask(rd, msk);
74299a2dd95SBruce Richardson #else
74399a2dd95SBruce Richardson if (ins->code == (BPF_ALU | EBPF_END | EBPF_TO_LE))
74499a2dd95SBruce Richardson eval_max_bound(rd, msk);
74599a2dd95SBruce Richardson else
74699a2dd95SBruce Richardson eval_apply_mask(rd, msk);
74799a2dd95SBruce Richardson #endif
74899a2dd95SBruce Richardson
74999a2dd95SBruce Richardson return NULL;
75099a2dd95SBruce Richardson }
75199a2dd95SBruce Richardson
75299a2dd95SBruce Richardson static const char *
eval_ptr(struct bpf_verifier * bvf,struct bpf_reg_val * rm,uint32_t opsz,uint32_t align,int16_t off)75399a2dd95SBruce Richardson eval_ptr(struct bpf_verifier *bvf, struct bpf_reg_val *rm, uint32_t opsz,
75499a2dd95SBruce Richardson uint32_t align, int16_t off)
75599a2dd95SBruce Richardson {
75699a2dd95SBruce Richardson struct bpf_reg_val rv;
75799a2dd95SBruce Richardson
75899a2dd95SBruce Richardson /* calculate reg + offset */
75999a2dd95SBruce Richardson eval_fill_imm(&rv, rm->mask, off);
76099a2dd95SBruce Richardson eval_add(rm, &rv, rm->mask);
76199a2dd95SBruce Richardson
76299a2dd95SBruce Richardson if (RTE_BPF_ARG_PTR_TYPE(rm->v.type) == 0)
76399a2dd95SBruce Richardson return "destination is not a pointer";
76499a2dd95SBruce Richardson
76599a2dd95SBruce Richardson if (rm->mask != UINT64_MAX)
76699a2dd95SBruce Richardson return "pointer truncation";
76799a2dd95SBruce Richardson
76899a2dd95SBruce Richardson if (rm->u.max + opsz > rm->v.size ||
76999a2dd95SBruce Richardson (uint64_t)rm->s.max + opsz > rm->v.size ||
77099a2dd95SBruce Richardson rm->s.min < 0)
77199a2dd95SBruce Richardson return "memory boundary violation";
77299a2dd95SBruce Richardson
77399a2dd95SBruce Richardson if (rm->u.max % align != 0)
77499a2dd95SBruce Richardson return "unaligned memory access";
77599a2dd95SBruce Richardson
77699a2dd95SBruce Richardson if (rm->v.type == BPF_ARG_PTR_STACK) {
77799a2dd95SBruce Richardson
77899a2dd95SBruce Richardson if (rm->u.max != rm->u.min || rm->s.max != rm->s.min ||
77999a2dd95SBruce Richardson rm->u.max != (uint64_t)rm->s.max)
78099a2dd95SBruce Richardson return "stack access with variable offset";
78199a2dd95SBruce Richardson
78299a2dd95SBruce Richardson bvf->stack_sz = RTE_MAX(bvf->stack_sz, rm->v.size - rm->u.max);
78399a2dd95SBruce Richardson
78499a2dd95SBruce Richardson /* pointer to mbuf */
78599a2dd95SBruce Richardson } else if (rm->v.type == RTE_BPF_ARG_PTR_MBUF) {
78699a2dd95SBruce Richardson
78799a2dd95SBruce Richardson if (rm->u.max != rm->u.min || rm->s.max != rm->s.min ||
78899a2dd95SBruce Richardson rm->u.max != (uint64_t)rm->s.max)
78999a2dd95SBruce Richardson return "mbuf access with variable offset";
79099a2dd95SBruce Richardson }
79199a2dd95SBruce Richardson
79299a2dd95SBruce Richardson return NULL;
79399a2dd95SBruce Richardson }
79499a2dd95SBruce Richardson
79599a2dd95SBruce Richardson static void
eval_max_load(struct bpf_reg_val * rv,uint64_t mask)79699a2dd95SBruce Richardson eval_max_load(struct bpf_reg_val *rv, uint64_t mask)
79799a2dd95SBruce Richardson {
79899a2dd95SBruce Richardson eval_umax_bound(rv, mask);
79999a2dd95SBruce Richardson
80099a2dd95SBruce Richardson /* full 64-bit load */
80199a2dd95SBruce Richardson if (mask == UINT64_MAX)
80299a2dd95SBruce Richardson eval_smax_bound(rv, mask);
80399a2dd95SBruce Richardson
80499a2dd95SBruce Richardson /* zero-extend load */
80599a2dd95SBruce Richardson rv->s.min = rv->u.min;
80699a2dd95SBruce Richardson rv->s.max = rv->u.max;
80799a2dd95SBruce Richardson }
80899a2dd95SBruce Richardson
80999a2dd95SBruce Richardson
81099a2dd95SBruce Richardson static const char *
eval_load(struct bpf_verifier * bvf,const struct ebpf_insn * ins)81199a2dd95SBruce Richardson eval_load(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
81299a2dd95SBruce Richardson {
81399a2dd95SBruce Richardson uint32_t opsz;
81499a2dd95SBruce Richardson uint64_t msk;
81599a2dd95SBruce Richardson const char *err;
81699a2dd95SBruce Richardson struct bpf_eval_state *st;
81799a2dd95SBruce Richardson struct bpf_reg_val *rd, rs;
81899a2dd95SBruce Richardson const struct bpf_reg_val *sv;
81999a2dd95SBruce Richardson
82099a2dd95SBruce Richardson st = bvf->evst;
82199a2dd95SBruce Richardson rd = st->rv + ins->dst_reg;
82299a2dd95SBruce Richardson rs = st->rv[ins->src_reg];
82399a2dd95SBruce Richardson opsz = bpf_size(BPF_SIZE(ins->code));
82499a2dd95SBruce Richardson msk = RTE_LEN2MASK(opsz * CHAR_BIT, uint64_t);
82599a2dd95SBruce Richardson
82699a2dd95SBruce Richardson err = eval_ptr(bvf, &rs, opsz, 1, ins->off);
82799a2dd95SBruce Richardson if (err != NULL)
82899a2dd95SBruce Richardson return err;
82999a2dd95SBruce Richardson
83099a2dd95SBruce Richardson if (rs.v.type == BPF_ARG_PTR_STACK) {
83199a2dd95SBruce Richardson
83299a2dd95SBruce Richardson sv = st->sv + rs.u.max / sizeof(uint64_t);
83399a2dd95SBruce Richardson if (sv->v.type == RTE_BPF_ARG_UNDEF || sv->mask < msk)
83499a2dd95SBruce Richardson return "undefined value on the stack";
83599a2dd95SBruce Richardson
83699a2dd95SBruce Richardson *rd = *sv;
83799a2dd95SBruce Richardson
83899a2dd95SBruce Richardson /* pointer to mbuf */
83999a2dd95SBruce Richardson } else if (rs.v.type == RTE_BPF_ARG_PTR_MBUF) {
84099a2dd95SBruce Richardson
84199a2dd95SBruce Richardson if (rs.u.max == offsetof(struct rte_mbuf, next)) {
84299a2dd95SBruce Richardson eval_fill_imm(rd, msk, 0);
84399a2dd95SBruce Richardson rd->v = rs.v;
84499a2dd95SBruce Richardson } else if (rs.u.max == offsetof(struct rte_mbuf, buf_addr)) {
84599a2dd95SBruce Richardson eval_fill_imm(rd, msk, 0);
84699a2dd95SBruce Richardson rd->v.type = RTE_BPF_ARG_PTR;
84799a2dd95SBruce Richardson rd->v.size = rs.v.buf_size;
84899a2dd95SBruce Richardson } else if (rs.u.max == offsetof(struct rte_mbuf, data_off)) {
84999a2dd95SBruce Richardson eval_fill_imm(rd, msk, RTE_PKTMBUF_HEADROOM);
85099a2dd95SBruce Richardson rd->v.type = RTE_BPF_ARG_RAW;
85199a2dd95SBruce Richardson } else {
85299a2dd95SBruce Richardson eval_max_load(rd, msk);
85399a2dd95SBruce Richardson rd->v.type = RTE_BPF_ARG_RAW;
85499a2dd95SBruce Richardson }
85599a2dd95SBruce Richardson
85699a2dd95SBruce Richardson /* pointer to raw data */
85799a2dd95SBruce Richardson } else {
85899a2dd95SBruce Richardson eval_max_load(rd, msk);
85999a2dd95SBruce Richardson rd->v.type = RTE_BPF_ARG_RAW;
86099a2dd95SBruce Richardson }
86199a2dd95SBruce Richardson
86299a2dd95SBruce Richardson return NULL;
86399a2dd95SBruce Richardson }
86499a2dd95SBruce Richardson
86599a2dd95SBruce Richardson static const char *
eval_mbuf_store(const struct bpf_reg_val * rv,uint32_t opsz)86699a2dd95SBruce Richardson eval_mbuf_store(const struct bpf_reg_val *rv, uint32_t opsz)
86799a2dd95SBruce Richardson {
86899a2dd95SBruce Richardson uint32_t i;
86999a2dd95SBruce Richardson
87099a2dd95SBruce Richardson static const struct {
87199a2dd95SBruce Richardson size_t off;
87299a2dd95SBruce Richardson size_t sz;
87399a2dd95SBruce Richardson } mbuf_ro_fileds[] = {
87499a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, buf_addr), },
87599a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, refcnt), },
87699a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, nb_segs), },
87799a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, buf_len), },
87899a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, pool), },
87999a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, next), },
88099a2dd95SBruce Richardson { .off = offsetof(struct rte_mbuf, priv_size), },
88199a2dd95SBruce Richardson };
88299a2dd95SBruce Richardson
88399a2dd95SBruce Richardson for (i = 0; i != RTE_DIM(mbuf_ro_fileds) &&
88499a2dd95SBruce Richardson (mbuf_ro_fileds[i].off + mbuf_ro_fileds[i].sz <=
88599a2dd95SBruce Richardson rv->u.max || rv->u.max + opsz <= mbuf_ro_fileds[i].off);
88699a2dd95SBruce Richardson i++)
88799a2dd95SBruce Richardson ;
88899a2dd95SBruce Richardson
88999a2dd95SBruce Richardson if (i != RTE_DIM(mbuf_ro_fileds))
89099a2dd95SBruce Richardson return "store to the read-only mbuf field";
89199a2dd95SBruce Richardson
89299a2dd95SBruce Richardson return NULL;
89399a2dd95SBruce Richardson
89499a2dd95SBruce Richardson }
89599a2dd95SBruce Richardson
89699a2dd95SBruce Richardson static const char *
eval_store(struct bpf_verifier * bvf,const struct ebpf_insn * ins)89799a2dd95SBruce Richardson eval_store(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
89899a2dd95SBruce Richardson {
89999a2dd95SBruce Richardson uint32_t opsz;
90099a2dd95SBruce Richardson uint64_t msk;
90199a2dd95SBruce Richardson const char *err;
90299a2dd95SBruce Richardson struct bpf_eval_state *st;
90399a2dd95SBruce Richardson struct bpf_reg_val rd, rs, *sv;
90499a2dd95SBruce Richardson
90599a2dd95SBruce Richardson opsz = bpf_size(BPF_SIZE(ins->code));
90699a2dd95SBruce Richardson msk = RTE_LEN2MASK(opsz * CHAR_BIT, uint64_t);
90799a2dd95SBruce Richardson
90899a2dd95SBruce Richardson st = bvf->evst;
90999a2dd95SBruce Richardson rd = st->rv[ins->dst_reg];
91099a2dd95SBruce Richardson
91199a2dd95SBruce Richardson if (BPF_CLASS(ins->code) == BPF_STX) {
91299a2dd95SBruce Richardson rs = st->rv[ins->src_reg];
91399a2dd95SBruce Richardson eval_apply_mask(&rs, msk);
91499a2dd95SBruce Richardson } else
91599a2dd95SBruce Richardson eval_fill_imm(&rs, msk, ins->imm);
91699a2dd95SBruce Richardson
91799a2dd95SBruce Richardson err = eval_defined(NULL, &rs);
91899a2dd95SBruce Richardson if (err != NULL)
91999a2dd95SBruce Richardson return err;
92099a2dd95SBruce Richardson
92199a2dd95SBruce Richardson err = eval_ptr(bvf, &rd, opsz, 1, ins->off);
92299a2dd95SBruce Richardson if (err != NULL)
92399a2dd95SBruce Richardson return err;
92499a2dd95SBruce Richardson
92599a2dd95SBruce Richardson if (rd.v.type == BPF_ARG_PTR_STACK) {
92699a2dd95SBruce Richardson
92799a2dd95SBruce Richardson sv = st->sv + rd.u.max / sizeof(uint64_t);
92899a2dd95SBruce Richardson if (BPF_CLASS(ins->code) == BPF_STX &&
92999a2dd95SBruce Richardson BPF_MODE(ins->code) == EBPF_XADD)
93099a2dd95SBruce Richardson eval_max_bound(sv, msk);
93199a2dd95SBruce Richardson else
93299a2dd95SBruce Richardson *sv = rs;
93399a2dd95SBruce Richardson
93499a2dd95SBruce Richardson /* pointer to mbuf */
93599a2dd95SBruce Richardson } else if (rd.v.type == RTE_BPF_ARG_PTR_MBUF) {
93699a2dd95SBruce Richardson err = eval_mbuf_store(&rd, opsz);
93799a2dd95SBruce Richardson if (err != NULL)
93899a2dd95SBruce Richardson return err;
93999a2dd95SBruce Richardson }
94099a2dd95SBruce Richardson
94199a2dd95SBruce Richardson return NULL;
94299a2dd95SBruce Richardson }
94399a2dd95SBruce Richardson
94499a2dd95SBruce Richardson static const char *
eval_func_arg(struct bpf_verifier * bvf,const struct rte_bpf_arg * arg,struct bpf_reg_val * rv)94599a2dd95SBruce Richardson eval_func_arg(struct bpf_verifier *bvf, const struct rte_bpf_arg *arg,
94699a2dd95SBruce Richardson struct bpf_reg_val *rv)
94799a2dd95SBruce Richardson {
94899a2dd95SBruce Richardson uint32_t i, n;
94999a2dd95SBruce Richardson struct bpf_eval_state *st;
95099a2dd95SBruce Richardson const char *err;
95199a2dd95SBruce Richardson
95299a2dd95SBruce Richardson st = bvf->evst;
95399a2dd95SBruce Richardson
95499a2dd95SBruce Richardson if (rv->v.type == RTE_BPF_ARG_UNDEF)
95599a2dd95SBruce Richardson return "Undefined argument type";
95699a2dd95SBruce Richardson
95799a2dd95SBruce Richardson if (arg->type != rv->v.type &&
95899a2dd95SBruce Richardson arg->type != RTE_BPF_ARG_RAW &&
95999a2dd95SBruce Richardson (arg->type != RTE_BPF_ARG_PTR ||
96099a2dd95SBruce Richardson RTE_BPF_ARG_PTR_TYPE(rv->v.type) == 0))
96199a2dd95SBruce Richardson return "Invalid argument type";
96299a2dd95SBruce Richardson
96399a2dd95SBruce Richardson err = NULL;
96499a2dd95SBruce Richardson
96599a2dd95SBruce Richardson /* argument is a pointer */
96699a2dd95SBruce Richardson if (RTE_BPF_ARG_PTR_TYPE(arg->type) != 0) {
96799a2dd95SBruce Richardson
96899a2dd95SBruce Richardson err = eval_ptr(bvf, rv, arg->size, 1, 0);
96999a2dd95SBruce Richardson
97099a2dd95SBruce Richardson /*
97199a2dd95SBruce Richardson * pointer to the variable on the stack is passed
97299a2dd95SBruce Richardson * as an argument, mark stack space it occupies as initialized.
97399a2dd95SBruce Richardson */
97499a2dd95SBruce Richardson if (err == NULL && rv->v.type == BPF_ARG_PTR_STACK) {
97599a2dd95SBruce Richardson
97699a2dd95SBruce Richardson i = rv->u.max / sizeof(uint64_t);
97799a2dd95SBruce Richardson n = i + arg->size / sizeof(uint64_t);
97899a2dd95SBruce Richardson while (i != n) {
97999a2dd95SBruce Richardson eval_fill_max_bound(st->sv + i, UINT64_MAX);
98099a2dd95SBruce Richardson i++;
98199a2dd95SBruce Richardson };
98299a2dd95SBruce Richardson }
98399a2dd95SBruce Richardson }
98499a2dd95SBruce Richardson
98599a2dd95SBruce Richardson return err;
98699a2dd95SBruce Richardson }
98799a2dd95SBruce Richardson
98899a2dd95SBruce Richardson static const char *
eval_call(struct bpf_verifier * bvf,const struct ebpf_insn * ins)98999a2dd95SBruce Richardson eval_call(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
99099a2dd95SBruce Richardson {
99199a2dd95SBruce Richardson uint32_t i, idx;
99299a2dd95SBruce Richardson struct bpf_reg_val *rv;
99399a2dd95SBruce Richardson const struct rte_bpf_xsym *xsym;
99499a2dd95SBruce Richardson const char *err;
99599a2dd95SBruce Richardson
99699a2dd95SBruce Richardson idx = ins->imm;
99799a2dd95SBruce Richardson
99899a2dd95SBruce Richardson if (idx >= bvf->prm->nb_xsym ||
99999a2dd95SBruce Richardson bvf->prm->xsym[idx].type != RTE_BPF_XTYPE_FUNC)
100099a2dd95SBruce Richardson return "invalid external function index";
100199a2dd95SBruce Richardson
100299a2dd95SBruce Richardson /* for now don't support function calls on 32 bit platform */
100399a2dd95SBruce Richardson if (sizeof(uint64_t) != sizeof(uintptr_t))
100499a2dd95SBruce Richardson return "function calls are supported only for 64 bit apps";
100599a2dd95SBruce Richardson
100699a2dd95SBruce Richardson xsym = bvf->prm->xsym + idx;
100799a2dd95SBruce Richardson
100899a2dd95SBruce Richardson /* evaluate function arguments */
100999a2dd95SBruce Richardson err = NULL;
101099a2dd95SBruce Richardson for (i = 0; i != xsym->func.nb_args && err == NULL; i++) {
101199a2dd95SBruce Richardson err = eval_func_arg(bvf, xsym->func.args + i,
101299a2dd95SBruce Richardson bvf->evst->rv + EBPF_REG_1 + i);
101399a2dd95SBruce Richardson }
101499a2dd95SBruce Richardson
101599a2dd95SBruce Richardson /* R1-R5 argument/scratch registers */
101699a2dd95SBruce Richardson for (i = EBPF_REG_1; i != EBPF_REG_6; i++)
101799a2dd95SBruce Richardson bvf->evst->rv[i].v.type = RTE_BPF_ARG_UNDEF;
101899a2dd95SBruce Richardson
101999a2dd95SBruce Richardson /* update return value */
102099a2dd95SBruce Richardson
102199a2dd95SBruce Richardson rv = bvf->evst->rv + EBPF_REG_0;
102299a2dd95SBruce Richardson rv->v = xsym->func.ret;
102399a2dd95SBruce Richardson if (rv->v.type == RTE_BPF_ARG_RAW)
102499a2dd95SBruce Richardson eval_fill_max_bound(rv,
102599a2dd95SBruce Richardson RTE_LEN2MASK(rv->v.size * CHAR_BIT, uint64_t));
102699a2dd95SBruce Richardson else if (RTE_BPF_ARG_PTR_TYPE(rv->v.type) != 0)
102799a2dd95SBruce Richardson eval_fill_imm64(rv, UINTPTR_MAX, 0);
102899a2dd95SBruce Richardson
102999a2dd95SBruce Richardson return err;
103099a2dd95SBruce Richardson }
103199a2dd95SBruce Richardson
103299a2dd95SBruce Richardson static void
eval_jeq_jne(struct bpf_reg_val * trd,struct bpf_reg_val * trs)103399a2dd95SBruce Richardson eval_jeq_jne(struct bpf_reg_val *trd, struct bpf_reg_val *trs)
103499a2dd95SBruce Richardson {
103599a2dd95SBruce Richardson /* sreg is constant */
103699a2dd95SBruce Richardson if (trs->u.min == trs->u.max) {
103799a2dd95SBruce Richardson trd->u = trs->u;
103899a2dd95SBruce Richardson /* dreg is constant */
103999a2dd95SBruce Richardson } else if (trd->u.min == trd->u.max) {
104099a2dd95SBruce Richardson trs->u = trd->u;
104199a2dd95SBruce Richardson } else {
104299a2dd95SBruce Richardson trd->u.max = RTE_MIN(trd->u.max, trs->u.max);
104399a2dd95SBruce Richardson trd->u.min = RTE_MAX(trd->u.min, trs->u.min);
104499a2dd95SBruce Richardson trs->u = trd->u;
104599a2dd95SBruce Richardson }
104699a2dd95SBruce Richardson
104799a2dd95SBruce Richardson /* sreg is constant */
104899a2dd95SBruce Richardson if (trs->s.min == trs->s.max) {
104999a2dd95SBruce Richardson trd->s = trs->s;
105099a2dd95SBruce Richardson /* dreg is constant */
105199a2dd95SBruce Richardson } else if (trd->s.min == trd->s.max) {
105299a2dd95SBruce Richardson trs->s = trd->s;
105399a2dd95SBruce Richardson } else {
105499a2dd95SBruce Richardson trd->s.max = RTE_MIN(trd->s.max, trs->s.max);
105599a2dd95SBruce Richardson trd->s.min = RTE_MAX(trd->s.min, trs->s.min);
105699a2dd95SBruce Richardson trs->s = trd->s;
105799a2dd95SBruce Richardson }
105899a2dd95SBruce Richardson }
105999a2dd95SBruce Richardson
106099a2dd95SBruce Richardson static void
eval_jgt_jle(struct bpf_reg_val * trd,struct bpf_reg_val * trs,struct bpf_reg_val * frd,struct bpf_reg_val * frs)106199a2dd95SBruce Richardson eval_jgt_jle(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
106299a2dd95SBruce Richardson struct bpf_reg_val *frd, struct bpf_reg_val *frs)
106399a2dd95SBruce Richardson {
106499a2dd95SBruce Richardson frd->u.max = RTE_MIN(frd->u.max, frs->u.min);
106599a2dd95SBruce Richardson trd->u.min = RTE_MAX(trd->u.min, trs->u.min + 1);
106699a2dd95SBruce Richardson }
106799a2dd95SBruce Richardson
106899a2dd95SBruce Richardson static void
eval_jlt_jge(struct bpf_reg_val * trd,struct bpf_reg_val * trs,struct bpf_reg_val * frd,struct bpf_reg_val * frs)106999a2dd95SBruce Richardson eval_jlt_jge(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
107099a2dd95SBruce Richardson struct bpf_reg_val *frd, struct bpf_reg_val *frs)
107199a2dd95SBruce Richardson {
107299a2dd95SBruce Richardson frd->u.min = RTE_MAX(frd->u.min, frs->u.min);
107399a2dd95SBruce Richardson trd->u.max = RTE_MIN(trd->u.max, trs->u.max - 1);
107499a2dd95SBruce Richardson }
107599a2dd95SBruce Richardson
107699a2dd95SBruce Richardson static void
eval_jsgt_jsle(struct bpf_reg_val * trd,struct bpf_reg_val * trs,struct bpf_reg_val * frd,struct bpf_reg_val * frs)107799a2dd95SBruce Richardson eval_jsgt_jsle(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
107899a2dd95SBruce Richardson struct bpf_reg_val *frd, struct bpf_reg_val *frs)
107999a2dd95SBruce Richardson {
108099a2dd95SBruce Richardson frd->s.max = RTE_MIN(frd->s.max, frs->s.min);
108199a2dd95SBruce Richardson trd->s.min = RTE_MAX(trd->s.min, trs->s.min + 1);
108299a2dd95SBruce Richardson }
108399a2dd95SBruce Richardson
108499a2dd95SBruce Richardson static void
eval_jslt_jsge(struct bpf_reg_val * trd,struct bpf_reg_val * trs,struct bpf_reg_val * frd,struct bpf_reg_val * frs)108599a2dd95SBruce Richardson eval_jslt_jsge(struct bpf_reg_val *trd, struct bpf_reg_val *trs,
108699a2dd95SBruce Richardson struct bpf_reg_val *frd, struct bpf_reg_val *frs)
108799a2dd95SBruce Richardson {
108899a2dd95SBruce Richardson frd->s.min = RTE_MAX(frd->s.min, frs->s.min);
108999a2dd95SBruce Richardson trd->s.max = RTE_MIN(trd->s.max, trs->s.max - 1);
109099a2dd95SBruce Richardson }
109199a2dd95SBruce Richardson
109299a2dd95SBruce Richardson static const char *
eval_jcc(struct bpf_verifier * bvf,const struct ebpf_insn * ins)109399a2dd95SBruce Richardson eval_jcc(struct bpf_verifier *bvf, const struct ebpf_insn *ins)
109499a2dd95SBruce Richardson {
109599a2dd95SBruce Richardson uint32_t op;
109699a2dd95SBruce Richardson const char *err;
109799a2dd95SBruce Richardson struct bpf_eval_state *fst, *tst;
109899a2dd95SBruce Richardson struct bpf_reg_val *frd, *frs, *trd, *trs;
109999a2dd95SBruce Richardson struct bpf_reg_val rvf, rvt;
110099a2dd95SBruce Richardson
110199a2dd95SBruce Richardson tst = bvf->evst;
1102*a258eebdSKonstantin Ananyev fst = bvf->evin->evst.cur;
110399a2dd95SBruce Richardson
110499a2dd95SBruce Richardson frd = fst->rv + ins->dst_reg;
110599a2dd95SBruce Richardson trd = tst->rv + ins->dst_reg;
110699a2dd95SBruce Richardson
110799a2dd95SBruce Richardson if (BPF_SRC(ins->code) == BPF_X) {
110899a2dd95SBruce Richardson frs = fst->rv + ins->src_reg;
110999a2dd95SBruce Richardson trs = tst->rv + ins->src_reg;
111099a2dd95SBruce Richardson } else {
111199a2dd95SBruce Richardson frs = &rvf;
111299a2dd95SBruce Richardson trs = &rvt;
111399a2dd95SBruce Richardson eval_fill_imm(frs, UINT64_MAX, ins->imm);
111499a2dd95SBruce Richardson eval_fill_imm(trs, UINT64_MAX, ins->imm);
111599a2dd95SBruce Richardson }
111699a2dd95SBruce Richardson
111799a2dd95SBruce Richardson err = eval_defined(trd, trs);
111899a2dd95SBruce Richardson if (err != NULL)
111999a2dd95SBruce Richardson return err;
112099a2dd95SBruce Richardson
112199a2dd95SBruce Richardson op = BPF_OP(ins->code);
112299a2dd95SBruce Richardson
112399a2dd95SBruce Richardson if (op == BPF_JEQ)
112499a2dd95SBruce Richardson eval_jeq_jne(trd, trs);
112599a2dd95SBruce Richardson else if (op == EBPF_JNE)
112699a2dd95SBruce Richardson eval_jeq_jne(frd, frs);
112799a2dd95SBruce Richardson else if (op == BPF_JGT)
112899a2dd95SBruce Richardson eval_jgt_jle(trd, trs, frd, frs);
112999a2dd95SBruce Richardson else if (op == EBPF_JLE)
113099a2dd95SBruce Richardson eval_jgt_jle(frd, frs, trd, trs);
113199a2dd95SBruce Richardson else if (op == EBPF_JLT)
113299a2dd95SBruce Richardson eval_jlt_jge(trd, trs, frd, frs);
113399a2dd95SBruce Richardson else if (op == BPF_JGE)
113499a2dd95SBruce Richardson eval_jlt_jge(frd, frs, trd, trs);
113599a2dd95SBruce Richardson else if (op == EBPF_JSGT)
113699a2dd95SBruce Richardson eval_jsgt_jsle(trd, trs, frd, frs);
113799a2dd95SBruce Richardson else if (op == EBPF_JSLE)
113899a2dd95SBruce Richardson eval_jsgt_jsle(frd, frs, trd, trs);
1139cdcee2ecSHongbo Zheng else if (op == EBPF_JSLT)
114099a2dd95SBruce Richardson eval_jslt_jsge(trd, trs, frd, frs);
114199a2dd95SBruce Richardson else if (op == EBPF_JSGE)
114299a2dd95SBruce Richardson eval_jslt_jsge(frd, frs, trd, trs);
114399a2dd95SBruce Richardson
114499a2dd95SBruce Richardson return NULL;
114599a2dd95SBruce Richardson }
114699a2dd95SBruce Richardson
114799a2dd95SBruce Richardson /*
114899a2dd95SBruce Richardson * validate parameters for each instruction type.
114999a2dd95SBruce Richardson */
115099a2dd95SBruce Richardson static const struct bpf_ins_check ins_chk[UINT8_MAX + 1] = {
115199a2dd95SBruce Richardson /* ALU IMM 32-bit instructions */
115299a2dd95SBruce Richardson [(BPF_ALU | BPF_ADD | BPF_K)] = {
115399a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
115499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
115599a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
115699a2dd95SBruce Richardson .eval = eval_alu,
115799a2dd95SBruce Richardson },
115899a2dd95SBruce Richardson [(BPF_ALU | BPF_SUB | BPF_K)] = {
115999a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
116099a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
116199a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
116299a2dd95SBruce Richardson .eval = eval_alu,
116399a2dd95SBruce Richardson },
116499a2dd95SBruce Richardson [(BPF_ALU | BPF_AND | BPF_K)] = {
116599a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
116699a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
116799a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
116899a2dd95SBruce Richardson .eval = eval_alu,
116999a2dd95SBruce Richardson },
117099a2dd95SBruce Richardson [(BPF_ALU | BPF_OR | BPF_K)] = {
117199a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
117299a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
117399a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
117499a2dd95SBruce Richardson .eval = eval_alu,
117599a2dd95SBruce Richardson },
117699a2dd95SBruce Richardson [(BPF_ALU | BPF_LSH | BPF_K)] = {
117799a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
117899a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
117999a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
118099a2dd95SBruce Richardson .eval = eval_alu,
118199a2dd95SBruce Richardson },
118299a2dd95SBruce Richardson [(BPF_ALU | BPF_RSH | BPF_K)] = {
118399a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
118499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
118599a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
118699a2dd95SBruce Richardson .eval = eval_alu,
118799a2dd95SBruce Richardson },
118899a2dd95SBruce Richardson [(BPF_ALU | BPF_XOR | BPF_K)] = {
118999a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
119099a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
119199a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
119299a2dd95SBruce Richardson .eval = eval_alu,
119399a2dd95SBruce Richardson },
119499a2dd95SBruce Richardson [(BPF_ALU | BPF_MUL | BPF_K)] = {
119599a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
119699a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
119799a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
119899a2dd95SBruce Richardson .eval = eval_alu,
119999a2dd95SBruce Richardson },
120099a2dd95SBruce Richardson [(BPF_ALU | EBPF_MOV | BPF_K)] = {
120199a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
120299a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
120399a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
120499a2dd95SBruce Richardson .eval = eval_alu,
120599a2dd95SBruce Richardson },
120699a2dd95SBruce Richardson [(BPF_ALU | BPF_DIV | BPF_K)] = {
120799a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
120899a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
120999a2dd95SBruce Richardson .imm = { .min = 1, .max = UINT32_MAX},
121099a2dd95SBruce Richardson .eval = eval_alu,
121199a2dd95SBruce Richardson },
121299a2dd95SBruce Richardson [(BPF_ALU | BPF_MOD | BPF_K)] = {
121399a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
121499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
121599a2dd95SBruce Richardson .imm = { .min = 1, .max = UINT32_MAX},
121699a2dd95SBruce Richardson .eval = eval_alu,
121799a2dd95SBruce Richardson },
121899a2dd95SBruce Richardson /* ALU IMM 64-bit instructions */
121999a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_ADD | BPF_K)] = {
122099a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
122199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
122299a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
122399a2dd95SBruce Richardson .eval = eval_alu,
122499a2dd95SBruce Richardson },
122599a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_SUB | BPF_K)] = {
122699a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
122799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
122899a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
122999a2dd95SBruce Richardson .eval = eval_alu,
123099a2dd95SBruce Richardson },
123199a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_AND | BPF_K)] = {
123299a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
123399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
123499a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
123599a2dd95SBruce Richardson .eval = eval_alu,
123699a2dd95SBruce Richardson },
123799a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_OR | BPF_K)] = {
123899a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
123999a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
124099a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
124199a2dd95SBruce Richardson .eval = eval_alu,
124299a2dd95SBruce Richardson },
124399a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_LSH | BPF_K)] = {
124499a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
124599a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
124699a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
124799a2dd95SBruce Richardson .eval = eval_alu,
124899a2dd95SBruce Richardson },
124999a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_RSH | BPF_K)] = {
125099a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
125199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
125299a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
125399a2dd95SBruce Richardson .eval = eval_alu,
125499a2dd95SBruce Richardson },
125599a2dd95SBruce Richardson [(EBPF_ALU64 | EBPF_ARSH | BPF_K)] = {
125699a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
125799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
125899a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
125999a2dd95SBruce Richardson .eval = eval_alu,
126099a2dd95SBruce Richardson },
126199a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_XOR | BPF_K)] = {
126299a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
126399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
126499a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
126599a2dd95SBruce Richardson .eval = eval_alu,
126699a2dd95SBruce Richardson },
126799a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_MUL | BPF_K)] = {
126899a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
126999a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
127099a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
127199a2dd95SBruce Richardson .eval = eval_alu,
127299a2dd95SBruce Richardson },
127399a2dd95SBruce Richardson [(EBPF_ALU64 | EBPF_MOV | BPF_K)] = {
127499a2dd95SBruce Richardson .mask = {.dreg = WRT_REGS, .sreg = ZERO_REG},
127599a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
127699a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX,},
127799a2dd95SBruce Richardson .eval = eval_alu,
127899a2dd95SBruce Richardson },
127999a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_DIV | BPF_K)] = {
128099a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
128199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
128299a2dd95SBruce Richardson .imm = { .min = 1, .max = UINT32_MAX},
128399a2dd95SBruce Richardson .eval = eval_alu,
128499a2dd95SBruce Richardson },
128599a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_MOD | BPF_K)] = {
128699a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
128799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
128899a2dd95SBruce Richardson .imm = { .min = 1, .max = UINT32_MAX},
128999a2dd95SBruce Richardson .eval = eval_alu,
129099a2dd95SBruce Richardson },
129199a2dd95SBruce Richardson /* ALU REG 32-bit instructions */
129299a2dd95SBruce Richardson [(BPF_ALU | BPF_ADD | BPF_X)] = {
129399a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
129499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
129599a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
129699a2dd95SBruce Richardson .eval = eval_alu,
129799a2dd95SBruce Richardson },
129899a2dd95SBruce Richardson [(BPF_ALU | BPF_SUB | BPF_X)] = {
129999a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
130099a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
130199a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
130299a2dd95SBruce Richardson .eval = eval_alu,
130399a2dd95SBruce Richardson },
130499a2dd95SBruce Richardson [(BPF_ALU | BPF_AND | BPF_X)] = {
130599a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
130699a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
130799a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
130899a2dd95SBruce Richardson .eval = eval_alu,
130999a2dd95SBruce Richardson },
131099a2dd95SBruce Richardson [(BPF_ALU | BPF_OR | BPF_X)] = {
131199a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
131299a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
131399a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
131499a2dd95SBruce Richardson .eval = eval_alu,
131599a2dd95SBruce Richardson },
131699a2dd95SBruce Richardson [(BPF_ALU | BPF_LSH | BPF_X)] = {
131799a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
131899a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
131999a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
132099a2dd95SBruce Richardson .eval = eval_alu,
132199a2dd95SBruce Richardson },
132299a2dd95SBruce Richardson [(BPF_ALU | BPF_RSH | BPF_X)] = {
132399a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
132499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
132599a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
132699a2dd95SBruce Richardson .eval = eval_alu,
132799a2dd95SBruce Richardson },
132899a2dd95SBruce Richardson [(BPF_ALU | BPF_XOR | BPF_X)] = {
132999a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
133099a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
133199a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
133299a2dd95SBruce Richardson .eval = eval_alu,
133399a2dd95SBruce Richardson },
133499a2dd95SBruce Richardson [(BPF_ALU | BPF_MUL | BPF_X)] = {
133599a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
133699a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
133799a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
133899a2dd95SBruce Richardson .eval = eval_alu,
133999a2dd95SBruce Richardson },
134099a2dd95SBruce Richardson [(BPF_ALU | BPF_DIV | BPF_X)] = {
134199a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
134299a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
134399a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
134499a2dd95SBruce Richardson .eval = eval_alu,
134599a2dd95SBruce Richardson },
134699a2dd95SBruce Richardson [(BPF_ALU | BPF_MOD | BPF_X)] = {
134799a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
134899a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
134999a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
135099a2dd95SBruce Richardson .eval = eval_alu,
135199a2dd95SBruce Richardson },
135299a2dd95SBruce Richardson [(BPF_ALU | EBPF_MOV | BPF_X)] = {
135399a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
135499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
135599a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
135699a2dd95SBruce Richardson .eval = eval_alu,
135799a2dd95SBruce Richardson },
135899a2dd95SBruce Richardson [(BPF_ALU | BPF_NEG)] = {
135999a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
136099a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
136199a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
136299a2dd95SBruce Richardson .eval = eval_alu,
136399a2dd95SBruce Richardson },
136499a2dd95SBruce Richardson [(BPF_ALU | EBPF_END | EBPF_TO_BE)] = {
136599a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
136699a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
136799a2dd95SBruce Richardson .imm = { .min = 16, .max = 64},
136899a2dd95SBruce Richardson .check = check_alu_bele,
136999a2dd95SBruce Richardson .eval = eval_bele,
137099a2dd95SBruce Richardson },
137199a2dd95SBruce Richardson [(BPF_ALU | EBPF_END | EBPF_TO_LE)] = {
137299a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
137399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
137499a2dd95SBruce Richardson .imm = { .min = 16, .max = 64},
137599a2dd95SBruce Richardson .check = check_alu_bele,
137699a2dd95SBruce Richardson .eval = eval_bele,
137799a2dd95SBruce Richardson },
137899a2dd95SBruce Richardson /* ALU REG 64-bit instructions */
137999a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_ADD | BPF_X)] = {
138099a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
138199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
138299a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
138399a2dd95SBruce Richardson .eval = eval_alu,
138499a2dd95SBruce Richardson },
138599a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_SUB | BPF_X)] = {
138699a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
138799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
138899a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
138999a2dd95SBruce Richardson .eval = eval_alu,
139099a2dd95SBruce Richardson },
139199a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_AND | BPF_X)] = {
139299a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
139399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
139499a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
139599a2dd95SBruce Richardson .eval = eval_alu,
139699a2dd95SBruce Richardson },
139799a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_OR | BPF_X)] = {
139899a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
139999a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
140099a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
140199a2dd95SBruce Richardson .eval = eval_alu,
140299a2dd95SBruce Richardson },
140399a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_LSH | BPF_X)] = {
140499a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
140599a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
140699a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
140799a2dd95SBruce Richardson .eval = eval_alu,
140899a2dd95SBruce Richardson },
140999a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_RSH | BPF_X)] = {
141099a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
141199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
141299a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
141399a2dd95SBruce Richardson .eval = eval_alu,
141499a2dd95SBruce Richardson },
141599a2dd95SBruce Richardson [(EBPF_ALU64 | EBPF_ARSH | BPF_X)] = {
141699a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
141799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
141899a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
141999a2dd95SBruce Richardson .eval = eval_alu,
142099a2dd95SBruce Richardson },
142199a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_XOR | BPF_X)] = {
142299a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
142399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
142499a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
142599a2dd95SBruce Richardson .eval = eval_alu,
142699a2dd95SBruce Richardson },
142799a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_MUL | BPF_X)] = {
142899a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
142999a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
143099a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
143199a2dd95SBruce Richardson .eval = eval_alu,
143299a2dd95SBruce Richardson },
143399a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_DIV | BPF_X)] = {
143499a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
143599a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
143699a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
143799a2dd95SBruce Richardson .eval = eval_alu,
143899a2dd95SBruce Richardson },
143999a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_MOD | BPF_X)] = {
144099a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
144199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
144299a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
144399a2dd95SBruce Richardson .eval = eval_alu,
144499a2dd95SBruce Richardson },
144599a2dd95SBruce Richardson [(EBPF_ALU64 | EBPF_MOV | BPF_X)] = {
144699a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ALL_REGS},
144799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
144899a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
144999a2dd95SBruce Richardson .eval = eval_alu,
145099a2dd95SBruce Richardson },
145199a2dd95SBruce Richardson [(EBPF_ALU64 | BPF_NEG)] = {
145299a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
145399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
145499a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
145599a2dd95SBruce Richardson .eval = eval_alu,
145699a2dd95SBruce Richardson },
145799a2dd95SBruce Richardson /* load instructions */
145899a2dd95SBruce Richardson [(BPF_LDX | BPF_MEM | BPF_B)] = {
145999a2dd95SBruce Richardson .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
146099a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
146199a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
146299a2dd95SBruce Richardson .eval = eval_load,
146399a2dd95SBruce Richardson },
146499a2dd95SBruce Richardson [(BPF_LDX | BPF_MEM | BPF_H)] = {
146599a2dd95SBruce Richardson .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
146699a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
146799a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
146899a2dd95SBruce Richardson .eval = eval_load,
146999a2dd95SBruce Richardson },
147099a2dd95SBruce Richardson [(BPF_LDX | BPF_MEM | BPF_W)] = {
147199a2dd95SBruce Richardson .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
147299a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
147399a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
147499a2dd95SBruce Richardson .eval = eval_load,
147599a2dd95SBruce Richardson },
147699a2dd95SBruce Richardson [(BPF_LDX | BPF_MEM | EBPF_DW)] = {
147799a2dd95SBruce Richardson .mask = {. dreg = WRT_REGS, .sreg = ALL_REGS},
147899a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
147999a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
148099a2dd95SBruce Richardson .eval = eval_load,
148199a2dd95SBruce Richardson },
148299a2dd95SBruce Richardson /* load 64 bit immediate value */
148399a2dd95SBruce Richardson [(BPF_LD | BPF_IMM | EBPF_DW)] = {
148499a2dd95SBruce Richardson .mask = { .dreg = WRT_REGS, .sreg = ZERO_REG},
148599a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
148699a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
148799a2dd95SBruce Richardson .eval = eval_ld_imm64,
148899a2dd95SBruce Richardson },
148999a2dd95SBruce Richardson /* load absolute instructions */
149099a2dd95SBruce Richardson [(BPF_LD | BPF_ABS | BPF_B)] = {
149199a2dd95SBruce Richardson .mask = {. dreg = ZERO_REG, .sreg = ZERO_REG},
149299a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
149399a2dd95SBruce Richardson .imm = { .min = 0, .max = INT32_MAX},
149499a2dd95SBruce Richardson .eval = eval_ld_mbuf,
149599a2dd95SBruce Richardson },
149699a2dd95SBruce Richardson [(BPF_LD | BPF_ABS | BPF_H)] = {
149799a2dd95SBruce Richardson .mask = {. dreg = ZERO_REG, .sreg = ZERO_REG},
149899a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
149999a2dd95SBruce Richardson .imm = { .min = 0, .max = INT32_MAX},
150099a2dd95SBruce Richardson .eval = eval_ld_mbuf,
150199a2dd95SBruce Richardson },
150299a2dd95SBruce Richardson [(BPF_LD | BPF_ABS | BPF_W)] = {
150399a2dd95SBruce Richardson .mask = {. dreg = ZERO_REG, .sreg = ZERO_REG},
150499a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
150599a2dd95SBruce Richardson .imm = { .min = 0, .max = INT32_MAX},
150699a2dd95SBruce Richardson .eval = eval_ld_mbuf,
150799a2dd95SBruce Richardson },
150899a2dd95SBruce Richardson /* load indirect instructions */
150999a2dd95SBruce Richardson [(BPF_LD | BPF_IND | BPF_B)] = {
151099a2dd95SBruce Richardson .mask = {. dreg = ZERO_REG, .sreg = IND_SRC_REGS},
151199a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
151299a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
151399a2dd95SBruce Richardson .eval = eval_ld_mbuf,
151499a2dd95SBruce Richardson },
151599a2dd95SBruce Richardson [(BPF_LD | BPF_IND | BPF_H)] = {
151699a2dd95SBruce Richardson .mask = {. dreg = ZERO_REG, .sreg = IND_SRC_REGS},
151799a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
151899a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
151999a2dd95SBruce Richardson .eval = eval_ld_mbuf,
152099a2dd95SBruce Richardson },
152199a2dd95SBruce Richardson [(BPF_LD | BPF_IND | BPF_W)] = {
152299a2dd95SBruce Richardson .mask = {. dreg = ZERO_REG, .sreg = IND_SRC_REGS},
152399a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
152499a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
152599a2dd95SBruce Richardson .eval = eval_ld_mbuf,
152699a2dd95SBruce Richardson },
152799a2dd95SBruce Richardson /* store REG instructions */
152899a2dd95SBruce Richardson [(BPF_STX | BPF_MEM | BPF_B)] = {
152999a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
153099a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
153199a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
153299a2dd95SBruce Richardson .eval = eval_store,
153399a2dd95SBruce Richardson },
153499a2dd95SBruce Richardson [(BPF_STX | BPF_MEM | BPF_H)] = {
153599a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
153699a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
153799a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
153899a2dd95SBruce Richardson .eval = eval_store,
153999a2dd95SBruce Richardson },
154099a2dd95SBruce Richardson [(BPF_STX | BPF_MEM | BPF_W)] = {
154199a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
154299a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
154399a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
154499a2dd95SBruce Richardson .eval = eval_store,
154599a2dd95SBruce Richardson },
154699a2dd95SBruce Richardson [(BPF_STX | BPF_MEM | EBPF_DW)] = {
154799a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
154899a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
154999a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
155099a2dd95SBruce Richardson .eval = eval_store,
155199a2dd95SBruce Richardson },
155299a2dd95SBruce Richardson /* atomic add instructions */
155399a2dd95SBruce Richardson [(BPF_STX | EBPF_XADD | BPF_W)] = {
155499a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
155599a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
155699a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
155799a2dd95SBruce Richardson .eval = eval_store,
155899a2dd95SBruce Richardson },
155999a2dd95SBruce Richardson [(BPF_STX | EBPF_XADD | EBPF_DW)] = {
156099a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
156199a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
156299a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
156399a2dd95SBruce Richardson .eval = eval_store,
156499a2dd95SBruce Richardson },
156599a2dd95SBruce Richardson /* store IMM instructions */
156699a2dd95SBruce Richardson [(BPF_ST | BPF_MEM | BPF_B)] = {
156799a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
156899a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
156999a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
157099a2dd95SBruce Richardson .eval = eval_store,
157199a2dd95SBruce Richardson },
157299a2dd95SBruce Richardson [(BPF_ST | BPF_MEM | BPF_H)] = {
157399a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
157499a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
157599a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
157699a2dd95SBruce Richardson .eval = eval_store,
157799a2dd95SBruce Richardson },
157899a2dd95SBruce Richardson [(BPF_ST | BPF_MEM | BPF_W)] = {
157999a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
158099a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
158199a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
158299a2dd95SBruce Richardson .eval = eval_store,
158399a2dd95SBruce Richardson },
158499a2dd95SBruce Richardson [(BPF_ST | BPF_MEM | EBPF_DW)] = {
158599a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
158699a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
158799a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
158899a2dd95SBruce Richardson .eval = eval_store,
158999a2dd95SBruce Richardson },
159099a2dd95SBruce Richardson /* jump instruction */
159199a2dd95SBruce Richardson [(BPF_JMP | BPF_JA)] = {
159299a2dd95SBruce Richardson .mask = { .dreg = ZERO_REG, .sreg = ZERO_REG},
159399a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
159499a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
159599a2dd95SBruce Richardson },
159699a2dd95SBruce Richardson /* jcc IMM instructions */
159799a2dd95SBruce Richardson [(BPF_JMP | BPF_JEQ | BPF_K)] = {
159899a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
159999a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
160099a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
160199a2dd95SBruce Richardson .eval = eval_jcc,
160299a2dd95SBruce Richardson },
160399a2dd95SBruce Richardson [(BPF_JMP | EBPF_JNE | BPF_K)] = {
160499a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
160599a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
160699a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
160799a2dd95SBruce Richardson .eval = eval_jcc,
160899a2dd95SBruce Richardson },
160999a2dd95SBruce Richardson [(BPF_JMP | BPF_JGT | BPF_K)] = {
161099a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
161199a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
161299a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
161399a2dd95SBruce Richardson .eval = eval_jcc,
161499a2dd95SBruce Richardson },
161599a2dd95SBruce Richardson [(BPF_JMP | EBPF_JLT | BPF_K)] = {
161699a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
161799a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
161899a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
161999a2dd95SBruce Richardson .eval = eval_jcc,
162099a2dd95SBruce Richardson },
162199a2dd95SBruce Richardson [(BPF_JMP | BPF_JGE | BPF_K)] = {
162299a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
162399a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
162499a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
162599a2dd95SBruce Richardson .eval = eval_jcc,
162699a2dd95SBruce Richardson },
162799a2dd95SBruce Richardson [(BPF_JMP | EBPF_JLE | BPF_K)] = {
162899a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
162999a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
163099a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
163199a2dd95SBruce Richardson .eval = eval_jcc,
163299a2dd95SBruce Richardson },
163399a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSGT | BPF_K)] = {
163499a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
163599a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
163699a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
163799a2dd95SBruce Richardson .eval = eval_jcc,
163899a2dd95SBruce Richardson },
163999a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSLT | BPF_K)] = {
164099a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
164199a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
164299a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
164399a2dd95SBruce Richardson .eval = eval_jcc,
164499a2dd95SBruce Richardson },
164599a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSGE | BPF_K)] = {
164699a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
164799a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
164899a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
164999a2dd95SBruce Richardson .eval = eval_jcc,
165099a2dd95SBruce Richardson },
165199a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSLE | BPF_K)] = {
165299a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
165399a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
165499a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
165599a2dd95SBruce Richardson .eval = eval_jcc,
165699a2dd95SBruce Richardson },
165799a2dd95SBruce Richardson [(BPF_JMP | BPF_JSET | BPF_K)] = {
165899a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ZERO_REG},
165999a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
166099a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
166199a2dd95SBruce Richardson .eval = eval_jcc,
166299a2dd95SBruce Richardson },
166399a2dd95SBruce Richardson /* jcc REG instructions */
166499a2dd95SBruce Richardson [(BPF_JMP | BPF_JEQ | BPF_X)] = {
166599a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
166699a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
166799a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
166899a2dd95SBruce Richardson .eval = eval_jcc,
166999a2dd95SBruce Richardson },
167099a2dd95SBruce Richardson [(BPF_JMP | EBPF_JNE | BPF_X)] = {
167199a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
167299a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
167399a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
167499a2dd95SBruce Richardson .eval = eval_jcc,
167599a2dd95SBruce Richardson },
167699a2dd95SBruce Richardson [(BPF_JMP | BPF_JGT | BPF_X)] = {
167799a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
167899a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
167999a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
168099a2dd95SBruce Richardson .eval = eval_jcc,
168199a2dd95SBruce Richardson },
168299a2dd95SBruce Richardson [(BPF_JMP | EBPF_JLT | BPF_X)] = {
168399a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
168499a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
168599a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
168699a2dd95SBruce Richardson .eval = eval_jcc,
168799a2dd95SBruce Richardson },
168899a2dd95SBruce Richardson [(BPF_JMP | BPF_JGE | BPF_X)] = {
168999a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
169099a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
169199a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
169299a2dd95SBruce Richardson .eval = eval_jcc,
169399a2dd95SBruce Richardson },
169499a2dd95SBruce Richardson [(BPF_JMP | EBPF_JLE | BPF_X)] = {
169599a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
169699a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
169799a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
169899a2dd95SBruce Richardson .eval = eval_jcc,
169999a2dd95SBruce Richardson },
170099a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSGT | BPF_X)] = {
170199a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
170299a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
170399a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
170499a2dd95SBruce Richardson .eval = eval_jcc,
170599a2dd95SBruce Richardson },
170699a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSLT | BPF_X)] = {
170799a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
170899a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
170999a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
171099a2dd95SBruce Richardson },
171199a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSGE | BPF_X)] = {
171299a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
171399a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
171499a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
171599a2dd95SBruce Richardson .eval = eval_jcc,
171699a2dd95SBruce Richardson },
171799a2dd95SBruce Richardson [(BPF_JMP | EBPF_JSLE | BPF_X)] = {
171899a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
171999a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
172099a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
172199a2dd95SBruce Richardson .eval = eval_jcc,
172299a2dd95SBruce Richardson },
172399a2dd95SBruce Richardson [(BPF_JMP | BPF_JSET | BPF_X)] = {
172499a2dd95SBruce Richardson .mask = { .dreg = ALL_REGS, .sreg = ALL_REGS},
172599a2dd95SBruce Richardson .off = { .min = 0, .max = UINT16_MAX},
172699a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
172799a2dd95SBruce Richardson .eval = eval_jcc,
172899a2dd95SBruce Richardson },
172999a2dd95SBruce Richardson /* call instruction */
173099a2dd95SBruce Richardson [(BPF_JMP | EBPF_CALL)] = {
173199a2dd95SBruce Richardson .mask = { .dreg = ZERO_REG, .sreg = ZERO_REG},
173299a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
173399a2dd95SBruce Richardson .imm = { .min = 0, .max = UINT32_MAX},
173499a2dd95SBruce Richardson .eval = eval_call,
173599a2dd95SBruce Richardson },
173699a2dd95SBruce Richardson /* ret instruction */
173799a2dd95SBruce Richardson [(BPF_JMP | EBPF_EXIT)] = {
173899a2dd95SBruce Richardson .mask = { .dreg = ZERO_REG, .sreg = ZERO_REG},
173999a2dd95SBruce Richardson .off = { .min = 0, .max = 0},
174099a2dd95SBruce Richardson .imm = { .min = 0, .max = 0},
174199a2dd95SBruce Richardson .eval = eval_exit,
174299a2dd95SBruce Richardson },
174399a2dd95SBruce Richardson };
174499a2dd95SBruce Richardson
174599a2dd95SBruce Richardson /*
174699a2dd95SBruce Richardson * make sure that instruction syntax is valid,
17474a6672c2SStephen Hemminger * and its fields don't violate particular instruction type restrictions.
174899a2dd95SBruce Richardson */
174999a2dd95SBruce Richardson static const char *
check_syntax(const struct ebpf_insn * ins)175099a2dd95SBruce Richardson check_syntax(const struct ebpf_insn *ins)
175199a2dd95SBruce Richardson {
175299a2dd95SBruce Richardson
175399a2dd95SBruce Richardson uint8_t op;
175499a2dd95SBruce Richardson uint16_t off;
175599a2dd95SBruce Richardson uint32_t imm;
175699a2dd95SBruce Richardson
175799a2dd95SBruce Richardson op = ins->code;
175899a2dd95SBruce Richardson
175999a2dd95SBruce Richardson if (ins_chk[op].mask.dreg == 0)
176099a2dd95SBruce Richardson return "invalid opcode";
176199a2dd95SBruce Richardson
176299a2dd95SBruce Richardson if ((ins_chk[op].mask.dreg & 1 << ins->dst_reg) == 0)
176399a2dd95SBruce Richardson return "invalid dst-reg field";
176499a2dd95SBruce Richardson
176599a2dd95SBruce Richardson if ((ins_chk[op].mask.sreg & 1 << ins->src_reg) == 0)
176699a2dd95SBruce Richardson return "invalid src-reg field";
176799a2dd95SBruce Richardson
176899a2dd95SBruce Richardson off = ins->off;
176999a2dd95SBruce Richardson if (ins_chk[op].off.min > off || ins_chk[op].off.max < off)
177099a2dd95SBruce Richardson return "invalid off field";
177199a2dd95SBruce Richardson
177299a2dd95SBruce Richardson imm = ins->imm;
177399a2dd95SBruce Richardson if (ins_chk[op].imm.min > imm || ins_chk[op].imm.max < imm)
177499a2dd95SBruce Richardson return "invalid imm field";
177599a2dd95SBruce Richardson
177699a2dd95SBruce Richardson if (ins_chk[op].check != NULL)
177799a2dd95SBruce Richardson return ins_chk[op].check(ins);
177899a2dd95SBruce Richardson
177999a2dd95SBruce Richardson return NULL;
178099a2dd95SBruce Richardson }
178199a2dd95SBruce Richardson
178299a2dd95SBruce Richardson /*
178399a2dd95SBruce Richardson * helper function, return instruction index for the given node.
178499a2dd95SBruce Richardson */
178599a2dd95SBruce Richardson static uint32_t
get_node_idx(const struct bpf_verifier * bvf,const struct inst_node * node)178699a2dd95SBruce Richardson get_node_idx(const struct bpf_verifier *bvf, const struct inst_node *node)
178799a2dd95SBruce Richardson {
178899a2dd95SBruce Richardson return node - bvf->in;
178999a2dd95SBruce Richardson }
179099a2dd95SBruce Richardson
179199a2dd95SBruce Richardson /*
179299a2dd95SBruce Richardson * helper function, used to walk through constructed CFG.
179399a2dd95SBruce Richardson */
179499a2dd95SBruce Richardson static struct inst_node *
get_next_node(struct bpf_verifier * bvf,struct inst_node * node)179599a2dd95SBruce Richardson get_next_node(struct bpf_verifier *bvf, struct inst_node *node)
179699a2dd95SBruce Richardson {
179799a2dd95SBruce Richardson uint32_t ce, ne, dst;
179899a2dd95SBruce Richardson
179999a2dd95SBruce Richardson ne = node->nb_edge;
180099a2dd95SBruce Richardson ce = node->cur_edge;
180199a2dd95SBruce Richardson if (ce == ne)
180299a2dd95SBruce Richardson return NULL;
180399a2dd95SBruce Richardson
180499a2dd95SBruce Richardson node->cur_edge++;
180599a2dd95SBruce Richardson dst = node->edge_dest[ce];
180699a2dd95SBruce Richardson return bvf->in + dst;
180799a2dd95SBruce Richardson }
180899a2dd95SBruce Richardson
180999a2dd95SBruce Richardson static void
set_node_colour(struct bpf_verifier * bvf,struct inst_node * node,uint32_t new)181099a2dd95SBruce Richardson set_node_colour(struct bpf_verifier *bvf, struct inst_node *node,
181199a2dd95SBruce Richardson uint32_t new)
181299a2dd95SBruce Richardson {
181399a2dd95SBruce Richardson uint32_t prev;
181499a2dd95SBruce Richardson
181599a2dd95SBruce Richardson prev = node->colour;
181699a2dd95SBruce Richardson node->colour = new;
181799a2dd95SBruce Richardson
181899a2dd95SBruce Richardson bvf->node_colour[prev]--;
181999a2dd95SBruce Richardson bvf->node_colour[new]++;
182099a2dd95SBruce Richardson }
182199a2dd95SBruce Richardson
182299a2dd95SBruce Richardson /*
182399a2dd95SBruce Richardson * helper function, add new edge between two nodes.
182499a2dd95SBruce Richardson */
182599a2dd95SBruce Richardson static int
add_edge(struct bpf_verifier * bvf,struct inst_node * node,uint32_t nidx)182699a2dd95SBruce Richardson add_edge(struct bpf_verifier *bvf, struct inst_node *node, uint32_t nidx)
182799a2dd95SBruce Richardson {
182899a2dd95SBruce Richardson uint32_t ne;
182999a2dd95SBruce Richardson
183099a2dd95SBruce Richardson if (nidx > bvf->prm->nb_ins) {
1831*a258eebdSKonstantin Ananyev RTE_BPF_LOG_LINE(ERR,
1832*a258eebdSKonstantin Ananyev "%s: program boundary violation at pc: %u, next pc: %u",
183399a2dd95SBruce Richardson __func__, get_node_idx(bvf, node), nidx);
183499a2dd95SBruce Richardson return -EINVAL;
183599a2dd95SBruce Richardson }
183699a2dd95SBruce Richardson
183799a2dd95SBruce Richardson ne = node->nb_edge;
183899a2dd95SBruce Richardson if (ne >= RTE_DIM(node->edge_dest)) {
18390e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s: internal error at pc: %u",
184099a2dd95SBruce Richardson __func__, get_node_idx(bvf, node));
184199a2dd95SBruce Richardson return -EINVAL;
184299a2dd95SBruce Richardson }
184399a2dd95SBruce Richardson
184499a2dd95SBruce Richardson node->edge_dest[ne] = nidx;
184599a2dd95SBruce Richardson node->nb_edge = ne + 1;
184699a2dd95SBruce Richardson return 0;
184799a2dd95SBruce Richardson }
184899a2dd95SBruce Richardson
184999a2dd95SBruce Richardson /*
185099a2dd95SBruce Richardson * helper function, determine type of edge between two nodes.
185199a2dd95SBruce Richardson */
185299a2dd95SBruce Richardson static void
set_edge_type(struct bpf_verifier * bvf,struct inst_node * node,const struct inst_node * next)185399a2dd95SBruce Richardson set_edge_type(struct bpf_verifier *bvf, struct inst_node *node,
185499a2dd95SBruce Richardson const struct inst_node *next)
185599a2dd95SBruce Richardson {
185699a2dd95SBruce Richardson uint32_t ce, clr, type;
185799a2dd95SBruce Richardson
185899a2dd95SBruce Richardson ce = node->cur_edge - 1;
185999a2dd95SBruce Richardson clr = next->colour;
186099a2dd95SBruce Richardson
186199a2dd95SBruce Richardson type = UNKNOWN_EDGE;
186299a2dd95SBruce Richardson
186399a2dd95SBruce Richardson if (clr == WHITE)
186499a2dd95SBruce Richardson type = TREE_EDGE;
186599a2dd95SBruce Richardson else if (clr == GREY)
186699a2dd95SBruce Richardson type = BACK_EDGE;
186799a2dd95SBruce Richardson else if (clr == BLACK)
186899a2dd95SBruce Richardson /*
186999a2dd95SBruce Richardson * in fact it could be either direct or cross edge,
187099a2dd95SBruce Richardson * but for now, we don't need to distinguish between them.
187199a2dd95SBruce Richardson */
187299a2dd95SBruce Richardson type = CROSS_EDGE;
187399a2dd95SBruce Richardson
187499a2dd95SBruce Richardson node->edge_type[ce] = type;
187599a2dd95SBruce Richardson bvf->edge_type[type]++;
187699a2dd95SBruce Richardson }
187799a2dd95SBruce Richardson
187899a2dd95SBruce Richardson static struct inst_node *
get_prev_node(struct bpf_verifier * bvf,struct inst_node * node)187999a2dd95SBruce Richardson get_prev_node(struct bpf_verifier *bvf, struct inst_node *node)
188099a2dd95SBruce Richardson {
188199a2dd95SBruce Richardson return bvf->in + node->prev_node;
188299a2dd95SBruce Richardson }
188399a2dd95SBruce Richardson
188499a2dd95SBruce Richardson /*
188599a2dd95SBruce Richardson * Depth-First Search (DFS) through previously constructed
188699a2dd95SBruce Richardson * Control Flow Graph (CFG).
188799a2dd95SBruce Richardson * Information collected at this path would be used later
188899a2dd95SBruce Richardson * to determine is there any loops, and/or unreachable instructions.
188999a2dd95SBruce Richardson */
189099a2dd95SBruce Richardson static void
dfs(struct bpf_verifier * bvf)189199a2dd95SBruce Richardson dfs(struct bpf_verifier *bvf)
189299a2dd95SBruce Richardson {
189399a2dd95SBruce Richardson struct inst_node *next, *node;
189499a2dd95SBruce Richardson
189599a2dd95SBruce Richardson node = bvf->in;
189699a2dd95SBruce Richardson while (node != NULL) {
189799a2dd95SBruce Richardson
189899a2dd95SBruce Richardson if (node->colour == WHITE)
189999a2dd95SBruce Richardson set_node_colour(bvf, node, GREY);
190099a2dd95SBruce Richardson
190199a2dd95SBruce Richardson if (node->colour == GREY) {
190299a2dd95SBruce Richardson
190399a2dd95SBruce Richardson /* find next unprocessed child node */
190499a2dd95SBruce Richardson do {
190599a2dd95SBruce Richardson next = get_next_node(bvf, node);
190699a2dd95SBruce Richardson if (next == NULL)
190799a2dd95SBruce Richardson break;
190899a2dd95SBruce Richardson set_edge_type(bvf, node, next);
190999a2dd95SBruce Richardson } while (next->colour != WHITE);
191099a2dd95SBruce Richardson
191199a2dd95SBruce Richardson if (next != NULL) {
191299a2dd95SBruce Richardson /* proceed with next child */
191399a2dd95SBruce Richardson next->prev_node = get_node_idx(bvf, node);
191499a2dd95SBruce Richardson node = next;
191599a2dd95SBruce Richardson } else {
191699a2dd95SBruce Richardson /*
191799a2dd95SBruce Richardson * finished with current node and all it's kids,
191899a2dd95SBruce Richardson * proceed with parent
191999a2dd95SBruce Richardson */
192099a2dd95SBruce Richardson set_node_colour(bvf, node, BLACK);
192199a2dd95SBruce Richardson node->cur_edge = 0;
192299a2dd95SBruce Richardson node = get_prev_node(bvf, node);
192399a2dd95SBruce Richardson }
192499a2dd95SBruce Richardson } else
192599a2dd95SBruce Richardson node = NULL;
192699a2dd95SBruce Richardson }
192799a2dd95SBruce Richardson }
192899a2dd95SBruce Richardson
192999a2dd95SBruce Richardson /*
193099a2dd95SBruce Richardson * report unreachable instructions.
193199a2dd95SBruce Richardson */
193299a2dd95SBruce Richardson static void
log_unreachable(const struct bpf_verifier * bvf)193399a2dd95SBruce Richardson log_unreachable(const struct bpf_verifier *bvf)
193499a2dd95SBruce Richardson {
193599a2dd95SBruce Richardson uint32_t i;
193699a2dd95SBruce Richardson struct inst_node *node;
193799a2dd95SBruce Richardson const struct ebpf_insn *ins;
193899a2dd95SBruce Richardson
193999a2dd95SBruce Richardson for (i = 0; i != bvf->prm->nb_ins; i++) {
194099a2dd95SBruce Richardson
194199a2dd95SBruce Richardson node = bvf->in + i;
194299a2dd95SBruce Richardson ins = bvf->prm->ins + i;
194399a2dd95SBruce Richardson
194499a2dd95SBruce Richardson if (node->colour == WHITE &&
194599a2dd95SBruce Richardson ins->code != (BPF_LD | BPF_IMM | EBPF_DW))
19460e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "unreachable code at pc: %u;", i);
194799a2dd95SBruce Richardson }
194899a2dd95SBruce Richardson }
194999a2dd95SBruce Richardson
195099a2dd95SBruce Richardson /*
195199a2dd95SBruce Richardson * report loops detected.
195299a2dd95SBruce Richardson */
195399a2dd95SBruce Richardson static void
log_loop(const struct bpf_verifier * bvf)195499a2dd95SBruce Richardson log_loop(const struct bpf_verifier *bvf)
195599a2dd95SBruce Richardson {
195699a2dd95SBruce Richardson uint32_t i, j;
195799a2dd95SBruce Richardson struct inst_node *node;
195899a2dd95SBruce Richardson
195999a2dd95SBruce Richardson for (i = 0; i != bvf->prm->nb_ins; i++) {
196099a2dd95SBruce Richardson
196199a2dd95SBruce Richardson node = bvf->in + i;
196299a2dd95SBruce Richardson if (node->colour != BLACK)
196399a2dd95SBruce Richardson continue;
196499a2dd95SBruce Richardson
196599a2dd95SBruce Richardson for (j = 0; j != node->nb_edge; j++) {
196699a2dd95SBruce Richardson if (node->edge_type[j] == BACK_EDGE)
19670e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR,
19680e21c7c0SDavid Marchand "loop at pc:%u --> pc:%u;",
196999a2dd95SBruce Richardson i, node->edge_dest[j]);
197099a2dd95SBruce Richardson }
197199a2dd95SBruce Richardson }
197299a2dd95SBruce Richardson }
197399a2dd95SBruce Richardson
197499a2dd95SBruce Richardson /*
197599a2dd95SBruce Richardson * First pass goes though all instructions in the set, checks that each
197699a2dd95SBruce Richardson * instruction is a valid one (correct syntax, valid field values, etc.)
197799a2dd95SBruce Richardson * and constructs control flow graph (CFG).
19784a6672c2SStephen Hemminger * Then depth-first search is performed over the constructed graph.
197999a2dd95SBruce Richardson * Programs with unreachable instructions and/or loops will be rejected.
198099a2dd95SBruce Richardson */
198199a2dd95SBruce Richardson static int
validate(struct bpf_verifier * bvf)198299a2dd95SBruce Richardson validate(struct bpf_verifier *bvf)
198399a2dd95SBruce Richardson {
198499a2dd95SBruce Richardson int32_t rc;
198599a2dd95SBruce Richardson uint32_t i;
198699a2dd95SBruce Richardson struct inst_node *node;
198799a2dd95SBruce Richardson const struct ebpf_insn *ins;
198899a2dd95SBruce Richardson const char *err;
198999a2dd95SBruce Richardson
199099a2dd95SBruce Richardson rc = 0;
199199a2dd95SBruce Richardson for (i = 0; i < bvf->prm->nb_ins; i++) {
199299a2dd95SBruce Richardson
199399a2dd95SBruce Richardson ins = bvf->prm->ins + i;
199499a2dd95SBruce Richardson node = bvf->in + i;
199599a2dd95SBruce Richardson
199699a2dd95SBruce Richardson err = check_syntax(ins);
199799a2dd95SBruce Richardson if (err != 0) {
19980e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s: %s at pc: %u",
199999a2dd95SBruce Richardson __func__, err, i);
200099a2dd95SBruce Richardson rc |= -EINVAL;
200199a2dd95SBruce Richardson }
200299a2dd95SBruce Richardson
200399a2dd95SBruce Richardson /*
200499a2dd95SBruce Richardson * construct CFG, jcc nodes have to outgoing edges,
20054a6672c2SStephen Hemminger * 'exit' nodes - none, all other nodes have exactly one
200699a2dd95SBruce Richardson * outgoing edge.
200799a2dd95SBruce Richardson */
200899a2dd95SBruce Richardson switch (ins->code) {
200999a2dd95SBruce Richardson case (BPF_JMP | EBPF_EXIT):
201099a2dd95SBruce Richardson break;
201199a2dd95SBruce Richardson case (BPF_JMP | BPF_JEQ | BPF_K):
201299a2dd95SBruce Richardson case (BPF_JMP | EBPF_JNE | BPF_K):
201399a2dd95SBruce Richardson case (BPF_JMP | BPF_JGT | BPF_K):
201499a2dd95SBruce Richardson case (BPF_JMP | EBPF_JLT | BPF_K):
201599a2dd95SBruce Richardson case (BPF_JMP | BPF_JGE | BPF_K):
201699a2dd95SBruce Richardson case (BPF_JMP | EBPF_JLE | BPF_K):
201799a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSGT | BPF_K):
201899a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSLT | BPF_K):
201999a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSGE | BPF_K):
202099a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSLE | BPF_K):
202199a2dd95SBruce Richardson case (BPF_JMP | BPF_JSET | BPF_K):
202299a2dd95SBruce Richardson case (BPF_JMP | BPF_JEQ | BPF_X):
202399a2dd95SBruce Richardson case (BPF_JMP | EBPF_JNE | BPF_X):
202499a2dd95SBruce Richardson case (BPF_JMP | BPF_JGT | BPF_X):
202599a2dd95SBruce Richardson case (BPF_JMP | EBPF_JLT | BPF_X):
202699a2dd95SBruce Richardson case (BPF_JMP | BPF_JGE | BPF_X):
202799a2dd95SBruce Richardson case (BPF_JMP | EBPF_JLE | BPF_X):
202899a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSGT | BPF_X):
202999a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSLT | BPF_X):
203099a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSGE | BPF_X):
203199a2dd95SBruce Richardson case (BPF_JMP | EBPF_JSLE | BPF_X):
203299a2dd95SBruce Richardson case (BPF_JMP | BPF_JSET | BPF_X):
203399a2dd95SBruce Richardson rc |= add_edge(bvf, node, i + ins->off + 1);
203499a2dd95SBruce Richardson rc |= add_edge(bvf, node, i + 1);
203599a2dd95SBruce Richardson bvf->nb_jcc_nodes++;
203699a2dd95SBruce Richardson break;
203799a2dd95SBruce Richardson case (BPF_JMP | BPF_JA):
203899a2dd95SBruce Richardson rc |= add_edge(bvf, node, i + ins->off + 1);
203999a2dd95SBruce Richardson break;
204099a2dd95SBruce Richardson /* load 64 bit immediate value */
204199a2dd95SBruce Richardson case (BPF_LD | BPF_IMM | EBPF_DW):
204299a2dd95SBruce Richardson rc |= add_edge(bvf, node, i + 2);
204399a2dd95SBruce Richardson i++;
204499a2dd95SBruce Richardson break;
204599a2dd95SBruce Richardson case (BPF_LD | BPF_ABS | BPF_B):
204699a2dd95SBruce Richardson case (BPF_LD | BPF_ABS | BPF_H):
204799a2dd95SBruce Richardson case (BPF_LD | BPF_ABS | BPF_W):
204899a2dd95SBruce Richardson case (BPF_LD | BPF_IND | BPF_B):
204999a2dd95SBruce Richardson case (BPF_LD | BPF_IND | BPF_H):
205099a2dd95SBruce Richardson case (BPF_LD | BPF_IND | BPF_W):
205199a2dd95SBruce Richardson bvf->nb_ldmb_nodes++;
205299a2dd95SBruce Richardson /* fallthrough */
205399a2dd95SBruce Richardson default:
205499a2dd95SBruce Richardson rc |= add_edge(bvf, node, i + 1);
205599a2dd95SBruce Richardson break;
205699a2dd95SBruce Richardson }
205799a2dd95SBruce Richardson
205899a2dd95SBruce Richardson bvf->nb_nodes++;
205999a2dd95SBruce Richardson bvf->node_colour[WHITE]++;
206099a2dd95SBruce Richardson }
206199a2dd95SBruce Richardson
206299a2dd95SBruce Richardson if (rc != 0)
206399a2dd95SBruce Richardson return rc;
206499a2dd95SBruce Richardson
206599a2dd95SBruce Richardson dfs(bvf);
206699a2dd95SBruce Richardson
20670e21c7c0SDavid Marchand RTE_LOG(DEBUG, BPF, "%s(%p) stats:\n"
206899a2dd95SBruce Richardson "nb_nodes=%u;\n"
206999a2dd95SBruce Richardson "nb_jcc_nodes=%u;\n"
207099a2dd95SBruce Richardson "node_color={[WHITE]=%u, [GREY]=%u,, [BLACK]=%u};\n"
207199a2dd95SBruce Richardson "edge_type={[UNKNOWN]=%u, [TREE]=%u, [BACK]=%u, [CROSS]=%u};\n",
207299a2dd95SBruce Richardson __func__, bvf,
207399a2dd95SBruce Richardson bvf->nb_nodes,
207499a2dd95SBruce Richardson bvf->nb_jcc_nodes,
207599a2dd95SBruce Richardson bvf->node_colour[WHITE], bvf->node_colour[GREY],
207699a2dd95SBruce Richardson bvf->node_colour[BLACK],
207799a2dd95SBruce Richardson bvf->edge_type[UNKNOWN_EDGE], bvf->edge_type[TREE_EDGE],
207899a2dd95SBruce Richardson bvf->edge_type[BACK_EDGE], bvf->edge_type[CROSS_EDGE]);
207999a2dd95SBruce Richardson
208099a2dd95SBruce Richardson if (bvf->node_colour[BLACK] != bvf->nb_nodes) {
20810e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(%p) unreachable instructions;",
208299a2dd95SBruce Richardson __func__, bvf);
208399a2dd95SBruce Richardson log_unreachable(bvf);
208499a2dd95SBruce Richardson return -EINVAL;
208599a2dd95SBruce Richardson }
208699a2dd95SBruce Richardson
208799a2dd95SBruce Richardson if (bvf->node_colour[GREY] != 0 || bvf->node_colour[WHITE] != 0 ||
208899a2dd95SBruce Richardson bvf->edge_type[UNKNOWN_EDGE] != 0) {
20890e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(%p) DFS internal error;",
209099a2dd95SBruce Richardson __func__, bvf);
209199a2dd95SBruce Richardson return -EINVAL;
209299a2dd95SBruce Richardson }
209399a2dd95SBruce Richardson
209499a2dd95SBruce Richardson if (bvf->edge_type[BACK_EDGE] != 0) {
20950e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s(%p) loops detected;",
209699a2dd95SBruce Richardson __func__, bvf);
209799a2dd95SBruce Richardson log_loop(bvf);
209899a2dd95SBruce Richardson return -EINVAL;
209999a2dd95SBruce Richardson }
210099a2dd95SBruce Richardson
210199a2dd95SBruce Richardson return 0;
210299a2dd95SBruce Richardson }
210399a2dd95SBruce Richardson
210499a2dd95SBruce Richardson /*
210599a2dd95SBruce Richardson * helper functions get/free eval states.
210699a2dd95SBruce Richardson */
210799a2dd95SBruce Richardson static struct bpf_eval_state *
pull_eval_state(struct evst_pool * pool)2108*a258eebdSKonstantin Ananyev pull_eval_state(struct evst_pool *pool)
210999a2dd95SBruce Richardson {
211099a2dd95SBruce Richardson uint32_t n;
211199a2dd95SBruce Richardson
2112*a258eebdSKonstantin Ananyev n = pool->cur;
2113*a258eebdSKonstantin Ananyev if (n == pool->num)
211499a2dd95SBruce Richardson return NULL;
211599a2dd95SBruce Richardson
2116*a258eebdSKonstantin Ananyev pool->cur = n + 1;
2117*a258eebdSKonstantin Ananyev return pool->ent + n;
211899a2dd95SBruce Richardson }
211999a2dd95SBruce Richardson
212099a2dd95SBruce Richardson static void
push_eval_state(struct evst_pool * pool)2121*a258eebdSKonstantin Ananyev push_eval_state(struct evst_pool *pool)
212299a2dd95SBruce Richardson {
2123*a258eebdSKonstantin Ananyev RTE_ASSERT(pool->cur != 0);
2124*a258eebdSKonstantin Ananyev pool->cur--;
212599a2dd95SBruce Richardson }
212699a2dd95SBruce Richardson
212799a2dd95SBruce Richardson static void
evst_pool_fini(struct bpf_verifier * bvf)212899a2dd95SBruce Richardson evst_pool_fini(struct bpf_verifier *bvf)
212999a2dd95SBruce Richardson {
213099a2dd95SBruce Richardson bvf->evst = NULL;
2131*a258eebdSKonstantin Ananyev free(bvf->evst_sr_pool.ent);
2132*a258eebdSKonstantin Ananyev memset(&bvf->evst_sr_pool, 0, sizeof(bvf->evst_sr_pool));
2133*a258eebdSKonstantin Ananyev memset(&bvf->evst_tp_pool, 0, sizeof(bvf->evst_tp_pool));
213499a2dd95SBruce Richardson }
213599a2dd95SBruce Richardson
213699a2dd95SBruce Richardson static int
evst_pool_init(struct bpf_verifier * bvf)213799a2dd95SBruce Richardson evst_pool_init(struct bpf_verifier *bvf)
213899a2dd95SBruce Richardson {
2139*a258eebdSKonstantin Ananyev uint32_t k, n;
214099a2dd95SBruce Richardson
2141*a258eebdSKonstantin Ananyev /*
2142*a258eebdSKonstantin Ananyev * We need nb_jcc_nodes + 1 for save_cur/restore_cur
2143*a258eebdSKonstantin Ananyev * remaining ones will be used for state tracking/pruning.
2144*a258eebdSKonstantin Ananyev */
2145*a258eebdSKonstantin Ananyev k = bvf->nb_jcc_nodes + 1;
2146*a258eebdSKonstantin Ananyev n = k * 3;
214799a2dd95SBruce Richardson
2148*a258eebdSKonstantin Ananyev bvf->evst_sr_pool.ent = calloc(n, sizeof(bvf->evst_sr_pool.ent[0]));
2149*a258eebdSKonstantin Ananyev if (bvf->evst_sr_pool.ent == NULL)
215099a2dd95SBruce Richardson return -ENOMEM;
215199a2dd95SBruce Richardson
2152*a258eebdSKonstantin Ananyev bvf->evst_sr_pool.num = k;
2153*a258eebdSKonstantin Ananyev bvf->evst_sr_pool.cur = 0;
215499a2dd95SBruce Richardson
2155*a258eebdSKonstantin Ananyev bvf->evst_tp_pool.ent = bvf->evst_sr_pool.ent + k;
2156*a258eebdSKonstantin Ananyev bvf->evst_tp_pool.num = n - k;
2157*a258eebdSKonstantin Ananyev bvf->evst_tp_pool.cur = 0;
2158*a258eebdSKonstantin Ananyev
2159*a258eebdSKonstantin Ananyev bvf->evst = pull_eval_state(&bvf->evst_sr_pool);
216099a2dd95SBruce Richardson return 0;
216199a2dd95SBruce Richardson }
216299a2dd95SBruce Richardson
216399a2dd95SBruce Richardson /*
2164*a258eebdSKonstantin Ananyev * try to allocate and initialise new eval state for given node.
2165*a258eebdSKonstantin Ananyev * later if no errors will be encountered, this state will be accepted as
2166*a258eebdSKonstantin Ananyev * one of the possible 'safe' states for that node.
2167*a258eebdSKonstantin Ananyev */
2168*a258eebdSKonstantin Ananyev static void
save_start_eval_state(struct bpf_verifier * bvf,struct inst_node * node)2169*a258eebdSKonstantin Ananyev save_start_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
2170*a258eebdSKonstantin Ananyev {
2171*a258eebdSKonstantin Ananyev RTE_ASSERT(node->evst.start == NULL);
2172*a258eebdSKonstantin Ananyev
2173*a258eebdSKonstantin Ananyev /* limit number of states for one node with some reasonable value */
2174*a258eebdSKonstantin Ananyev if (node->evst.nb_safe >= NODE_EVST_MAX)
2175*a258eebdSKonstantin Ananyev return;
2176*a258eebdSKonstantin Ananyev
2177*a258eebdSKonstantin Ananyev /* try to get new eval_state */
2178*a258eebdSKonstantin Ananyev node->evst.start = pull_eval_state(&bvf->evst_tp_pool);
2179*a258eebdSKonstantin Ananyev
2180*a258eebdSKonstantin Ananyev /* make a copy of current state */
2181*a258eebdSKonstantin Ananyev if (node->evst.start != NULL) {
2182*a258eebdSKonstantin Ananyev memcpy(node->evst.start, bvf->evst, sizeof(*node->evst.start));
2183*a258eebdSKonstantin Ananyev SLIST_NEXT(node->evst.start, next) = NULL;
2184*a258eebdSKonstantin Ananyev }
2185*a258eebdSKonstantin Ananyev }
2186*a258eebdSKonstantin Ananyev
2187*a258eebdSKonstantin Ananyev /*
2188*a258eebdSKonstantin Ananyev * add @start state to the list of @safe states.
2189*a258eebdSKonstantin Ananyev */
2190*a258eebdSKonstantin Ananyev static void
save_safe_eval_state(struct bpf_verifier * bvf,struct inst_node * node)2191*a258eebdSKonstantin Ananyev save_safe_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
2192*a258eebdSKonstantin Ananyev {
2193*a258eebdSKonstantin Ananyev if (node->evst.start == NULL)
2194*a258eebdSKonstantin Ananyev return;
2195*a258eebdSKonstantin Ananyev
2196*a258eebdSKonstantin Ananyev SLIST_INSERT_HEAD(&node->evst.safe, node->evst.start, next);
2197*a258eebdSKonstantin Ananyev node->evst.nb_safe++;
2198*a258eebdSKonstantin Ananyev
2199*a258eebdSKonstantin Ananyev RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u,state=%p): nb_safe=%u;",
2200*a258eebdSKonstantin Ananyev __func__, bvf, get_node_idx(bvf, node), node->evst.start,
2201*a258eebdSKonstantin Ananyev node->evst.nb_safe);
2202*a258eebdSKonstantin Ananyev
2203*a258eebdSKonstantin Ananyev node->evst.start = NULL;
2204*a258eebdSKonstantin Ananyev }
2205*a258eebdSKonstantin Ananyev
2206*a258eebdSKonstantin Ananyev /*
220799a2dd95SBruce Richardson * Save current eval state.
220899a2dd95SBruce Richardson */
220999a2dd95SBruce Richardson static int
save_cur_eval_state(struct bpf_verifier * bvf,struct inst_node * node)2210*a258eebdSKonstantin Ananyev save_cur_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
221199a2dd95SBruce Richardson {
221299a2dd95SBruce Richardson struct bpf_eval_state *st;
221399a2dd95SBruce Richardson
221499a2dd95SBruce Richardson /* get new eval_state for this node */
2215*a258eebdSKonstantin Ananyev st = pull_eval_state(&bvf->evst_sr_pool);
221699a2dd95SBruce Richardson if (st == NULL) {
22170e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR,
22180e21c7c0SDavid Marchand "%s: internal error (out of space) at pc: %u",
221999a2dd95SBruce Richardson __func__, get_node_idx(bvf, node));
222099a2dd95SBruce Richardson return -ENOMEM;
222199a2dd95SBruce Richardson }
222299a2dd95SBruce Richardson
222399a2dd95SBruce Richardson /* make a copy of current state */
222499a2dd95SBruce Richardson memcpy(st, bvf->evst, sizeof(*st));
222599a2dd95SBruce Richardson
222699a2dd95SBruce Richardson /* swap current state with new one */
2227*a258eebdSKonstantin Ananyev RTE_ASSERT(node->evst.cur == NULL);
2228*a258eebdSKonstantin Ananyev node->evst.cur = bvf->evst;
222999a2dd95SBruce Richardson bvf->evst = st;
223099a2dd95SBruce Richardson
22310e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u) old/new states: %p/%p;",
2232*a258eebdSKonstantin Ananyev __func__, bvf, get_node_idx(bvf, node), node->evst.cur,
2233*a258eebdSKonstantin Ananyev bvf->evst);
223499a2dd95SBruce Richardson
223599a2dd95SBruce Richardson return 0;
223699a2dd95SBruce Richardson }
223799a2dd95SBruce Richardson
223899a2dd95SBruce Richardson /*
223999a2dd95SBruce Richardson * Restore previous eval state and mark current eval state as free.
224099a2dd95SBruce Richardson */
224199a2dd95SBruce Richardson static void
restore_cur_eval_state(struct bpf_verifier * bvf,struct inst_node * node)2242*a258eebdSKonstantin Ananyev restore_cur_eval_state(struct bpf_verifier *bvf, struct inst_node *node)
224399a2dd95SBruce Richardson {
22440e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u) old/new states: %p/%p;",
2245*a258eebdSKonstantin Ananyev __func__, bvf, get_node_idx(bvf, node), bvf->evst,
2246*a258eebdSKonstantin Ananyev node->evst.cur);
224799a2dd95SBruce Richardson
2248*a258eebdSKonstantin Ananyev bvf->evst = node->evst.cur;
2249*a258eebdSKonstantin Ananyev node->evst.cur = NULL;
2250*a258eebdSKonstantin Ananyev push_eval_state(&bvf->evst_sr_pool);
225199a2dd95SBruce Richardson }
225299a2dd95SBruce Richardson
225399a2dd95SBruce Richardson static void
log_dbg_eval_state(const struct bpf_verifier * bvf,const struct ebpf_insn * ins,uint32_t pc)2254df82b12bSDavid Marchand log_dbg_eval_state(const struct bpf_verifier *bvf, const struct ebpf_insn *ins,
2255df82b12bSDavid Marchand uint32_t pc)
225699a2dd95SBruce Richardson {
225799a2dd95SBruce Richardson const struct bpf_eval_state *st;
225899a2dd95SBruce Richardson const struct bpf_reg_val *rv;
225999a2dd95SBruce Richardson
22600e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(DEBUG, "%s(pc=%u):", __func__, pc);
226199a2dd95SBruce Richardson
226299a2dd95SBruce Richardson st = bvf->evst;
226399a2dd95SBruce Richardson rv = st->rv + ins->dst_reg;
226499a2dd95SBruce Richardson
22650e21c7c0SDavid Marchand RTE_LOG(DEBUG, BPF,
226699a2dd95SBruce Richardson "r%u={\n"
2267*a258eebdSKonstantin Ananyev "\tv={type=%u, size=%zu, buf_size=%zu},\n"
226899a2dd95SBruce Richardson "\tmask=0x%" PRIx64 ",\n"
226999a2dd95SBruce Richardson "\tu={min=0x%" PRIx64 ", max=0x%" PRIx64 "},\n"
227099a2dd95SBruce Richardson "\ts={min=%" PRId64 ", max=%" PRId64 "},\n"
227199a2dd95SBruce Richardson "};\n",
227299a2dd95SBruce Richardson ins->dst_reg,
2273*a258eebdSKonstantin Ananyev rv->v.type, rv->v.size, rv->v.buf_size,
227499a2dd95SBruce Richardson rv->mask,
227599a2dd95SBruce Richardson rv->u.min, rv->u.max,
227699a2dd95SBruce Richardson rv->s.min, rv->s.max);
227799a2dd95SBruce Richardson }
227899a2dd95SBruce Richardson
227999a2dd95SBruce Richardson /*
2280*a258eebdSKonstantin Ananyev * compare two evaluation states.
2281*a258eebdSKonstantin Ananyev * returns zero if @lv is more conservative (safer) then @rv.
2282*a258eebdSKonstantin Ananyev * returns non-zero value otherwise.
2283*a258eebdSKonstantin Ananyev */
2284*a258eebdSKonstantin Ananyev static int
cmp_reg_val_within(const struct bpf_reg_val * lv,const struct bpf_reg_val * rv)2285*a258eebdSKonstantin Ananyev cmp_reg_val_within(const struct bpf_reg_val *lv, const struct bpf_reg_val *rv)
2286*a258eebdSKonstantin Ananyev {
2287*a258eebdSKonstantin Ananyev /* expect @v and @mask to be identical */
2288*a258eebdSKonstantin Ananyev if (memcmp(&lv->v, &rv->v, sizeof(lv->v)) != 0 || lv->mask != rv->mask)
2289*a258eebdSKonstantin Ananyev return -1;
2290*a258eebdSKonstantin Ananyev
2291*a258eebdSKonstantin Ananyev /* exact match only for mbuf and stack pointers */
2292*a258eebdSKonstantin Ananyev if (lv->v.type == RTE_BPF_ARG_PTR_MBUF ||
2293*a258eebdSKonstantin Ananyev lv->v.type == BPF_ARG_PTR_STACK)
2294*a258eebdSKonstantin Ananyev return -1;
2295*a258eebdSKonstantin Ananyev
2296*a258eebdSKonstantin Ananyev if (lv->u.min <= rv->u.min && lv->u.max >= rv->u.max &&
2297*a258eebdSKonstantin Ananyev lv->s.min <= rv->s.min && lv->s.max >= rv->s.max)
2298*a258eebdSKonstantin Ananyev return 0;
2299*a258eebdSKonstantin Ananyev
2300*a258eebdSKonstantin Ananyev return -1;
2301*a258eebdSKonstantin Ananyev }
2302*a258eebdSKonstantin Ananyev
2303*a258eebdSKonstantin Ananyev /*
2304*a258eebdSKonstantin Ananyev * compare two evaluation states.
2305*a258eebdSKonstantin Ananyev * returns zero if they are identical.
2306*a258eebdSKonstantin Ananyev * returns positive value if @lv is more conservative (safer) then @rv.
2307*a258eebdSKonstantin Ananyev * returns negative value otherwise.
2308*a258eebdSKonstantin Ananyev */
2309*a258eebdSKonstantin Ananyev static int
cmp_eval_state(const struct bpf_eval_state * lv,const struct bpf_eval_state * rv)2310*a258eebdSKonstantin Ananyev cmp_eval_state(const struct bpf_eval_state *lv, const struct bpf_eval_state *rv)
2311*a258eebdSKonstantin Ananyev {
2312*a258eebdSKonstantin Ananyev int32_t rc;
2313*a258eebdSKonstantin Ananyev uint32_t i, k;
2314*a258eebdSKonstantin Ananyev
2315*a258eebdSKonstantin Ananyev /* for stack expect identical values */
2316*a258eebdSKonstantin Ananyev rc = memcmp(lv->sv, rv->sv, sizeof(lv->sv));
2317*a258eebdSKonstantin Ananyev if (rc != 0)
2318*a258eebdSKonstantin Ananyev return -(2 * EBPF_REG_NUM);
2319*a258eebdSKonstantin Ananyev
2320*a258eebdSKonstantin Ananyev k = 0;
2321*a258eebdSKonstantin Ananyev /* check register values */
2322*a258eebdSKonstantin Ananyev for (i = 0; i != RTE_DIM(lv->rv); i++) {
2323*a258eebdSKonstantin Ananyev rc = memcmp(&lv->rv[i], &rv->rv[i], sizeof(lv->rv[i]));
2324*a258eebdSKonstantin Ananyev if (rc != 0 && cmp_reg_val_within(&lv->rv[i], &rv->rv[i]) != 0)
2325*a258eebdSKonstantin Ananyev return -(i + 1);
2326*a258eebdSKonstantin Ananyev k += (rc != 0);
2327*a258eebdSKonstantin Ananyev }
2328*a258eebdSKonstantin Ananyev
2329*a258eebdSKonstantin Ananyev return k;
2330*a258eebdSKonstantin Ananyev }
2331*a258eebdSKonstantin Ananyev
2332*a258eebdSKonstantin Ananyev /*
2333*a258eebdSKonstantin Ananyev * check did we already evaluated that path and can it be pruned that time.
2334*a258eebdSKonstantin Ananyev */
2335*a258eebdSKonstantin Ananyev static int
prune_eval_state(struct bpf_verifier * bvf,const struct inst_node * node,struct inst_node * next)2336*a258eebdSKonstantin Ananyev prune_eval_state(struct bpf_verifier *bvf, const struct inst_node *node,
2337*a258eebdSKonstantin Ananyev struct inst_node *next)
2338*a258eebdSKonstantin Ananyev {
2339*a258eebdSKonstantin Ananyev int32_t rc;
2340*a258eebdSKonstantin Ananyev struct bpf_eval_state *safe;
2341*a258eebdSKonstantin Ananyev
2342*a258eebdSKonstantin Ananyev rc = INT32_MIN;
2343*a258eebdSKonstantin Ananyev SLIST_FOREACH(safe, &next->evst.safe, next) {
2344*a258eebdSKonstantin Ananyev rc = cmp_eval_state(safe, bvf->evst);
2345*a258eebdSKonstantin Ananyev if (rc >= 0)
2346*a258eebdSKonstantin Ananyev break;
2347*a258eebdSKonstantin Ananyev }
2348*a258eebdSKonstantin Ananyev
2349*a258eebdSKonstantin Ananyev rc = (rc >= 0) ? 0 : -1;
2350*a258eebdSKonstantin Ananyev
2351*a258eebdSKonstantin Ananyev /*
2352*a258eebdSKonstantin Ananyev * current state doesn't match any safe states,
2353*a258eebdSKonstantin Ananyev * so no prunning is possible right now,
2354*a258eebdSKonstantin Ananyev * track current state for future references.
2355*a258eebdSKonstantin Ananyev */
2356*a258eebdSKonstantin Ananyev if (rc != 0)
2357*a258eebdSKonstantin Ananyev save_start_eval_state(bvf, next);
2358*a258eebdSKonstantin Ananyev
2359*a258eebdSKonstantin Ananyev RTE_BPF_LOG_LINE(DEBUG, "%s(bvf=%p,node=%u,next=%u) returns %d, "
2360*a258eebdSKonstantin Ananyev "next->evst.start=%p, next->evst.nb_safe=%u",
2361*a258eebdSKonstantin Ananyev __func__, bvf, get_node_idx(bvf, node),
2362*a258eebdSKonstantin Ananyev get_node_idx(bvf, next), rc,
2363*a258eebdSKonstantin Ananyev next->evst.start, next->evst.nb_safe);
2364*a258eebdSKonstantin Ananyev return rc;
2365*a258eebdSKonstantin Ananyev }
2366*a258eebdSKonstantin Ananyev
2367*a258eebdSKonstantin Ananyev /* Do second pass through CFG and try to evaluate instructions
2368*a258eebdSKonstantin Ananyev * via each possible path. The verifier will try all paths, tracking types of
2369*a258eebdSKonstantin Ananyev * registers used as input to instructions, and updating resulting type via
2370*a258eebdSKonstantin Ananyev * register state values. Plus for each register and possible stack value it
2371*a258eebdSKonstantin Ananyev * tries to estimate possible max/min value.
2372*a258eebdSKonstantin Ananyev * For conditional jumps, a stack is used to save evaluation state, so one
2373*a258eebdSKonstantin Ananyev * path is explored while the state for the other path is pushed onto the stack.
2374*a258eebdSKonstantin Ananyev * Then later, we backtrack to the first pushed instruction and repeat the cycle
2375*a258eebdSKonstantin Ananyev * until the stack is empty and we're done.
2376*a258eebdSKonstantin Ananyev * For program with many conditional branches walking through all possible path
2377*a258eebdSKonstantin Ananyev * could be very excessive. So to minimize number of evaluations we use
2378*a258eebdSKonstantin Ananyev * heuristic similar to what Linux kernel does - state pruning:
2379*a258eebdSKonstantin Ananyev * If from given instruction for given program state we explore all possible
2380*a258eebdSKonstantin Ananyev * paths and for each of them reach _exit() without any complaints and a valid
2381*a258eebdSKonstantin Ananyev * R0 value, then for that instruction, that program state can be marked as
2382*a258eebdSKonstantin Ananyev * 'safe'. When we later arrive at the same instruction with a state
2383*a258eebdSKonstantin Ananyev * equivalent to an earlier instruction's 'safe' state, we can prune the search.
2384*a258eebdSKonstantin Ananyev * For now, only states for JCC targets are saved/examined.
238599a2dd95SBruce Richardson */
238699a2dd95SBruce Richardson static int
evaluate(struct bpf_verifier * bvf)238799a2dd95SBruce Richardson evaluate(struct bpf_verifier *bvf)
238899a2dd95SBruce Richardson {
238999a2dd95SBruce Richardson int32_t rc;
239099a2dd95SBruce Richardson uint32_t idx, op;
239199a2dd95SBruce Richardson const char *err;
239299a2dd95SBruce Richardson const struct ebpf_insn *ins;
239399a2dd95SBruce Richardson struct inst_node *next, *node;
239499a2dd95SBruce Richardson
2395*a258eebdSKonstantin Ananyev struct {
2396*a258eebdSKonstantin Ananyev uint32_t nb_eval;
2397*a258eebdSKonstantin Ananyev uint32_t nb_prune;
2398*a258eebdSKonstantin Ananyev uint32_t nb_save;
2399*a258eebdSKonstantin Ananyev uint32_t nb_restore;
2400*a258eebdSKonstantin Ananyev } stats;
2401*a258eebdSKonstantin Ananyev
240299a2dd95SBruce Richardson /* initial state of frame pointer */
240399a2dd95SBruce Richardson static const struct bpf_reg_val rvfp = {
240499a2dd95SBruce Richardson .v = {
240599a2dd95SBruce Richardson .type = BPF_ARG_PTR_STACK,
240699a2dd95SBruce Richardson .size = MAX_BPF_STACK_SIZE,
240799a2dd95SBruce Richardson },
240899a2dd95SBruce Richardson .mask = UINT64_MAX,
240999a2dd95SBruce Richardson .u = {.min = MAX_BPF_STACK_SIZE, .max = MAX_BPF_STACK_SIZE},
241099a2dd95SBruce Richardson .s = {.min = MAX_BPF_STACK_SIZE, .max = MAX_BPF_STACK_SIZE},
241199a2dd95SBruce Richardson };
241299a2dd95SBruce Richardson
241399a2dd95SBruce Richardson bvf->evst->rv[EBPF_REG_1].v = bvf->prm->prog_arg;
241499a2dd95SBruce Richardson bvf->evst->rv[EBPF_REG_1].mask = UINT64_MAX;
241599a2dd95SBruce Richardson if (bvf->prm->prog_arg.type == RTE_BPF_ARG_RAW)
241699a2dd95SBruce Richardson eval_max_bound(bvf->evst->rv + EBPF_REG_1, UINT64_MAX);
241799a2dd95SBruce Richardson
241899a2dd95SBruce Richardson bvf->evst->rv[EBPF_REG_10] = rvfp;
241999a2dd95SBruce Richardson
242099a2dd95SBruce Richardson ins = bvf->prm->ins;
242199a2dd95SBruce Richardson node = bvf->in;
242299a2dd95SBruce Richardson next = node;
242399a2dd95SBruce Richardson rc = 0;
242499a2dd95SBruce Richardson
2425*a258eebdSKonstantin Ananyev memset(&stats, 0, sizeof(stats));
2426*a258eebdSKonstantin Ananyev
242799a2dd95SBruce Richardson while (node != NULL && rc == 0) {
242899a2dd95SBruce Richardson
242999a2dd95SBruce Richardson /*
243099a2dd95SBruce Richardson * current node evaluation, make sure we evaluate
243199a2dd95SBruce Richardson * each node only once.
243299a2dd95SBruce Richardson */
243399a2dd95SBruce Richardson if (next != NULL) {
243499a2dd95SBruce Richardson
243599a2dd95SBruce Richardson bvf->evin = node;
243699a2dd95SBruce Richardson idx = get_node_idx(bvf, node);
243799a2dd95SBruce Richardson op = ins[idx].code;
243899a2dd95SBruce Richardson
24394a6672c2SStephen Hemminger /* for jcc node make a copy of evaluation state */
2440*a258eebdSKonstantin Ananyev if (node->nb_edge > 1) {
2441*a258eebdSKonstantin Ananyev rc |= save_cur_eval_state(bvf, node);
2442*a258eebdSKonstantin Ananyev stats.nb_save++;
2443*a258eebdSKonstantin Ananyev }
244499a2dd95SBruce Richardson
244599a2dd95SBruce Richardson if (ins_chk[op].eval != NULL && rc == 0) {
244699a2dd95SBruce Richardson err = ins_chk[op].eval(bvf, ins + idx);
2447*a258eebdSKonstantin Ananyev stats.nb_eval++;
244899a2dd95SBruce Richardson if (err != NULL) {
24490e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s: %s at pc: %u",
245099a2dd95SBruce Richardson __func__, err, idx);
245199a2dd95SBruce Richardson rc = -EINVAL;
245299a2dd95SBruce Richardson }
245399a2dd95SBruce Richardson }
245499a2dd95SBruce Richardson
2455df82b12bSDavid Marchand log_dbg_eval_state(bvf, ins + idx, idx);
245699a2dd95SBruce Richardson bvf->evin = NULL;
245799a2dd95SBruce Richardson }
245899a2dd95SBruce Richardson
245999a2dd95SBruce Richardson /* proceed through CFG */
246099a2dd95SBruce Richardson next = get_next_node(bvf, node);
2461*a258eebdSKonstantin Ananyev
246299a2dd95SBruce Richardson if (next != NULL) {
246399a2dd95SBruce Richardson
246499a2dd95SBruce Richardson /* proceed with next child */
246599a2dd95SBruce Richardson if (node->cur_edge == node->nb_edge &&
2466*a258eebdSKonstantin Ananyev node->evst.cur != NULL) {
2467*a258eebdSKonstantin Ananyev restore_cur_eval_state(bvf, node);
2468*a258eebdSKonstantin Ananyev stats.nb_restore++;
2469*a258eebdSKonstantin Ananyev }
247099a2dd95SBruce Richardson
2471*a258eebdSKonstantin Ananyev /*
2472*a258eebdSKonstantin Ananyev * for jcc targets: check did we already evaluated
2473*a258eebdSKonstantin Ananyev * that path and can it's evaluation be skipped that
2474*a258eebdSKonstantin Ananyev * time.
2475*a258eebdSKonstantin Ananyev */
2476*a258eebdSKonstantin Ananyev if (node->nb_edge > 1 && prune_eval_state(bvf, node,
2477*a258eebdSKonstantin Ananyev next) == 0) {
2478*a258eebdSKonstantin Ananyev next = NULL;
2479*a258eebdSKonstantin Ananyev stats.nb_prune++;
2480*a258eebdSKonstantin Ananyev } else {
248199a2dd95SBruce Richardson next->prev_node = get_node_idx(bvf, node);
248299a2dd95SBruce Richardson node = next;
2483*a258eebdSKonstantin Ananyev }
248499a2dd95SBruce Richardson } else {
248599a2dd95SBruce Richardson /*
248699a2dd95SBruce Richardson * finished with current node and all it's kids,
2487*a258eebdSKonstantin Ananyev * mark it's @start state as safe for future references,
2488*a258eebdSKonstantin Ananyev * and proceed with parent.
248999a2dd95SBruce Richardson */
249099a2dd95SBruce Richardson node->cur_edge = 0;
2491*a258eebdSKonstantin Ananyev save_safe_eval_state(bvf, node);
249299a2dd95SBruce Richardson node = get_prev_node(bvf, node);
249399a2dd95SBruce Richardson
249499a2dd95SBruce Richardson /* finished */
249599a2dd95SBruce Richardson if (node == bvf->in)
249699a2dd95SBruce Richardson node = NULL;
249799a2dd95SBruce Richardson }
249899a2dd95SBruce Richardson }
249999a2dd95SBruce Richardson
2500*a258eebdSKonstantin Ananyev RTE_LOG(DEBUG, BPF, "%s(%p) returns %d, stats:\n"
2501*a258eebdSKonstantin Ananyev "node evaluations=%u;\n"
2502*a258eebdSKonstantin Ananyev "state pruned=%u;\n"
2503*a258eebdSKonstantin Ananyev "state saves=%u;\n"
2504*a258eebdSKonstantin Ananyev "state restores=%u;\n",
2505*a258eebdSKonstantin Ananyev __func__, bvf, rc,
2506*a258eebdSKonstantin Ananyev stats.nb_eval, stats.nb_prune, stats.nb_save, stats.nb_restore);
2507*a258eebdSKonstantin Ananyev
250899a2dd95SBruce Richardson return rc;
250999a2dd95SBruce Richardson }
251099a2dd95SBruce Richardson
251199a2dd95SBruce Richardson int
__rte_bpf_validate(struct rte_bpf * bpf)2512cf095b1eSJ.J. Martzki __rte_bpf_validate(struct rte_bpf *bpf)
251399a2dd95SBruce Richardson {
251499a2dd95SBruce Richardson int32_t rc;
251599a2dd95SBruce Richardson struct bpf_verifier bvf;
251699a2dd95SBruce Richardson
251799a2dd95SBruce Richardson /* check input argument type, don't allow mbuf ptr on 32-bit */
251899a2dd95SBruce Richardson if (bpf->prm.prog_arg.type != RTE_BPF_ARG_RAW &&
251999a2dd95SBruce Richardson bpf->prm.prog_arg.type != RTE_BPF_ARG_PTR &&
252099a2dd95SBruce Richardson (sizeof(uint64_t) != sizeof(uintptr_t) ||
252199a2dd95SBruce Richardson bpf->prm.prog_arg.type != RTE_BPF_ARG_PTR_MBUF)) {
25220e21c7c0SDavid Marchand RTE_BPF_LOG_LINE(ERR, "%s: unsupported argument type", __func__);
252399a2dd95SBruce Richardson return -ENOTSUP;
252499a2dd95SBruce Richardson }
252599a2dd95SBruce Richardson
252699a2dd95SBruce Richardson memset(&bvf, 0, sizeof(bvf));
252799a2dd95SBruce Richardson bvf.prm = &bpf->prm;
252899a2dd95SBruce Richardson bvf.in = calloc(bpf->prm.nb_ins, sizeof(bvf.in[0]));
252999a2dd95SBruce Richardson if (bvf.in == NULL)
253099a2dd95SBruce Richardson return -ENOMEM;
253199a2dd95SBruce Richardson
253299a2dd95SBruce Richardson rc = validate(&bvf);
253399a2dd95SBruce Richardson
253499a2dd95SBruce Richardson if (rc == 0) {
253599a2dd95SBruce Richardson rc = evst_pool_init(&bvf);
253699a2dd95SBruce Richardson if (rc == 0)
253799a2dd95SBruce Richardson rc = evaluate(&bvf);
253899a2dd95SBruce Richardson evst_pool_fini(&bvf);
253999a2dd95SBruce Richardson }
254099a2dd95SBruce Richardson
254199a2dd95SBruce Richardson free(bvf.in);
254299a2dd95SBruce Richardson
254399a2dd95SBruce Richardson /* copy collected info */
254499a2dd95SBruce Richardson if (rc == 0) {
254599a2dd95SBruce Richardson bpf->stack_sz = bvf.stack_sz;
254699a2dd95SBruce Richardson
254799a2dd95SBruce Richardson /* for LD_ABS/LD_IND, we'll need extra space on the stack */
254899a2dd95SBruce Richardson if (bvf.nb_ldmb_nodes != 0)
254999a2dd95SBruce Richardson bpf->stack_sz = RTE_ALIGN_CEIL(bpf->stack_sz +
255099a2dd95SBruce Richardson sizeof(uint64_t), sizeof(uint64_t));
255199a2dd95SBruce Richardson }
255299a2dd95SBruce Richardson
255399a2dd95SBruce Richardson return rc;
255499a2dd95SBruce Richardson }
2555