History

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Alexei Starovoitov says: ==================== pull-request: bpf 2019-01-02 The following pull-request contains BPF updates for your *net* tree. The main changes are: 1) prevent out of bounds speculation on pointer arithmetic, from Daniel. 2) typo fix, from Xiaozhou. ====================

David S. Miller committed 7 years ago

Commit be630042 parents d63967e a67825f6 files · +1452 −108Browse files

Unified · Split

6 files
  1. include/linux/bpf_verifier.h +12 −0
  2. include/linux/filter.h +3 −7
  3. kernel/bpf/core.c +37 −17
  4. kernel/bpf/verifier.c +275 −61
  5. tools/testing/selftests/bpf/test_maps.c +1 −1
  6. tools/testing/selftests/bpf/test_verifier.c +1124 −22
include/linux/bpf_verifier.h+12−0
@@ -148,6 +148,7 @@ struct bpf_verifier_state { · 147 unmodified lines
148148 /* call stack tracking */
149149 struct bpf_func_state *frame[MAX_CALL_FRAMES];
150150 u32 curframe;
151+ bool speculative;
151152 };
152153
153154 #define bpf_get_spilled_reg(slot, frame) \
@@ -167,15 +168,24 @@ struct bpf_verifier_state_list { · 13 unmodified lines
167168 struct bpf_verifier_state_list *next;
168169 };
169170
171+/* Possible states for alu_state member. */
172+#define BPF_ALU_SANITIZE_SRC 1U
173+#define BPF_ALU_SANITIZE_DST 2U
174+#define BPF_ALU_NEG_VALUE (1U << 2)
175+#define BPF_ALU_SANITIZE (BPF_ALU_SANITIZE_SRC | \
176+ BPF_ALU_SANITIZE_DST)
177+
170178 struct bpf_insn_aux_data {
171179 union {
172180 enum bpf_reg_type ptr_type; /* pointer type for load/store insns */
173181 unsigned long map_state; /* pointer/poison value for maps */
174182 s32 call_imm; /* saved imm field of call insn */
183+ u32 alu_limit; /* limit for add/sub register with pointer */
175184 };
176185 int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
177186 int sanitize_stack_off; /* stack slot to be cleared */
178187 bool seen; /* this insn was processed by the verifier */
188+ u8 alu_state; /* used in combination with alu_limit */
179189 };
180190
181191 #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
@@ -212,6 +222,8 @@ struct bpf_subprog_info { · 30 unmodified lines
212222 * one verifier_env per bpf_check() call
213223 */
214224 struct bpf_verifier_env {
225+ u32 insn_idx;
226+ u32 prev_insn_idx;
215227 struct bpf_prog *prog; /* eBPF program being verified */
216228 const struct bpf_verifier_ops *ops;
217229 struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */
include/linux/filter.h+3−7
@@ -53,14 +53,10 @@ struct sock_reuseport; · 52 unmodified lines
5353 #define BPF_REG_D BPF_REG_8 /* data, callee-saved */
5454 #define BPF_REG_H BPF_REG_9 /* hlen, callee-saved */
5555
56−/* Kernel hidden auxiliary/helper register for hardening step.
57− * Only used by eBPF JITs. It's nothing more than a temporary
58− * register that JITs use internally, only that here it's part
59− * of eBPF instructions that have been rewritten for blinding
60− * constants. See JIT pre-step in bpf_jit_blind_constants().
61− */
56+/* Kernel hidden auxiliary/helper register. */
6257 #define BPF_REG_AX MAX_BPF_REG
63−#define MAX_BPF_JIT_REG (MAX_BPF_REG + 1)
58+#define MAX_BPF_EXT_REG (MAX_BPF_REG + 1)
59+#define MAX_BPF_JIT_REG MAX_BPF_EXT_REG
6460
6561 /* unused opcode to mark special call to bpf_tail_call() helper */
6662 #define BPF_TAIL_CALL 0xf0
kernel/bpf/core.c+37−17
@@ -54,6 +54,7 @@ · 53 unmodified lines
5454 #define DST regs[insn->dst_reg]
5555 #define SRC regs[insn->src_reg]
5656 #define FP regs[BPF_REG_FP]
57+#define AX regs[BPF_REG_AX]
5758 #define ARG1 regs[BPF_REG_ARG1]
5859 #define CTX regs[BPF_REG_CTX]
5960 #define IMM insn->imm
@@ -857,6 +858,26 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from, · 797 unmodified lines
857858 BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG);
858859 BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG);
859860
861+ /* Constraints on AX register:
862+ *
863+ * AX register is inaccessible from user space. It is mapped in
864+ * all JITs, and used here for constant blinding rewrites. It is
865+ * typically "stateless" meaning its contents are only valid within
866+ * the executed instruction, but not across several instructions.
867+ * There are a few exceptions however which are further detailed
868+ * below.
869+ *
870+ * Constant blinding is only used by JITs, not in the interpreter.
871+ * The interpreter uses AX in some occasions as a local temporary
872+ * register e.g. in DIV or MOD instructions.
873+ *
874+ * In restricted circumstances, the verifier can also use the AX
875+ * register for rewrites as long as they do not interfere with
876+ * the above cases!
877+ */
878+ if (from->dst_reg == BPF_REG_AX || from->src_reg == BPF_REG_AX)
879+ goto out;
880+
860881 if (from->imm == 0 &&
861882 (from->code == (BPF_ALU | BPF_MOV | BPF_K) ||
862883 from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) {
@@ -1188,7 +1209,6 @@ bool bpf_opcode_in_insntable(u8 code) · 325 unmodified lines
11881209 */
11891210 static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack)
11901211 {
1191− u64 tmp;
11921212 #define BPF_INSN_2_LBL(x, y) [BPF_##x | BPF_##y] = &&x##_##y
11931213 #define BPF_INSN_3_LBL(x, y, z) [BPF_##x | BPF_##y | BPF_##z] = &&x##_##y##_##z
11941214 static const void *jumptable[256] = {
@@ -1268,36 +1288,36 @@ select_insn: · 73 unmodified lines
12681288 (*(s64 *) &DST) >>= IMM;
12691289 CONT;
12701290 ALU64_MOD_X:
1271− div64_u64_rem(DST, SRC, &tmp);
1272− DST = tmp;
1291+ div64_u64_rem(DST, SRC, &AX);
1292+ DST = AX;
12731293 CONT;
12741294 ALU_MOD_X:
1275− tmp = (u32) DST;
1276− DST = do_div(tmp, (u32) SRC);
1295+ AX = (u32) DST;
1296+ DST = do_div(AX, (u32) SRC);
12771297 CONT;
12781298 ALU64_MOD_K:
1279− div64_u64_rem(DST, IMM, &tmp);
1280− DST = tmp;
1299+ div64_u64_rem(DST, IMM, &AX);
1300+ DST = AX;
12811301 CONT;
12821302 ALU_MOD_K:
1283− tmp = (u32) DST;
1284− DST = do_div(tmp, (u32) IMM);
1303+ AX = (u32) DST;
1304+ DST = do_div(AX, (u32) IMM);
12851305 CONT;
12861306 ALU64_DIV_X:
12871307 DST = div64_u64(DST, SRC);
12881308 CONT;
12891309 ALU_DIV_X:
1290− tmp = (u32) DST;
1291− do_div(tmp, (u32) SRC);
1292− DST = (u32) tmp;
1310+ AX = (u32) DST;
1311+ do_div(AX, (u32) SRC);
1312+ DST = (u32) AX;
12931313 CONT;
12941314 ALU64_DIV_K:
12951315 DST = div64_u64(DST, IMM);
12961316 CONT;
12971317 ALU_DIV_K:
1298− tmp = (u32) DST;
1299− do_div(tmp, (u32) IMM);
1300− DST = (u32) tmp;
1318+ AX = (u32) DST;
1319+ do_div(AX, (u32) IMM);
1320+ DST = (u32) AX;
13011321 CONT;
13021322 ALU_END_TO_BE:
13031323 switch (IMM) {
@@ -1553,7 +1573,7 @@ STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */ · 249 unmodified lines
15531573 static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \
15541574 { \
15551575 u64 stack[stack_size / sizeof(u64)]; \
1556− u64 regs[MAX_BPF_REG]; \
1576+ u64 regs[MAX_BPF_EXT_REG]; \
15571577 \
15581578 FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
15591579 ARG1 = (u64) (unsigned long) ctx; \
@@ -1566,7 +1586,7 @@ static u64 PROG_NAME_ARGS(stack_size)(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5, \ · 6 unmodified lines
15661586 const struct bpf_insn *insn) \
15671587 { \
15681588 u64 stack[stack_size / sizeof(u64)]; \
1569− u64 regs[MAX_BPF_REG]; \
1589+ u64 regs[MAX_BPF_EXT_REG]; \
15701590 \
15711591 FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \
15721592 BPF_R1 = r1; \
kernel/bpf/verifier.c+275−61
@@ -710,6 +710,7 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state, · 709 unmodified lines
710710 free_func_state(dst_state->frame[i]);
711711 dst_state->frame[i] = NULL;
712712 }
713+ dst_state->speculative = src->speculative;
713714 dst_state->curframe = src->curframe;
714715 for (i = 0; i <= src->curframe; i++) {
715716 dst = dst_state->frame[i];
@@ -754,7 +755,8 @@ static int pop_stack(struct bpf_verifier_env *env, int *prev_insn_idx, · 38 unmodified lines
754755 }
755756
756757 static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
757− int insn_idx, int prev_insn_idx)
758+ int insn_idx, int prev_insn_idx,
759+ bool speculative)
758760 {
759761 struct bpf_verifier_state *cur = env->cur_state;
760762 struct bpf_verifier_stack_elem *elem;
@@ -772,6 +774,7 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env, · 11 unmodified lines
772774 err = copy_verifier_state(&elem->st, cur);
773775 if (err)
774776 goto err;
777+ elem->st.speculative |= speculative;
775778 if (env->stack_size > BPF_COMPLEXITY_LIMIT_STACK) {
776779 verbose(env, "BPF program is too complex\n");
777780 goto err;
@@ -1387,6 +1390,31 @@ static int check_stack_read(struct bpf_verifier_env *env, · 609 unmodified lines
13871390 }
13881391 }
13891392
1393+static int check_stack_access(struct bpf_verifier_env *env,
1394+ const struct bpf_reg_state *reg,
1395+ int off, int size)
1396+{
1397+ /* Stack accesses must be at a fixed offset, so that we
1398+ * can determine what type of data were returned. See
1399+ * check_stack_read().
1400+ */
1401+ if (!tnum_is_const(reg->var_off)) {
1402+ char tn_buf[48];
1403+
1404+ tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
1405+ verbose(env, "variable stack access var_off=%s off=%d size=%d",
1406+ tn_buf, off, size);
1407+ return -EACCES;
1408+ }
1409+
1410+ if (off >= 0 || off < -MAX_BPF_STACK) {
1411+ verbose(env, "invalid stack off=%d size=%d\n", off, size);
1412+ return -EACCES;
1413+ }
1414+
1415+ return 0;
1416+}
1417+
13901418 /* check read/write into map element returned by bpf_map_lookup_elem() */
13911419 static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off,
13921420 int size, bool zero_size_allowed)
@@ -1418,13 +1446,17 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, · 25 unmodified lines
14181446 */
14191447 if (env->log.level)
14201448 print_verifier_state(env, state);
1449+
14211450 /* The minimum value is only important with signed
14221451 * comparisons where we can't assume the floor of a
14231452 * value is 0. If we are using signed variables for our
14241453 * index'es we need to make sure that whatever we use
14251454 * will have a set floor within our range.
14261455 */
1427− if (reg->smin_value < 0) {
1456+ if (reg->smin_value < 0 &&
1457+ (reg->smin_value == S64_MIN ||
1458+ (off + reg->smin_value != (s64)(s32)(off + reg->smin_value)) ||
1459+ reg->smin_value + off < 0)) {
14281460 verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
14291461 regno);
14301462 return -EACCES;
@@ -1954,24 +1986,10 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn · 523 unmodified lines
19541986 }
19551987
19561988 } else if (reg->type == PTR_TO_STACK) {
1957− /* stack accesses must be at a fixed offset, so that we can
1958− * determine what type of data were returned.
1959− * See check_stack_read().
1960− */
1961− if (!tnum_is_const(reg->var_off)) {
1962− char tn_buf[48];
1963−
1964− tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
1965− verbose(env, "variable stack access var_off=%s off=%d size=%d",
1966− tn_buf, off, size);
1967− return -EACCES;
1968− }
19691989 off += reg->var_off.value;
1970− if (off >= 0 || off < -MAX_BPF_STACK) {
1971− verbose(env, "invalid stack off=%d size=%d\n", off,
1972− size);
1973− return -EACCES;
1974− }
1990+ err = check_stack_access(env, reg, off, size);
1991+ if (err)
1992+ return err;
19751993
19761994 state = func(env, reg);
19771995 err = update_stack_depth(env, state, off);
@@ -3052,6 +3070,102 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env, · 1074 unmodified lines
30523070 return true;
30533071 }
30543072
3073+static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env)
3074+{
3075+ return &env->insn_aux_data[env->insn_idx];
3076+}
3077+
3078+static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
3079+ u32 *ptr_limit, u8 opcode, bool off_is_neg)
3080+{
3081+ bool mask_to_left = (opcode == BPF_ADD && off_is_neg) ||
3082+ (opcode == BPF_SUB && !off_is_neg);
3083+ u32 off;
3084+
3085+ switch (ptr_reg->type) {
3086+ case PTR_TO_STACK:
3087+ off = ptr_reg->off + ptr_reg->var_off.value;
3088+ if (mask_to_left)
3089+ *ptr_limit = MAX_BPF_STACK + off;
3090+ else
3091+ *ptr_limit = -off;
3092+ return 0;
3093+ case PTR_TO_MAP_VALUE:
3094+ if (mask_to_left) {
3095+ *ptr_limit = ptr_reg->umax_value + ptr_reg->off;
3096+ } else {
3097+ off = ptr_reg->smin_value + ptr_reg->off;
3098+ *ptr_limit = ptr_reg->map_ptr->value_size - off;
3099+ }
3100+ return 0;
3101+ default:
3102+ return -EINVAL;
3103+ }
3104+}
3105+
3106+static int sanitize_ptr_alu(struct bpf_verifier_env *env,
3107+ struct bpf_insn *insn,
3108+ const struct bpf_reg_state *ptr_reg,
3109+ struct bpf_reg_state *dst_reg,
3110+ bool off_is_neg)
3111+{
3112+ struct bpf_verifier_state *vstate = env->cur_state;
3113+ struct bpf_insn_aux_data *aux = cur_aux(env);
3114+ bool ptr_is_dst_reg = ptr_reg == dst_reg;
3115+ u8 opcode = BPF_OP(insn->code);
3116+ u32 alu_state, alu_limit;
3117+ struct bpf_reg_state tmp;
3118+ bool ret;
3119+
3120+ if (env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K)
3121+ return 0;
3122+
3123+ /* We already marked aux for masking from non-speculative
3124+ * paths, thus we got here in the first place. We only care
3125+ * to explore bad access from here.
3126+ */
3127+ if (vstate->speculative)
3128+ goto do_sim;
3129+
3130+ alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
3131+ alu_state |= ptr_is_dst_reg ?
3132+ BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
3133+
3134+ if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg))
3135+ return 0;
3136+
3137+ /* If we arrived here from different branches with different
3138+ * limits to sanitize, then this won't work.
3139+ */
3140+ if (aux->alu_state &&
3141+ (aux->alu_state != alu_state ||
3142+ aux->alu_limit != alu_limit))
3143+ return -EACCES;
3144+
3145+ /* Corresponding fixup done in fixup_bpf_calls(). */
3146+ aux->alu_state = alu_state;
3147+ aux->alu_limit = alu_limit;
3148+
3149+do_sim:
3150+ /* Simulate and find potential out-of-bounds access under
3151+ * speculative execution from truncation as a result of
3152+ * masking when off was not within expected range. If off
3153+ * sits in dst, then we temporarily need to move ptr there
3154+ * to simulate dst (== 0) +/-= ptr. Needed, for example,
3155+ * for cases where we use K-based arithmetic in one direction
3156+ * and truncated reg-based in the other in order to explore
3157+ * bad access.
3158+ */
3159+ if (!ptr_is_dst_reg) {
3160+ tmp = *dst_reg;
3161+ *dst_reg = *ptr_reg;
3162+ }
3163+ ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
3164+ if (!ptr_is_dst_reg)
3165+ *dst_reg = tmp;
3166+ return !ret ? -EFAULT : 0;
3167+}
3168+
30553169 /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
30563170 * Caller should also handle BPF_MOV case separately.
30573171 * If we return -EACCES, caller may want to try again treating pointer as a
@@ -3070,8 +3184,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 12 unmodified lines
30703184 smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
30713185 u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
30723186 umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
3187+ u32 dst = insn->dst_reg, src = insn->src_reg;
30733188 u8 opcode = BPF_OP(insn->code);
3074− u32 dst = insn->dst_reg;
3189+ int ret;
30753190
30763191 dst_reg = &regs[dst];
30773192
@@ -3104,6 +3219,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 26 unmodified lines
31043219 verbose(env, "R%d pointer arithmetic on %s prohibited\n",
31053220 dst, reg_type_str[ptr_reg->type]);
31063221 return -EACCES;
3222+ case PTR_TO_MAP_VALUE:
3223+ if (!env->allow_ptr_leaks && !known && (smin_val < 0) != (smax_val < 0)) {
3224+ verbose(env, "R%d has unknown scalar with mixed signed bounds, pointer arithmetic with it prohibited for !root\n",
3225+ off_reg == dst_reg ? dst : src);
3226+ return -EACCES;
3227+ }
3228+ /* fall-through */
31073229 default:
31083230 break;
31093231 }
@@ -3120,6 +3242,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 10 unmodified lines
31203242
31213243 switch (opcode) {
31223244 case BPF_ADD:
3245+ ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
3246+ if (ret < 0) {
3247+ verbose(env, "R%d tried to add from different maps or paths\n", dst);
3248+ return ret;
3249+ }
31233250 /* We can take a fixed offset as long as it doesn't overflow
31243251 * the s32 'off' field
31253252 */
@@ -3170,6 +3297,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 44 unmodified lines
31703297 }
31713298 break;
31723299 case BPF_SUB:
3300+ ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
3301+ if (ret < 0) {
3302+ verbose(env, "R%d tried to sub from different maps or paths\n", dst);
3303+ return ret;
3304+ }
31733305 if (dst_reg == off_reg) {
31743306 /* scalar -= pointer. Creates an unknown scalar */
31753307 verbose(env, "R%d tried to subtract pointer from scalar\n",
@@ -3249,6 +3381,25 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 73 unmodified lines
32493381 __update_reg_bounds(dst_reg);
32503382 __reg_deduce_bounds(dst_reg);
32513383 __reg_bound_offset(dst_reg);
3384+
3385+ /* For unprivileged we require that resulting offset must be in bounds
3386+ * in order to be able to sanitize access later on.
3387+ */
3388+ if (!env->allow_ptr_leaks) {
3389+ if (dst_reg->type == PTR_TO_MAP_VALUE &&
3390+ check_map_access(env, dst, dst_reg->off, 1, false)) {
3391+ verbose(env, "R%d pointer arithmetic of map value goes out of range, "
3392+ "prohibited for !root\n", dst);
3393+ return -EACCES;
3394+ } else if (dst_reg->type == PTR_TO_STACK &&
3395+ check_stack_access(env, dst_reg, dst_reg->off +
3396+ dst_reg->var_off.value, 1)) {
3397+ verbose(env, "R%d stack pointer arithmetic goes out of range, "
3398+ "prohibited for !root\n", dst);
3399+ return -EACCES;
3400+ }
3401+ }
3402+
32523403 return 0;
32533404 }
32543405
@@ -4348,7 +4499,8 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, · 1093 unmodified lines
43484499 }
43494500 }
43504501
4351− other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx);
4502+ other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx,
4503+ false);
43524504 if (!other_branch)
43534505 return -EFAULT;
43544506 other_branch_regs = other_branch->frame[other_branch->curframe]->regs;
@@ -5458,6 +5610,12 @@ static bool states_equal(struct bpf_verifier_env *env, · 1103 unmodified lines
54585610 if (old->curframe != cur->curframe)
54595611 return false;
54605612
5613+ /* Verification state from speculative execution simulation
5614+ * must never prune a non-speculative execution one.
5615+ */
5616+ if (old->speculative && !cur->speculative)
5617+ return false;
5618+
54615619 /* for states to be equal callsites have to be the same
54625620 * and all frame states need to be equivalent
54635621 */
@@ -5650,7 +5808,6 @@ static int do_check(struct bpf_verifier_env *env) · 186 unmodified lines
56505808 struct bpf_insn *insns = env->prog->insnsi;
56515809 struct bpf_reg_state *regs;
56525810 int insn_cnt = env->prog->len, i;
5653− int insn_idx, prev_insn_idx = 0;
56545811 int insn_processed = 0;
56555812 bool do_print_state = false;
56565813
@@ -5660,6 +5817,7 @@ static int do_check(struct bpf_verifier_env *env) · 3 unmodified lines
56605817 if (!state)
56615818 return -ENOMEM;
56625819 state->curframe = 0;
5820+ state->speculative = false;
56635821 state->frame[0] = kzalloc(sizeof(struct bpf_func_state), GFP_KERNEL);
56645822 if (!state->frame[0]) {
56655823 kfree(state);
@@ -5670,19 +5828,19 @@ static int do_check(struct bpf_verifier_env *env) · 4 unmodified lines
56705828 BPF_MAIN_FUNC /* callsite */,
56715829 0 /* frameno */,
56725830 0 /* subprogno, zero == main subprog */);
5673− insn_idx = 0;
5831+
56745832 for (;;) {
56755833 struct bpf_insn *insn;
56765834 u8 class;
56775835 int err;
56785836
5679− if (insn_idx >= insn_cnt) {
5837+ if (env->insn_idx >= insn_cnt) {
56805838 verbose(env, "invalid insn idx %d insn_cnt %d\n",
5681− insn_idx, insn_cnt);
5839+ env->insn_idx, insn_cnt);
56825840 return -EFAULT;
56835841 }
56845842
5685− insn = &insns[insn_idx];
5843+ insn = &insns[env->insn_idx];
56865844 class = BPF_CLASS(insn->code);
56875845
56885846 if (++insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) {
@@ -5692,17 +5850,19 @@ static int do_check(struct bpf_verifier_env *env) · 3 unmodified lines
56925850 return -E2BIG;
56935851 }
56945852
5695− err = is_state_visited(env, insn_idx);
5853+ err = is_state_visited(env, env->insn_idx);
56965854 if (err < 0)
56975855 return err;
56985856 if (err == 1) {
56995857 /* found equivalent state, can prune the search */
57005858 if (env->log.level) {
57015859 if (do_print_state)
5702− verbose(env, "\nfrom %d to %d: safe\n",
5703− prev_insn_idx, insn_idx);
5860+ verbose(env, "\nfrom %d to %d%s: safe\n",
5861+ env->prev_insn_idx, env->insn_idx,
5862+ env->cur_state->speculative ?
5863+ " (speculative execution)" : "");
57045864 else
5705− verbose(env, "%d: safe\n", insn_idx);
5865+ verbose(env, "%d: safe\n", env->insn_idx);
57065866 }
57075867 goto process_bpf_exit;
57085868 }
@@ -5715,10 +5875,12 @@ static int do_check(struct bpf_verifier_env *env) · 6 unmodified lines
57155875
57165876 if (env->log.level > 1 || (env->log.level && do_print_state)) {
57175877 if (env->log.level > 1)
5718− verbose(env, "%d:", insn_idx);
5878+ verbose(env, "%d:", env->insn_idx);
57195879 else
5720− verbose(env, "\nfrom %d to %d:",
5721− prev_insn_idx, insn_idx);
5880+ verbose(env, "\nfrom %d to %d%s:",
5881+ env->prev_insn_idx, env->insn_idx,
5882+ env->cur_state->speculative ?
5883+ " (speculative execution)" : "");
57225884 print_verifier_state(env, state->frame[state->curframe]);
57235885 do_print_state = false;
57245886 }
@@ -5729,20 +5891,20 @@ static int do_check(struct bpf_verifier_env *env) · 4 unmodified lines
57295891 .private_data = env,
57305892 };
57315893
5732− verbose_linfo(env, insn_idx, "; ");
5733− verbose(env, "%d: ", insn_idx);
5894+ verbose_linfo(env, env->insn_idx, "; ");
5895+ verbose(env, "%d: ", env->insn_idx);
57345896 print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
57355897 }
57365898
57375899 if (bpf_prog_is_dev_bound(env->prog->aux)) {
5738− err = bpf_prog_offload_verify_insn(env, insn_idx,
5739− prev_insn_idx);
5900+ err = bpf_prog_offload_verify_insn(env, env->insn_idx,
5901+ env->prev_insn_idx);
57405902 if (err)
57415903 return err;
57425904 }
57435905
57445906 regs = cur_regs(env);
5745− env->insn_aux_data[insn_idx].seen = true;
5907+ env->insn_aux_data[env->insn_idx].seen = true;
57465908
57475909 if (class == BPF_ALU || class == BPF_ALU64) {
57485910 err = check_alu_op(env, insn);
@@ -5768,13 +5930,13 @@ static int do_check(struct bpf_verifier_env *env) · 19 unmodified lines
57685930 /* check that memory (src_reg + off) is readable,
57695931 * the state of dst_reg will be updated by this func
57705932 */
5771− err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
5772− BPF_SIZE(insn->code), BPF_READ,
5773− insn->dst_reg, false);
5933+ err = check_mem_access(env, env->insn_idx, insn->src_reg,
5934+ insn->off, BPF_SIZE(insn->code),
5935+ BPF_READ, insn->dst_reg, false);
57745936 if (err)
57755937 return err;
57765938
5777− prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
5939+ prev_src_type = &env->insn_aux_data[env->insn_idx].ptr_type;
57785940
57795941 if (*prev_src_type == NOT_INIT) {
57805942 /* saw a valid insn
@@ -5799,10 +5961,10 @@ static int do_check(struct bpf_verifier_env *env) · 18 unmodified lines
57995961 enum bpf_reg_type *prev_dst_type, dst_reg_type;
58005962
58015963 if (BPF_MODE(insn->code) == BPF_XADD) {
5802− err = check_xadd(env, insn_idx, insn);
5964+ err = check_xadd(env, env->insn_idx, insn);
58035965 if (err)
58045966 return err;
5805− insn_idx++;
5967+ env->insn_idx++;
58065968 continue;
58075969 }
58085970
@@ -5818,13 +5980,13 @@ static int do_check(struct bpf_verifier_env *env) · 9 unmodified lines
58185980 dst_reg_type = regs[insn->dst_reg].type;
58195981
58205982 /* check that memory (dst_reg + off) is writeable */
5821− err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
5822− BPF_SIZE(insn->code), BPF_WRITE,
5823− insn->src_reg, false);
5983+ err = check_mem_access(env, env->insn_idx, insn->dst_reg,
5984+ insn->off, BPF_SIZE(insn->code),
5985+ BPF_WRITE, insn->src_reg, false);
58245986 if (err)
58255987 return err;
58265988
5827− prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type;
5989+ prev_dst_type = &env->insn_aux_data[env->insn_idx].ptr_type;
58285990
58295991 if (*prev_dst_type == NOT_INIT) {
58305992 *prev_dst_type = dst_reg_type;
@@ -5852,9 +6014,9 @@ static int do_check(struct bpf_verifier_env *env) · 21 unmodified lines
58526014 }
58536015
58546016 /* check that memory (dst_reg + off) is writeable */
5855− err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
5856− BPF_SIZE(insn->code), BPF_WRITE,
5857− -1, false);
6017+ err = check_mem_access(env, env->insn_idx, insn->dst_reg,
6018+ insn->off, BPF_SIZE(insn->code),
6019+ BPF_WRITE, -1, false);
58586020 if (err)
58596021 return err;
58606022
@@ -5872,9 +6034,9 @@ static int do_check(struct bpf_verifier_env *env) · 11 unmodified lines
58726034 }
58736035
58746036 if (insn->src_reg == BPF_PSEUDO_CALL)
5875− err = check_func_call(env, insn, &insn_idx);
6037+ err = check_func_call(env, insn, &env->insn_idx);
58766038 else
5877− err = check_helper_call(env, insn->imm, insn_idx);
6039+ err = check_helper_call(env, insn->imm, env->insn_idx);
58786040 if (err)
58796041 return err;
58806042
@@ -5887,7 +6049,7 @@ static int do_check(struct bpf_verifier_env *env) · 6 unmodified lines
58876049 return -EINVAL;
58886050 }
58896051
5890− insn_idx += insn->off + 1;
6052+ env->insn_idx += insn->off + 1;
58916053 continue;
58926054
58936055 } else if (opcode == BPF_EXIT) {
@@ -5901,8 +6063,8 @@ static int do_check(struct bpf_verifier_env *env) · 7 unmodified lines
59016063
59026064 if (state->curframe) {
59036065 /* exit from nested function */
5904− prev_insn_idx = insn_idx;
5905− err = prepare_func_exit(env, &insn_idx);
6066+ env->prev_insn_idx = env->insn_idx;
6067+ err = prepare_func_exit(env, &env->insn_idx);
59066068 if (err)
59076069 return err;
59086070 do_print_state = true;
@@ -5932,7 +6094,8 @@ static int do_check(struct bpf_verifier_env *env) · 23 unmodified lines
59326094 if (err)
59336095 return err;
59346096 process_bpf_exit:
5935− err = pop_stack(env, &prev_insn_idx, &insn_idx);
6097+ err = pop_stack(env, &env->prev_insn_idx,
6098+ &env->insn_idx);
59366099 if (err < 0) {
59376100 if (err != -ENOENT)
59386101 return err;
@@ -5942,7 +6105,7 @@ process_bpf_exit: · 3 unmodified lines
59426105 continue;
59436106 }
59446107 } else {
5945− err = check_cond_jmp_op(env, insn, &insn_idx);
6108+ err = check_cond_jmp_op(env, insn, &env->insn_idx);
59466109 if (err)
59476110 return err;
59486111 }
@@ -5959,8 +6122,8 @@ process_bpf_exit: · 10 unmodified lines
59596122 if (err)
59606123 return err;
59616124
5962− insn_idx++;
5963− env->insn_aux_data[insn_idx].seen = true;
6125+ env->insn_idx++;
6126+ env->insn_aux_data[env->insn_idx].seen = true;
59646127 } else {
59656128 verbose(env, "invalid BPF_LD mode\n");
59666129 return -EINVAL;
@@ -5970,7 +6133,7 @@ process_bpf_exit: · 3 unmodified lines
59706133 return -EINVAL;
59716134 }
59726135
5973− insn_idx++;
6136+ env->insn_idx++;
59746137 }
59756138
59766139 verbose(env, "processed %d insns (limit %d), stack depth ",
@@ -6709,6 +6872,57 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env) · 732 unmodified lines
67096872 continue;
67106873 }
67116874
6875+ if (insn->code == (BPF_ALU64 | BPF_ADD | BPF_X) ||
6876+ insn->code == (BPF_ALU64 | BPF_SUB | BPF_X)) {
6877+ const u8 code_add = BPF_ALU64 | BPF_ADD | BPF_X;
6878+ const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X;
6879+ struct bpf_insn insn_buf[16];
6880+ struct bpf_insn *patch = &insn_buf[0];
6881+ bool issrc, isneg;
6882+ u32 off_reg;
6883+
6884+ aux = &env->insn_aux_data[i + delta];
6885+ if (!aux->alu_state)
6886+ continue;
6887+
6888+ isneg = aux->alu_state & BPF_ALU_NEG_VALUE;
6889+ issrc = (aux->alu_state & BPF_ALU_SANITIZE) ==
6890+ BPF_ALU_SANITIZE_SRC;
6891+
6892+ off_reg = issrc ? insn->src_reg : insn->dst_reg;
6893+ if (isneg)
6894+ *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
6895+ *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit - 1);
6896+ *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg);
6897+ *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg);
6898+ *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0);
6899+ *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63);
6900+ if (issrc) {
6901+ *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX,
6902+ off_reg);
6903+ insn->src_reg = BPF_REG_AX;
6904+ } else {
6905+ *patch++ = BPF_ALU64_REG(BPF_AND, off_reg,
6906+ BPF_REG_AX);
6907+ }
6908+ if (isneg)
6909+ insn->code = insn->code == code_add ?
6910+ code_sub : code_add;
6911+ *patch++ = *insn;
6912+ if (issrc && isneg)
6913+ *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
6914+ cnt = patch - insn_buf;
6915+
6916+ new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
6917+ if (!new_prog)
6918+ return -ENOMEM;
6919+
6920+ delta += cnt - 1;
6921+ env->prog = prog = new_prog;
6922+ insn = new_prog->insnsi + i + delta;
6923+ continue;
6924+ }
6925+
67126926 if (insn->code != (BPF_JMP | BPF_CALL))
67136927 continue;
67146928 if (insn->src_reg == BPF_PSEUDO_CALL)
tools/testing/selftests/bpf/test_maps.c+1−1
@@ -510,7 +510,7 @@ static void test_devmap(int task, void *data) · 509 unmodified lines
510510 fd = bpf_create_map(BPF_MAP_TYPE_DEVMAP, sizeof(key), sizeof(value),
511511 2, 0);
512512 if (fd < 0) {
513− printf("Failed to create arraymap '%s'!\n", strerror(errno));
513+ printf("Failed to create devmap '%s'!\n", strerror(errno));
514514 exit(1);
515515 }
516516
tools/testing/selftests/bpf/test_verifier.c+1124−22
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323 #include <stdbool.h>
2424 #include <sched.h>
2525 #include <limits.h>
26+#include <assert.h>
2627
2728 #include <sys/capability.h>
2829
@@ -2577,6 +2578,7 @@ static struct bpf_test tests[] = { · 2548 unmodified lines
25772578 },
25782579 .result = REJECT,
25792580 .errstr = "invalid stack off=-79992 size=8",
2581+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
25802582 },
25812583 {
25822584 "PTR_TO_STACK store/load - out of bounds high",
@@ -3104,6 +3106,8 @@ static struct bpf_test tests[] = { · 521 unmodified lines
31043106 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8),
31053107 BPF_EXIT_INSN(),
31063108 },
3109+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3110+ .result_unpriv = REJECT,
31073111 .result = ACCEPT,
31083112 },
31093113 {
@@ -3205,6 +3209,243 @@ static struct bpf_test tests[] = { · 95 unmodified lines
32053209 /* Verifier rewrite for unpriv skips tail call here. */
32063210 .retval_unpriv = 2,
32073211 },
3212+ {
3213+ "PTR_TO_STACK check high 1",
3214+ .insns = {
3215+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3216+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -1),
3217+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3218+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3219+ BPF_EXIT_INSN(),
3220+ },
3221+ .result = ACCEPT,
3222+ .retval = 42,
3223+ },
3224+ {
3225+ "PTR_TO_STACK check high 2",
3226+ .insns = {
3227+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3228+ BPF_ST_MEM(BPF_B, BPF_REG_1, -1, 42),
3229+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, -1),
3230+ BPF_EXIT_INSN(),
3231+ },
3232+ .result = ACCEPT,
3233+ .retval = 42,
3234+ },
3235+ {
3236+ "PTR_TO_STACK check high 3",
3237+ .insns = {
3238+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3239+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0),
3240+ BPF_ST_MEM(BPF_B, BPF_REG_1, -1, 42),
3241+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, -1),
3242+ BPF_EXIT_INSN(),
3243+ },
3244+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3245+ .result_unpriv = REJECT,
3246+ .result = ACCEPT,
3247+ .retval = 42,
3248+ },
3249+ {
3250+ "PTR_TO_STACK check high 4",
3251+ .insns = {
3252+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3253+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 0),
3254+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3255+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3256+ BPF_EXIT_INSN(),
3257+ },
3258+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3259+ .errstr = "invalid stack off=0 size=1",
3260+ .result = REJECT,
3261+ },
3262+ {
3263+ "PTR_TO_STACK check high 5",
3264+ .insns = {
3265+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3266+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, (1 << 29) - 1),
3267+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3268+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3269+ BPF_EXIT_INSN(),
3270+ },
3271+ .result = REJECT,
3272+ .errstr = "invalid stack off",
3273+ },
3274+ {
3275+ "PTR_TO_STACK check high 6",
3276+ .insns = {
3277+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3278+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, (1 << 29) - 1),
3279+ BPF_ST_MEM(BPF_B, BPF_REG_1, SHRT_MAX, 42),
3280+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, SHRT_MAX),
3281+ BPF_EXIT_INSN(),
3282+ },
3283+ .result = REJECT,
3284+ .errstr = "invalid stack off",
3285+ },
3286+ {
3287+ "PTR_TO_STACK check high 7",
3288+ .insns = {
3289+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3290+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, (1 << 29) - 1),
3291+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, (1 << 29) - 1),
3292+ BPF_ST_MEM(BPF_B, BPF_REG_1, SHRT_MAX, 42),
3293+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, SHRT_MAX),
3294+ BPF_EXIT_INSN(),
3295+ },
3296+ .result = REJECT,
3297+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3298+ .errstr = "fp pointer offset",
3299+ },
3300+ {
3301+ "PTR_TO_STACK check low 1",
3302+ .insns = {
3303+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3304+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -512),
3305+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3306+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3307+ BPF_EXIT_INSN(),
3308+ },
3309+ .result = ACCEPT,
3310+ .retval = 42,
3311+ },
3312+ {
3313+ "PTR_TO_STACK check low 2",
3314+ .insns = {
3315+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3316+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -513),
3317+ BPF_ST_MEM(BPF_B, BPF_REG_1, 1, 42),
3318+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 1),
3319+ BPF_EXIT_INSN(),
3320+ },
3321+ .result_unpriv = REJECT,
3322+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3323+ .result = ACCEPT,
3324+ .retval = 42,
3325+ },
3326+ {
3327+ "PTR_TO_STACK check low 3",
3328+ .insns = {
3329+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3330+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -513),
3331+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3332+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3333+ BPF_EXIT_INSN(),
3334+ },
3335+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3336+ .errstr = "invalid stack off=-513 size=1",
3337+ .result = REJECT,
3338+ },
3339+ {
3340+ "PTR_TO_STACK check low 4",
3341+ .insns = {
3342+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3343+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, INT_MIN),
3344+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3345+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3346+ BPF_EXIT_INSN(),
3347+ },
3348+ .result = REJECT,
3349+ .errstr = "math between fp pointer",
3350+ },
3351+ {
3352+ "PTR_TO_STACK check low 5",
3353+ .insns = {
3354+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3355+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -((1 << 29) - 1)),
3356+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3357+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3358+ BPF_EXIT_INSN(),
3359+ },
3360+ .result = REJECT,
3361+ .errstr = "invalid stack off",
3362+ },
3363+ {
3364+ "PTR_TO_STACK check low 6",
3365+ .insns = {
3366+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3367+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -((1 << 29) - 1)),
3368+ BPF_ST_MEM(BPF_B, BPF_REG_1, SHRT_MIN, 42),
3369+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, SHRT_MIN),
3370+ BPF_EXIT_INSN(),
3371+ },
3372+ .result = REJECT,
3373+ .errstr = "invalid stack off",
3374+ },
3375+ {
3376+ "PTR_TO_STACK check low 7",
3377+ .insns = {
3378+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3379+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -((1 << 29) - 1)),
3380+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -((1 << 29) - 1)),
3381+ BPF_ST_MEM(BPF_B, BPF_REG_1, SHRT_MIN, 42),
3382+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, SHRT_MIN),
3383+ BPF_EXIT_INSN(),
3384+ },
3385+ .result = REJECT,
3386+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
3387+ .errstr = "fp pointer offset",
3388+ },
3389+ {
3390+ "PTR_TO_STACK mixed reg/k, 1",
3391+ .insns = {
3392+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3393+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -3),
3394+ BPF_MOV64_IMM(BPF_REG_2, -3),
3395+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
3396+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3397+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3398+ BPF_EXIT_INSN(),
3399+ },
3400+ .result = ACCEPT,
3401+ .retval = 42,
3402+ },
3403+ {
3404+ "PTR_TO_STACK mixed reg/k, 2",
3405+ .insns = {
3406+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
3407+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
3408+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3409+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -3),
3410+ BPF_MOV64_IMM(BPF_REG_2, -3),
3411+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
3412+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3413+ BPF_MOV64_REG(BPF_REG_5, BPF_REG_10),
3414+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_5, -6),
3415+ BPF_EXIT_INSN(),
3416+ },
3417+ .result = ACCEPT,
3418+ .retval = 42,
3419+ },
3420+ {
3421+ "PTR_TO_STACK mixed reg/k, 3",
3422+ .insns = {
3423+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3424+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -3),
3425+ BPF_MOV64_IMM(BPF_REG_2, -3),
3426+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
3427+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3428+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
3429+ BPF_EXIT_INSN(),
3430+ },
3431+ .result = ACCEPT,
3432+ .retval = -3,
3433+ },
3434+ {
3435+ "PTR_TO_STACK reg",
3436+ .insns = {
3437+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
3438+ BPF_MOV64_IMM(BPF_REG_2, -3),
3439+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
3440+ BPF_ST_MEM(BPF_B, BPF_REG_1, 0, 42),
3441+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
3442+ BPF_EXIT_INSN(),
3443+ },
3444+ .result_unpriv = REJECT,
3445+ .errstr_unpriv = "invalid stack off=0 size=1",
3446+ .result = ACCEPT,
3447+ .retval = 42,
3448+ },
32083449 {
32093450 "stack pointer arithmetic",
32103451 .insns = {
@@ -6610,7 +6851,446 @@ static struct bpf_test tests[] = { · 3399 unmodified lines
66106851 .prog_type = BPF_PROG_TYPE_TRACEPOINT,
66116852 },
66126853 {
6613− "map access: known scalar += value_ptr",
6854+ "map access: known scalar += value_ptr from different maps",
6855+ .insns = {
6856+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
6857+ offsetof(struct __sk_buff, len)),
6858+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6859+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
6860+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
6861+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
6862+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6863+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
6864+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6865+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6866+ BPF_FUNC_map_lookup_elem),
6867+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
6868+ BPF_MOV64_IMM(BPF_REG_1, 4),
6869+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
6870+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
6871+ BPF_MOV64_IMM(BPF_REG_0, 1),
6872+ BPF_EXIT_INSN(),
6873+ },
6874+ .fixup_map_hash_16b = { 5 },
6875+ .fixup_map_array_48b = { 8 },
6876+ .result = ACCEPT,
6877+ .result_unpriv = REJECT,
6878+ .errstr_unpriv = "R1 tried to add from different maps",
6879+ .retval = 1,
6880+ },
6881+ {
6882+ "map access: value_ptr -= known scalar from different maps",
6883+ .insns = {
6884+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
6885+ offsetof(struct __sk_buff, len)),
6886+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6887+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
6888+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
6889+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
6890+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6891+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
6892+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6893+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6894+ BPF_FUNC_map_lookup_elem),
6895+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
6896+ BPF_MOV64_IMM(BPF_REG_1, 4),
6897+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
6898+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
6899+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
6900+ BPF_MOV64_IMM(BPF_REG_0, 1),
6901+ BPF_EXIT_INSN(),
6902+ },
6903+ .fixup_map_hash_16b = { 5 },
6904+ .fixup_map_array_48b = { 8 },
6905+ .result = ACCEPT,
6906+ .result_unpriv = REJECT,
6907+ .errstr_unpriv = "R0 min value is outside of the array range",
6908+ .retval = 1,
6909+ },
6910+ {
6911+ "map access: known scalar += value_ptr from different maps, but same value properties",
6912+ .insns = {
6913+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
6914+ offsetof(struct __sk_buff, len)),
6915+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6916+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
6917+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
6918+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 1, 3),
6919+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6920+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 1, 2),
6921+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6922+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6923+ BPF_FUNC_map_lookup_elem),
6924+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
6925+ BPF_MOV64_IMM(BPF_REG_1, 4),
6926+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
6927+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
6928+ BPF_MOV64_IMM(BPF_REG_0, 1),
6929+ BPF_EXIT_INSN(),
6930+ },
6931+ .fixup_map_hash_48b = { 5 },
6932+ .fixup_map_array_48b = { 8 },
6933+ .result = ACCEPT,
6934+ .retval = 1,
6935+ },
6936+ {
6937+ "map access: value_ptr += known scalar, upper oob arith, test 1",
6938+ .insns = {
6939+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6940+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
6941+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
6942+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6943+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6944+ BPF_FUNC_map_lookup_elem),
6945+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
6946+ BPF_MOV64_IMM(BPF_REG_1, 48),
6947+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
6948+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
6949+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
6950+ BPF_MOV64_IMM(BPF_REG_0, 1),
6951+ BPF_EXIT_INSN(),
6952+ },
6953+ .fixup_map_array_48b = { 3 },
6954+ .result = ACCEPT,
6955+ .result_unpriv = REJECT,
6956+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
6957+ .retval = 1,
6958+ },
6959+ {
6960+ "map access: value_ptr += known scalar, upper oob arith, test 2",
6961+ .insns = {
6962+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6963+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
6964+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
6965+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6966+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6967+ BPF_FUNC_map_lookup_elem),
6968+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
6969+ BPF_MOV64_IMM(BPF_REG_1, 49),
6970+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
6971+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
6972+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
6973+ BPF_MOV64_IMM(BPF_REG_0, 1),
6974+ BPF_EXIT_INSN(),
6975+ },
6976+ .fixup_map_array_48b = { 3 },
6977+ .result = ACCEPT,
6978+ .result_unpriv = REJECT,
6979+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
6980+ .retval = 1,
6981+ },
6982+ {
6983+ "map access: value_ptr += known scalar, upper oob arith, test 3",
6984+ .insns = {
6985+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
6986+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
6987+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
6988+ BPF_LD_MAP_FD(BPF_REG_1, 0),
6989+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6990+ BPF_FUNC_map_lookup_elem),
6991+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
6992+ BPF_MOV64_IMM(BPF_REG_1, 47),
6993+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
6994+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
6995+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
6996+ BPF_MOV64_IMM(BPF_REG_0, 1),
6997+ BPF_EXIT_INSN(),
6998+ },
6999+ .fixup_map_array_48b = { 3 },
7000+ .result = ACCEPT,
7001+ .result_unpriv = REJECT,
7002+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
7003+ .retval = 1,
7004+ },
7005+ {
7006+ "map access: value_ptr -= known scalar, lower oob arith, test 1",
7007+ .insns = {
7008+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7009+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7010+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7011+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7012+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7013+ BPF_FUNC_map_lookup_elem),
7014+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
7015+ BPF_MOV64_IMM(BPF_REG_1, 47),
7016+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7017+ BPF_MOV64_IMM(BPF_REG_1, 48),
7018+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
7019+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
7020+ BPF_MOV64_IMM(BPF_REG_0, 1),
7021+ BPF_EXIT_INSN(),
7022+ },
7023+ .fixup_map_array_48b = { 3 },
7024+ .result = REJECT,
7025+ .errstr = "R0 min value is outside of the array range",
7026+ .result_unpriv = REJECT,
7027+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
7028+ },
7029+ {
7030+ "map access: value_ptr -= known scalar, lower oob arith, test 2",
7031+ .insns = {
7032+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7033+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7034+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7035+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7036+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7037+ BPF_FUNC_map_lookup_elem),
7038+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
7039+ BPF_MOV64_IMM(BPF_REG_1, 47),
7040+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7041+ BPF_MOV64_IMM(BPF_REG_1, 48),
7042+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
7043+ BPF_MOV64_IMM(BPF_REG_1, 1),
7044+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7045+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
7046+ BPF_MOV64_IMM(BPF_REG_0, 1),
7047+ BPF_EXIT_INSN(),
7048+ },
7049+ .fixup_map_array_48b = { 3 },
7050+ .result = ACCEPT,
7051+ .result_unpriv = REJECT,
7052+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
7053+ .retval = 1,
7054+ },
7055+ {
7056+ "map access: value_ptr -= known scalar, lower oob arith, test 3",
7057+ .insns = {
7058+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7059+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7060+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7061+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7062+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7063+ BPF_FUNC_map_lookup_elem),
7064+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
7065+ BPF_MOV64_IMM(BPF_REG_1, 47),
7066+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7067+ BPF_MOV64_IMM(BPF_REG_1, 47),
7068+ BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
7069+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
7070+ BPF_MOV64_IMM(BPF_REG_0, 1),
7071+ BPF_EXIT_INSN(),
7072+ },
7073+ .fixup_map_array_48b = { 3 },
7074+ .result = ACCEPT,
7075+ .result_unpriv = REJECT,
7076+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
7077+ .retval = 1,
7078+ },
7079+ {
7080+ "map access: known scalar += value_ptr",
7081+ .insns = {
7082+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7083+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7084+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7085+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7086+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7087+ BPF_FUNC_map_lookup_elem),
7088+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
7089+ BPF_MOV64_IMM(BPF_REG_1, 4),
7090+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
7091+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
7092+ BPF_MOV64_IMM(BPF_REG_0, 1),
7093+ BPF_EXIT_INSN(),
7094+ },
7095+ .fixup_map_array_48b = { 3 },
7096+ .result = ACCEPT,
7097+ .retval = 1,
7098+ },
7099+ {
7100+ "map access: value_ptr += known scalar, 1",
7101+ .insns = {
7102+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7103+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7104+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7105+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7106+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7107+ BPF_FUNC_map_lookup_elem),
7108+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
7109+ BPF_MOV64_IMM(BPF_REG_1, 4),
7110+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7111+ BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7112+ BPF_MOV64_IMM(BPF_REG_0, 1),
7113+ BPF_EXIT_INSN(),
7114+ },
7115+ .fixup_map_array_48b = { 3 },
7116+ .result = ACCEPT,
7117+ .retval = 1,
7118+ },
7119+ {
7120+ "map access: value_ptr += known scalar, 2",
7121+ .insns = {
7122+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7123+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7124+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7125+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7126+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7127+ BPF_FUNC_map_lookup_elem),
7128+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
7129+ BPF_MOV64_IMM(BPF_REG_1, 49),
7130+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7131+ BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7132+ BPF_MOV64_IMM(BPF_REG_0, 1),
7133+ BPF_EXIT_INSN(),
7134+ },
7135+ .fixup_map_array_48b = { 3 },
7136+ .result = REJECT,
7137+ .errstr = "invalid access to map value",
7138+ },
7139+ {
7140+ "map access: value_ptr += known scalar, 3",
7141+ .insns = {
7142+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7143+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7144+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7145+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7146+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7147+ BPF_FUNC_map_lookup_elem),
7148+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
7149+ BPF_MOV64_IMM(BPF_REG_1, -1),
7150+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7151+ BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7152+ BPF_MOV64_IMM(BPF_REG_0, 1),
7153+ BPF_EXIT_INSN(),
7154+ },
7155+ .fixup_map_array_48b = { 3 },
7156+ .result = REJECT,
7157+ .errstr = "invalid access to map value",
7158+ },
7159+ {
7160+ "map access: value_ptr += known scalar, 4",
7161+ .insns = {
7162+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7163+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7164+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7165+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7166+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7167+ BPF_FUNC_map_lookup_elem),
7168+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
7169+ BPF_MOV64_IMM(BPF_REG_1, 5),
7170+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7171+ BPF_MOV64_IMM(BPF_REG_1, -2),
7172+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7173+ BPF_MOV64_IMM(BPF_REG_1, -1),
7174+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7175+ BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7176+ BPF_MOV64_IMM(BPF_REG_0, 1),
7177+ BPF_EXIT_INSN(),
7178+ },
7179+ .fixup_map_array_48b = { 3 },
7180+ .result = ACCEPT,
7181+ .result_unpriv = REJECT,
7182+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
7183+ .retval = 1,
7184+ },
7185+ {
7186+ "map access: value_ptr += known scalar, 5",
7187+ .insns = {
7188+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7189+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7190+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7191+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7192+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7193+ BPF_FUNC_map_lookup_elem),
7194+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
7195+ BPF_MOV64_IMM(BPF_REG_1, (6 + 1) * sizeof(int)),
7196+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
7197+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
7198+ BPF_EXIT_INSN(),
7199+ },
7200+ .fixup_map_array_48b = { 3 },
7201+ .result = ACCEPT,
7202+ .retval = 0xabcdef12,
7203+ },
7204+ {
7205+ "map access: value_ptr += known scalar, 6",
7206+ .insns = {
7207+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7208+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7209+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7210+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7211+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7212+ BPF_FUNC_map_lookup_elem),
7213+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
7214+ BPF_MOV64_IMM(BPF_REG_1, (3 + 1) * sizeof(int)),
7215+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7216+ BPF_MOV64_IMM(BPF_REG_1, 3 * sizeof(int)),
7217+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7218+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0),
7219+ BPF_EXIT_INSN(),
7220+ },
7221+ .fixup_map_array_48b = { 3 },
7222+ .result = ACCEPT,
7223+ .retval = 0xabcdef12,
7224+ },
7225+ {
7226+ "map access: unknown scalar += value_ptr, 1",
7227+ .insns = {
7228+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7229+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7230+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7231+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7232+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7233+ BPF_FUNC_map_lookup_elem),
7234+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
7235+ BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7236+ BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
7237+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
7238+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
7239+ BPF_MOV64_IMM(BPF_REG_0, 1),
7240+ BPF_EXIT_INSN(),
7241+ },
7242+ .fixup_map_array_48b = { 3 },
7243+ .result = ACCEPT,
7244+ .retval = 1,
7245+ },
7246+ {
7247+ "map access: unknown scalar += value_ptr, 2",
7248+ .insns = {
7249+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7250+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7251+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7252+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7253+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7254+ BPF_FUNC_map_lookup_elem),
7255+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
7256+ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
7257+ BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 31),
7258+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
7259+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
7260+ BPF_EXIT_INSN(),
7261+ },
7262+ .fixup_map_array_48b = { 3 },
7263+ .result = ACCEPT,
7264+ .retval = 0xabcdef12,
7265+ },
7266+ {
7267+ "map access: unknown scalar += value_ptr, 3",
7268+ .insns = {
7269+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
7270+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
7271+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
7272+ BPF_LD_MAP_FD(BPF_REG_1, 0),
7273+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7274+ BPF_FUNC_map_lookup_elem),
7275+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
7276+ BPF_MOV64_IMM(BPF_REG_1, -1),
7277+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7278+ BPF_MOV64_IMM(BPF_REG_1, 1),
7279+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7280+ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
7281+ BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 31),
7282+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
7283+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
7284+ BPF_EXIT_INSN(),
7285+ },
7286+ .fixup_map_array_48b = { 3 },
7287+ .result = ACCEPT,
7288+ .result_unpriv = REJECT,
7289+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
7290+ .retval = 0xabcdef12,
7291+ },
7292+ {
7293+ "map access: unknown scalar += value_ptr, 4",
66147294 .insns = {
66157295 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
66167296 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -6618,19 +7298,22 @@ static struct bpf_test tests[] = { · 1 unmodified line
66187298 BPF_LD_MAP_FD(BPF_REG_1, 0),
66197299 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
66207300 BPF_FUNC_map_lookup_elem),
6621− BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
6622− BPF_MOV64_IMM(BPF_REG_1, 4),
7301+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
7302+ BPF_MOV64_IMM(BPF_REG_1, 19),
7303+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7304+ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
7305+ BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 31),
66237306 BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
6624− BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
6625− BPF_MOV64_IMM(BPF_REG_0, 1),
7307+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
66267308 BPF_EXIT_INSN(),
66277309 },
66287310 .fixup_map_array_48b = { 3 },
6629− .result = ACCEPT,
6630− .retval = 1,
7311+ .result = REJECT,
7312+ .errstr = "R1 max value is outside of the array range",
7313+ .errstr_unpriv = "R1 pointer arithmetic of map value goes out of range",
66317314 },
66327315 {
6633− "map access: value_ptr += known scalar",
7316+ "map access: value_ptr += unknown scalar, 1",
66347317 .insns = {
66357318 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
66367319 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -6638,8 +7321,9 @@ static struct bpf_test tests[] = { · 1 unmodified line
66387321 BPF_LD_MAP_FD(BPF_REG_1, 0),
66397322 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
66407323 BPF_FUNC_map_lookup_elem),
6641− BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
6642− BPF_MOV64_IMM(BPF_REG_1, 4),
7324+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
7325+ BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7326+ BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
66437327 BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
66447328 BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
66457329 BPF_MOV64_IMM(BPF_REG_0, 1),
@@ -6650,7 +7334,7 @@ static struct bpf_test tests[] = { · 4 unmodified lines
66507334 .retval = 1,
66517335 },
66527336 {
6653− "map access: unknown scalar += value_ptr",
7337+ "map access: value_ptr += unknown scalar, 2",
66547338 .insns = {
66557339 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
66567340 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -6659,19 +7343,18 @@ static struct bpf_test tests[] = { · 2 unmodified lines
66597343 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
66607344 BPF_FUNC_map_lookup_elem),
66617345 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
6662− BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
6663− BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
6664− BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
6665− BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
6666− BPF_MOV64_IMM(BPF_REG_0, 1),
7346+ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
7347+ BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 31),
7348+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
7349+ BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0),
66677350 BPF_EXIT_INSN(),
66687351 },
66697352 .fixup_map_array_48b = { 3 },
66707353 .result = ACCEPT,
6671− .retval = 1,
7354+ .retval = 0xabcdef12,
66727355 },
66737356 {
6674− "map access: value_ptr += unknown scalar",
7357+ "map access: value_ptr += unknown scalar, 3",
66757358 .insns = {
66767359 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
66777360 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -6679,13 +7362,20 @@ static struct bpf_test tests[] = { · 1 unmodified line
66797362 BPF_LD_MAP_FD(BPF_REG_1, 0),
66807363 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
66817364 BPF_FUNC_map_lookup_elem),
6682− BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
6683− BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7365+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
7366+ BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
7367+ BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 8),
7368+ BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 16),
66847369 BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
6685− BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
6686− BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
7370+ BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 1),
7371+ BPF_ALU64_IMM(BPF_OR, BPF_REG_3, 1),
7372+ BPF_JMP_REG(BPF_JGT, BPF_REG_2, BPF_REG_3, 4),
7373+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_3),
7374+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
66877375 BPF_MOV64_IMM(BPF_REG_0, 1),
66887376 BPF_EXIT_INSN(),
7377+ BPF_MOV64_IMM(BPF_REG_0, 2),
7378+ BPF_JMP_IMM(BPF_JA, 0, 0, -3),
66897379 },
66907380 .fixup_map_array_48b = { 3 },
66917381 .result = ACCEPT,
@@ -6770,6 +7460,8 @@ static struct bpf_test tests[] = { · 78 unmodified lines
67707460 },
67717461 .fixup_map_array_48b = { 3 },
67727462 .result = ACCEPT,
7463+ .result_unpriv = REJECT,
7464+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
67737465 .retval = 1,
67747466 },
67757467 {
@@ -6837,6 +7529,8 @@ static struct bpf_test tests[] = { · 61 unmodified lines
68377529 },
68387530 .fixup_map_array_48b = { 3 },
68397531 .result = ACCEPT,
7532+ .result_unpriv = REJECT,
7533+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
68407534 .retval = 1,
68417535 },
68427536 {
@@ -8376,6 +9070,7 @@ static struct bpf_test tests[] = { · 1533 unmodified lines
83769070 },
83779071 .fixup_map_hash_8b = { 3 },
83789072 .errstr = "unbounded min value",
9073+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
83799074 .result = REJECT,
83809075 },
83819076 {
@@ -8400,6 +9095,7 @@ static struct bpf_test tests[] = { · 18 unmodified lines
84009095 },
84019096 .fixup_map_hash_8b = { 3 },
84029097 .errstr = "unbounded min value",
9098+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
84039099 .result = REJECT,
84049100 },
84059101 {
@@ -8426,6 +9122,7 @@ static struct bpf_test tests[] = { · 20 unmodified lines
84269122 },
84279123 .fixup_map_hash_8b = { 3 },
84289124 .errstr = "unbounded min value",
9125+ .errstr_unpriv = "R8 has unknown scalar with mixed signed bounds",
84299126 .result = REJECT,
84309127 },
84319128 {
@@ -8451,6 +9148,7 @@ static struct bpf_test tests[] = { · 19 unmodified lines
84519148 },
84529149 .fixup_map_hash_8b = { 3 },
84539150 .errstr = "unbounded min value",
9151+ .errstr_unpriv = "R8 has unknown scalar with mixed signed bounds",
84549152 .result = REJECT,
84559153 },
84569154 {
@@ -8499,6 +9197,7 @@ static struct bpf_test tests[] = { · 42 unmodified lines
84999197 },
85009198 .fixup_map_hash_8b = { 3 },
85019199 .errstr = "unbounded min value",
9200+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
85029201 .result = REJECT,
85039202 },
85049203 {
@@ -8570,6 +9269,7 @@ static struct bpf_test tests[] = { · 65 unmodified lines
85709269 },
85719270 .fixup_map_hash_8b = { 3 },
85729271 .errstr = "unbounded min value",
9272+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
85739273 .result = REJECT,
85749274 },
85759275 {
@@ -8621,6 +9321,7 @@ static struct bpf_test tests[] = { · 45 unmodified lines
86219321 },
86229322 .fixup_map_hash_8b = { 3 },
86239323 .errstr = "unbounded min value",
9324+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
86249325 .result = REJECT,
86259326 },
86269327 {
@@ -8648,6 +9349,7 @@ static struct bpf_test tests[] = { · 21 unmodified lines
86489349 },
86499350 .fixup_map_hash_8b = { 3 },
86509351 .errstr = "unbounded min value",
9352+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
86519353 .result = REJECT,
86529354 },
86539355 {
@@ -8674,6 +9376,7 @@ static struct bpf_test tests[] = { · 20 unmodified lines
86749376 },
86759377 .fixup_map_hash_8b = { 3 },
86769378 .errstr = "unbounded min value",
9379+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
86779380 .result = REJECT,
86789381 },
86799382 {
@@ -8703,6 +9406,7 @@ static struct bpf_test tests[] = { · 23 unmodified lines
87039406 },
87049407 .fixup_map_hash_8b = { 3 },
87059408 .errstr = "unbounded min value",
9409+ .errstr_unpriv = "R7 has unknown scalar with mixed signed bounds",
87069410 .result = REJECT,
87079411 },
87089412 {
@@ -8733,6 +9437,7 @@ static struct bpf_test tests[] = { · 24 unmodified lines
87339437 },
87349438 .fixup_map_hash_8b = { 4 },
87359439 .errstr = "unbounded min value",
9440+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
87369441 .result = REJECT,
87379442 },
87389443 {
@@ -8761,6 +9466,7 @@ static struct bpf_test tests[] = { · 22 unmodified lines
87619466 },
87629467 .fixup_map_hash_8b = { 3 },
87639468 .errstr = "unbounded min value",
9469+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
87649470 .result = REJECT,
87659471 .result_unpriv = REJECT,
87669472 },
@@ -8813,8 +9519,38 @@ static struct bpf_test tests[] = { · 46 unmodified lines
88139519 },
88149520 .fixup_map_hash_8b = { 3 },
88159521 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
9522+ .errstr_unpriv = "R1 has unknown scalar with mixed signed bounds",
88169523 .result = REJECT,
88179524 },
9525+ {
9526+ "check subtraction on pointers for unpriv",
9527+ .insns = {
9528+ BPF_MOV64_IMM(BPF_REG_0, 0),
9529+ BPF_LD_MAP_FD(BPF_REG_ARG1, 0),
9530+ BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP),
9531+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -8),
9532+ BPF_ST_MEM(BPF_DW, BPF_REG_ARG2, 0, 9),
9533+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
9534+ BPF_FUNC_map_lookup_elem),
9535+ BPF_MOV64_REG(BPF_REG_9, BPF_REG_FP),
9536+ BPF_ALU64_REG(BPF_SUB, BPF_REG_9, BPF_REG_0),
9537+ BPF_LD_MAP_FD(BPF_REG_ARG1, 0),
9538+ BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP),
9539+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -8),
9540+ BPF_ST_MEM(BPF_DW, BPF_REG_ARG2, 0, 0),
9541+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
9542+ BPF_FUNC_map_lookup_elem),
9543+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
9544+ BPF_EXIT_INSN(),
9545+ BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_9, 0),
9546+ BPF_MOV64_IMM(BPF_REG_0, 0),
9547+ BPF_EXIT_INSN(),
9548+ },
9549+ .fixup_map_hash_8b = { 1, 9 },
9550+ .result = ACCEPT,
9551+ .result_unpriv = REJECT,
9552+ .errstr_unpriv = "R9 pointer -= pointer prohibited",
9553+ },
88189554 {
88199555 "bounds check based on zero-extended MOV",
88209556 .insns = {
@@ -9145,6 +9881,36 @@ static struct bpf_test tests[] = { · 324 unmodified lines
91459881 .errstr = "R0 unbounded memory access",
91469882 .result = REJECT
91479883 },
9884+ {
9885+ "bounds check after 32-bit right shift with 64-bit input",
9886+ .insns = {
9887+ BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
9888+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
9889+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
9890+ BPF_LD_MAP_FD(BPF_REG_1, 0),
9891+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
9892+ BPF_FUNC_map_lookup_elem),
9893+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
9894+ /* r1 = 2 */
9895+ BPF_MOV64_IMM(BPF_REG_1, 2),
9896+ /* r1 = 1<<32 */
9897+ BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 31),
9898+ /* r1 = 0 (NOT 2!) */
9899+ BPF_ALU32_IMM(BPF_RSH, BPF_REG_1, 31),
9900+ /* r1 = 0xffff'fffe (NOT 0!) */
9901+ BPF_ALU32_IMM(BPF_SUB, BPF_REG_1, 2),
9902+ /* computes OOB pointer */
9903+ BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
9904+ /* OOB access */
9905+ BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0),
9906+ /* exit */
9907+ BPF_MOV64_IMM(BPF_REG_0, 0),
9908+ BPF_EXIT_INSN(),
9909+ },
9910+ .fixup_map_hash_8b = { 3 },
9911+ .errstr = "R0 invalid mem access",
9912+ .result = REJECT,
9913+ },
91489914 {
91499915 "bounds check map access with off+size signed 32bit overflow. test1",
91509916 .insns = {
@@ -9185,6 +9951,7 @@ static struct bpf_test tests[] = { · 34 unmodified lines
91859951 },
91869952 .fixup_map_hash_8b = { 3 },
91879953 .errstr = "pointer offset 1073741822",
9954+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
91889955 .result = REJECT
91899956 },
91909957 {
@@ -9206,6 +9973,7 @@ static struct bpf_test tests[] = { · 15 unmodified lines
92069973 },
92079974 .fixup_map_hash_8b = { 3 },
92089975 .errstr = "pointer offset -1073741822",
9976+ .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
92099977 .result = REJECT
92109978 },
92119979 {
@@ -9377,6 +10145,7 @@ static struct bpf_test tests[] = { · 165 unmodified lines
937710145 BPF_EXIT_INSN()
937810146 },
937910147 .errstr = "fp pointer offset 1073741822",
10148+ .errstr_unpriv = "R1 stack pointer arithmetic goes out of range",
938010149 .result = REJECT
938110150 },
938210151 {
@@ -13718,6 +14487,328 @@ static struct bpf_test tests[] = { · 4335 unmodified lines
1371814487 .result_unpriv = ACCEPT,
1371914488 .insn_processed = 15,
1372014489 },
14490+ {
14491+ "masking, test out of bounds 1",
14492+ .insns = {
14493+ BPF_MOV32_IMM(BPF_REG_1, 5),
14494+ BPF_MOV32_IMM(BPF_REG_2, 5 - 1),
14495+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14496+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14497+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14498+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14499+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14500+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14501+ BPF_EXIT_INSN(),
14502+ },
14503+ .result = ACCEPT,
14504+ .retval = 0,
14505+ },
14506+ {
14507+ "masking, test out of bounds 2",
14508+ .insns = {
14509+ BPF_MOV32_IMM(BPF_REG_1, 1),
14510+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14511+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14512+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14513+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14514+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14515+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14516+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14517+ BPF_EXIT_INSN(),
14518+ },
14519+ .result = ACCEPT,
14520+ .retval = 0,
14521+ },
14522+ {
14523+ "masking, test out of bounds 3",
14524+ .insns = {
14525+ BPF_MOV32_IMM(BPF_REG_1, 0xffffffff),
14526+ BPF_MOV32_IMM(BPF_REG_2, 0xffffffff - 1),
14527+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14528+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14529+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14530+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14531+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14532+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14533+ BPF_EXIT_INSN(),
14534+ },
14535+ .result = ACCEPT,
14536+ .retval = 0,
14537+ },
14538+ {
14539+ "masking, test out of bounds 4",
14540+ .insns = {
14541+ BPF_MOV32_IMM(BPF_REG_1, 0xffffffff),
14542+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14543+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14544+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14545+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14546+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14547+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14548+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14549+ BPF_EXIT_INSN(),
14550+ },
14551+ .result = ACCEPT,
14552+ .retval = 0,
14553+ },
14554+ {
14555+ "masking, test out of bounds 5",
14556+ .insns = {
14557+ BPF_MOV32_IMM(BPF_REG_1, -1),
14558+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14559+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14560+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14561+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14562+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14563+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14564+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14565+ BPF_EXIT_INSN(),
14566+ },
14567+ .result = ACCEPT,
14568+ .retval = 0,
14569+ },
14570+ {
14571+ "masking, test out of bounds 6",
14572+ .insns = {
14573+ BPF_MOV32_IMM(BPF_REG_1, -1),
14574+ BPF_MOV32_IMM(BPF_REG_2, 0xffffffff - 1),
14575+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14576+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14577+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14578+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14579+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14580+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14581+ BPF_EXIT_INSN(),
14582+ },
14583+ .result = ACCEPT,
14584+ .retval = 0,
14585+ },
14586+ {
14587+ "masking, test out of bounds 7",
14588+ .insns = {
14589+ BPF_MOV64_IMM(BPF_REG_1, 5),
14590+ BPF_MOV32_IMM(BPF_REG_2, 5 - 1),
14591+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14592+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14593+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14594+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14595+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14596+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14597+ BPF_EXIT_INSN(),
14598+ },
14599+ .result = ACCEPT,
14600+ .retval = 0,
14601+ },
14602+ {
14603+ "masking, test out of bounds 8",
14604+ .insns = {
14605+ BPF_MOV64_IMM(BPF_REG_1, 1),
14606+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14607+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14608+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14609+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14610+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14611+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14612+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14613+ BPF_EXIT_INSN(),
14614+ },
14615+ .result = ACCEPT,
14616+ .retval = 0,
14617+ },
14618+ {
14619+ "masking, test out of bounds 9",
14620+ .insns = {
14621+ BPF_MOV64_IMM(BPF_REG_1, 0xffffffff),
14622+ BPF_MOV32_IMM(BPF_REG_2, 0xffffffff - 1),
14623+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14624+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14625+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14626+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14627+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14628+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14629+ BPF_EXIT_INSN(),
14630+ },
14631+ .result = ACCEPT,
14632+ .retval = 0,
14633+ },
14634+ {
14635+ "masking, test out of bounds 10",
14636+ .insns = {
14637+ BPF_MOV64_IMM(BPF_REG_1, 0xffffffff),
14638+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14639+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14640+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14641+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14642+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14643+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14644+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14645+ BPF_EXIT_INSN(),
14646+ },
14647+ .result = ACCEPT,
14648+ .retval = 0,
14649+ },
14650+ {
14651+ "masking, test out of bounds 11",
14652+ .insns = {
14653+ BPF_MOV64_IMM(BPF_REG_1, -1),
14654+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14655+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14656+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14657+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14658+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14659+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14660+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14661+ BPF_EXIT_INSN(),
14662+ },
14663+ .result = ACCEPT,
14664+ .retval = 0,
14665+ },
14666+ {
14667+ "masking, test out of bounds 12",
14668+ .insns = {
14669+ BPF_MOV64_IMM(BPF_REG_1, -1),
14670+ BPF_MOV32_IMM(BPF_REG_2, 0xffffffff - 1),
14671+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14672+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14673+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14674+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14675+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14676+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14677+ BPF_EXIT_INSN(),
14678+ },
14679+ .result = ACCEPT,
14680+ .retval = 0,
14681+ },
14682+ {
14683+ "masking, test in bounds 1",
14684+ .insns = {
14685+ BPF_MOV32_IMM(BPF_REG_1, 4),
14686+ BPF_MOV32_IMM(BPF_REG_2, 5 - 1),
14687+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14688+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14689+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14690+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14691+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14692+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14693+ BPF_EXIT_INSN(),
14694+ },
14695+ .result = ACCEPT,
14696+ .retval = 4,
14697+ },
14698+ {
14699+ "masking, test in bounds 2",
14700+ .insns = {
14701+ BPF_MOV32_IMM(BPF_REG_1, 0),
14702+ BPF_MOV32_IMM(BPF_REG_2, 0xffffffff - 1),
14703+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14704+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14705+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14706+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14707+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14708+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14709+ BPF_EXIT_INSN(),
14710+ },
14711+ .result = ACCEPT,
14712+ .retval = 0,
14713+ },
14714+ {
14715+ "masking, test in bounds 3",
14716+ .insns = {
14717+ BPF_MOV32_IMM(BPF_REG_1, 0xfffffffe),
14718+ BPF_MOV32_IMM(BPF_REG_2, 0xffffffff - 1),
14719+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14720+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14721+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14722+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14723+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14724+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14725+ BPF_EXIT_INSN(),
14726+ },
14727+ .result = ACCEPT,
14728+ .retval = 0xfffffffe,
14729+ },
14730+ {
14731+ "masking, test in bounds 4",
14732+ .insns = {
14733+ BPF_MOV32_IMM(BPF_REG_1, 0xabcde),
14734+ BPF_MOV32_IMM(BPF_REG_2, 0xabcdef - 1),
14735+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14736+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14737+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14738+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14739+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14740+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14741+ BPF_EXIT_INSN(),
14742+ },
14743+ .result = ACCEPT,
14744+ .retval = 0xabcde,
14745+ },
14746+ {
14747+ "masking, test in bounds 5",
14748+ .insns = {
14749+ BPF_MOV32_IMM(BPF_REG_1, 0),
14750+ BPF_MOV32_IMM(BPF_REG_2, 1 - 1),
14751+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14752+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14753+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14754+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14755+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14756+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14757+ BPF_EXIT_INSN(),
14758+ },
14759+ .result = ACCEPT,
14760+ .retval = 0,
14761+ },
14762+ {
14763+ "masking, test in bounds 6",
14764+ .insns = {
14765+ BPF_MOV32_IMM(BPF_REG_1, 46),
14766+ BPF_MOV32_IMM(BPF_REG_2, 47 - 1),
14767+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_1),
14768+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_1),
14769+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14770+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14771+ BPF_ALU64_REG(BPF_AND, BPF_REG_1, BPF_REG_2),
14772+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
14773+ BPF_EXIT_INSN(),
14774+ },
14775+ .result = ACCEPT,
14776+ .retval = 46,
14777+ },
14778+ {
14779+ "masking, test in bounds 7",
14780+ .insns = {
14781+ BPF_MOV64_IMM(BPF_REG_3, -46),
14782+ BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, -1),
14783+ BPF_MOV32_IMM(BPF_REG_2, 47 - 1),
14784+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_3),
14785+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_3),
14786+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14787+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14788+ BPF_ALU64_REG(BPF_AND, BPF_REG_3, BPF_REG_2),
14789+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_3),
14790+ BPF_EXIT_INSN(),
14791+ },
14792+ .result = ACCEPT,
14793+ .retval = 46,
14794+ },
14795+ {
14796+ "masking, test in bounds 8",
14797+ .insns = {
14798+ BPF_MOV64_IMM(BPF_REG_3, -47),
14799+ BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, -1),
14800+ BPF_MOV32_IMM(BPF_REG_2, 47 - 1),
14801+ BPF_ALU64_REG(BPF_SUB, BPF_REG_2, BPF_REG_3),
14802+ BPF_ALU64_REG(BPF_OR, BPF_REG_2, BPF_REG_3),
14803+ BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
14804+ BPF_ALU64_IMM(BPF_ARSH, BPF_REG_2, 63),
14805+ BPF_ALU64_REG(BPF_AND, BPF_REG_3, BPF_REG_2),
14806+ BPF_MOV64_REG(BPF_REG_0, BPF_REG_3),
14807+ BPF_EXIT_INSN(),
14808+ },
14809+ .result = ACCEPT,
14810+ .retval = 0,
14811+ },
1372114812 {
1372214813 "reference tracking in call: free reference in subprog and outside",
1372314814 .insns = {
@@ -14413,6 +15504,16 @@ static int create_map(uint32_t type, uint32_t size_key, · 689 unmodified lines
1441315504 return fd;
1441415505 }
1441515506
15507+static void update_map(int fd, int index)
15508+{
15509+ struct test_val value = {
15510+ .index = (6 + 1) * sizeof(int),
15511+ .foo[6] = 0xabcdef12,
15512+ };
15513+
15514+ assert(!bpf_map_update_elem(fd, &index, &value, 0));
15515+}
15516+
1441615517 static int create_prog_dummy1(enum bpf_prog_type prog_type)
1441715518 {
1441815519 struct bpf_insn prog[] = {
@@ -14564,6 +15665,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, · 145 unmodified lines
1456415665 if (*fixup_map_array_48b) {
1456515666 map_fds[3] = create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
1456615667 sizeof(struct test_val), 1);
15668+ update_map(map_fds[3], 0);
1456715669 do {
1456815670 prog[*fixup_map_array_48b].imm = map_fds[3];
1456915671 fixup_map_array_48b++;