11501b536SEduard Zingerman // SPDX-License-Identifier: GPL-2.0-only 21501b536SEduard Zingerman /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 31501b536SEduard Zingerman 46ccf49f7SEduard Zingerman #include "linux/cnum.h" 51501b536SEduard Zingerman #include <linux/bpf_verifier.h> 61501b536SEduard Zingerman #include <linux/jhash.h> 71501b536SEduard Zingerman #include <linux/log2.h> 84cce2861SEduard Zingerman #include <linux/math64.h> 91501b536SEduard Zingerman #include <linux/min_heap.h> 101501b536SEduard Zingerman #include <linux/bug.h> 116ccf49f7SEduard Zingerman #include <linux/tnum.h> 126ccf49f7SEduard Zingerman #include <linux/overflow.h> 131501b536SEduard Zingerman 14088a5477SEduard Zingerman #define REGS_NUM BPF_SCEV_REGS_NUM 151501b536SEduard Zingerman #define UNKNOWN_EXPR_ID 0 161501b536SEduard Zingerman #define OPAQUE_EXPR_ID 1 171501b536SEduard Zingerman 181501b536SEduard Zingerman /* 191501b536SEduard Zingerman * BPF instructions use 'code', 'src_reg', 'off' and 'imm' fields for instruction encoding. 201501b536SEduard Zingerman * For scalar evolution purpose we want to reuse most of the opcode definitions, 211501b536SEduard Zingerman * but also add a few custom operations (REG and IMM). 221501b536SEduard Zingerman * Use the enum below to uniformly represent all operations relevant for SCEV. 231501b536SEduard Zingerman */ 241501b536SEduard Zingerman enum expr_op { 251501b536SEduard Zingerman /* leave range 0..255 for standard bpf opcodes */ 261501b536SEduard Zingerman UNKNOWN = 256, /* start custom opcodes from the second byte */ 271501b536SEduard Zingerman REG, 281501b536SEduard Zingerman IMM, 291501b536SEduard Zingerman SDIV, SMOD, 301501b536SEduard Zingerman SEXT8, SEXT16, SEXT32, 311501b536SEduard Zingerman ZEXT8, ZEXT16, ZEXT32, 321501b536SEduard Zingerman BSWAP16, BSWAP32, BSWAP64, 331501b536SEduard Zingerman /* during the loop body execution the value can be either of param[0] or param[1] */ 341501b536SEduard Zingerman ANY, 351501b536SEduard Zingerman /* some value that verifier is not going to track precisely */ 361501b536SEduard Zingerman OPAQUE, 371501b536SEduard Zingerman /* '*(u8/16/32 *)(r10 + X) = Y' writes define slot contents only partially */ 381501b536SEduard Zingerman SPILL8, SPILL16, SPILL32, 391501b536SEduard Zingerman /* 401501b536SEduard Zingerman * SCEV expression corresponding to linear equation 'param[0] + param[1] * k', 411501b536SEduard Zingerman * where k is a loop iteration number. Loop here refers to innermost loop 421501b536SEduard Zingerman * containing instruction associated with this expression, as returned by 431501b536SEduard Zingerman * bpf_loop_at_index(). 441501b536SEduard Zingerman */ 451501b536SEduard Zingerman LINEAR_SCEV, 461501b536SEduard Zingerman }; 471501b536SEduard Zingerman 481501b536SEduard Zingerman struct expr { 491501b536SEduard Zingerman u32 op; 501501b536SEduard Zingerman union { 511501b536SEduard Zingerman u32 params[2]; 521501b536SEduard Zingerman s64 imm; 531501b536SEduard Zingerman }; 541501b536SEduard Zingerman }; 551501b536SEduard Zingerman 561501b536SEduard Zingerman struct expr_bucket { 571501b536SEduard Zingerman u32 cnt; 581501b536SEduard Zingerman u32 cap; 591501b536SEduard Zingerman u32 ids[]; 601501b536SEduard Zingerman }; 611501b536SEduard Zingerman 621501b536SEduard Zingerman struct env { 631501b536SEduard Zingerman bool empty; 641501b536SEduard Zingerman u32 reg2expr[REGS_NUM]; 651501b536SEduard Zingerman u32 reg2scev[REGS_NUM]; 661501b536SEduard Zingerman }; 671501b536SEduard Zingerman 681501b536SEduard Zingerman struct insn_envs { 691501b536SEduard Zingerman u32 cnt; 701501b536SEduard Zingerman struct { 711501b536SEduard Zingerman int loop_header; 721501b536SEduard Zingerman struct env *env; 731501b536SEduard Zingerman } entries[]; 741501b536SEduard Zingerman }; 751501b536SEduard Zingerman 761501b536SEduard Zingerman #define EXPR_STACK_DEPTH 8 771501b536SEduard Zingerman 781501b536SEduard Zingerman struct expr_stack_elt { 791501b536SEduard Zingerman u32 id:28; 801501b536SEduard Zingerman u32 pre:1; 811501b536SEduard Zingerman u32 next_param:2; 821501b536SEduard Zingerman }; 831501b536SEduard Zingerman 841501b536SEduard Zingerman DEFINE_MIN_HEAP(int, scev_worklist); 851501b536SEduard Zingerman 861501b536SEduard Zingerman struct scev { 876ccf49f7SEduard Zingerman /* Read-only representatives for stack slots without a saved register. */ 886ccf49f7SEduard Zingerman struct bpf_reg_state zero_reg; 896ccf49f7SEduard Zingerman struct bpf_reg_state unknown_reg; 901501b536SEduard Zingerman /* 911501b536SEduard Zingerman * Expressions are identified by id, exprs_ht ensures that 921501b536SEduard Zingerman * each expression exists as a unique instance. 931501b536SEduard Zingerman * This allows for fast equivalence check: id1 === id2. 941501b536SEduard Zingerman */ 951501b536SEduard Zingerman struct expr_bucket **exprs_ht; 961501b536SEduard Zingerman struct scev_worklist worklist; 971501b536SEduard Zingerman struct insn_envs **envs; 981501b536SEduard Zingerman struct expr *exprs; 991501b536SEduard Zingerman /* 1001501b536SEduard Zingerman * Loops are analyzed one by one, this array keeps track if a particular 1011501b536SEduard Zingerman * instruction was visited on a current pass. 1021501b536SEduard Zingerman */ 1031501b536SEduard Zingerman u32 *discovered; 1041501b536SEduard Zingerman u32 exprs_ht_cnt; 1051501b536SEduard Zingerman int exprs_cnt; 1061501b536SEduard Zingerman int exprs_cap; 1071501b536SEduard Zingerman int envs_cnt; 1081501b536SEduard Zingerman int stack_sz; 1091501b536SEduard Zingerman struct expr_stack_elt expr_stack[EXPR_STACK_DEPTH]; 1101501b536SEduard Zingerman u32 ids_buf[EXPR_STACK_DEPTH]; 1111501b536SEduard Zingerman }; 1121501b536SEduard Zingerman 1131501b536SEduard Zingerman static u32 expr_hash(struct expr *e) 1141501b536SEduard Zingerman { 1151501b536SEduard Zingerman return jhash_3words(e->op, e->params[0], e->params[1], 0); 1161501b536SEduard Zingerman } 1171501b536SEduard Zingerman 1181501b536SEduard Zingerman static int expr_eq(struct expr *a, struct expr *b) 1191501b536SEduard Zingerman { 1201501b536SEduard Zingerman return a->op == b->op && a->imm == b->imm; 1211501b536SEduard Zingerman } 1221501b536SEduard Zingerman 1231501b536SEduard Zingerman static int add_expr(struct scev *scev, struct expr e) 1241501b536SEduard Zingerman { 1251501b536SEduard Zingerman struct expr_bucket *bucket; 1261501b536SEduard Zingerman u32 i, id, hash, new_cap; 1271501b536SEduard Zingerman void *tmp; 1281501b536SEduard Zingerman 1291501b536SEduard Zingerman hash = expr_hash(&e) & (scev->exprs_ht_cnt - 1); 1301501b536SEduard Zingerman bucket = scev->exprs_ht[hash]; 1311501b536SEduard Zingerman 1321501b536SEduard Zingerman if (bucket) { 1331501b536SEduard Zingerman for (i = 0; i < bucket->cnt; i++) { 1341501b536SEduard Zingerman id = bucket->ids[i]; 1351501b536SEduard Zingerman if (expr_eq(&e, &scev->exprs[id])) 1361501b536SEduard Zingerman return id; 1371501b536SEduard Zingerman } 1381501b536SEduard Zingerman } 1391501b536SEduard Zingerman 1401501b536SEduard Zingerman if (!bucket || bucket->cap == bucket->cnt) { 1411501b536SEduard Zingerman new_cap = bucket ? bucket->cap * 2 : 4; 1421501b536SEduard Zingerman bucket = kvrealloc(bucket, sizeof(*bucket) + sizeof(u32) * new_cap, GFP_KERNEL_ACCOUNT | __GFP_ZERO); 1431501b536SEduard Zingerman if (!bucket) 1441501b536SEduard Zingerman return -ENOMEM; 1451501b536SEduard Zingerman scev->exprs_ht[hash] = bucket; 1461501b536SEduard Zingerman bucket->cap = new_cap; 1471501b536SEduard Zingerman } 1481501b536SEduard Zingerman 1491501b536SEduard Zingerman if (scev->exprs_cnt == scev->exprs_cap) { 1501501b536SEduard Zingerman new_cap = scev->exprs_cap ? scev->exprs_cap * 2 : 256; 1511501b536SEduard Zingerman tmp = kvrealloc(scev->exprs, sizeof(struct expr) * new_cap, GFP_KERNEL_ACCOUNT); 1521501b536SEduard Zingerman if (!tmp) 1531501b536SEduard Zingerman return -ENOMEM; 1541501b536SEduard Zingerman scev->exprs = tmp; 1551501b536SEduard Zingerman scev->exprs_cap = new_cap; 1561501b536SEduard Zingerman } 1571501b536SEduard Zingerman 1581501b536SEduard Zingerman id = scev->exprs_cnt++; 1591501b536SEduard Zingerman scev->exprs[id] = e; 1601501b536SEduard Zingerman bucket->ids[bucket->cnt++] = id; 1611501b536SEduard Zingerman return id; 1621501b536SEduard Zingerman } 1631501b536SEduard Zingerman 1641501b536SEduard Zingerman static int expr2(struct scev *scev, u32 op, int a, int b) 1651501b536SEduard Zingerman { 1661501b536SEduard Zingerman if (a < 0) 1671501b536SEduard Zingerman return a; 1681501b536SEduard Zingerman if (b < 0) 1691501b536SEduard Zingerman return b; 1701501b536SEduard Zingerman return add_expr(scev, (struct expr){ .op = op, .params = {a, b} }); 1711501b536SEduard Zingerman } 1721501b536SEduard Zingerman 1731501b536SEduard Zingerman static int expr1(struct scev *scev, u32 op, int a) 1741501b536SEduard Zingerman { 1751501b536SEduard Zingerman if (a < 0) 1761501b536SEduard Zingerman return a; 1771501b536SEduard Zingerman return expr2(scev, op, a, 0); 1781501b536SEduard Zingerman } 1791501b536SEduard Zingerman 1801501b536SEduard Zingerman static int expr0(struct scev *scev, u32 op) 1811501b536SEduard Zingerman { 1821501b536SEduard Zingerman return expr2(scev, op, 0, 0); 1831501b536SEduard Zingerman } 1841501b536SEduard Zingerman 1851501b536SEduard Zingerman static int imm_expr(struct scev *scev, s64 value) 1861501b536SEduard Zingerman { 1871501b536SEduard Zingerman return add_expr(scev, (struct expr){ .op = IMM, .imm = value }); 1881501b536SEduard Zingerman } 1891501b536SEduard Zingerman 1901501b536SEduard Zingerman static bool same_exprs(struct scev *scev, int id_a, int id_b) 1911501b536SEduard Zingerman { 1921501b536SEduard Zingerman return id_a == id_b; 1931501b536SEduard Zingerman } 1941501b536SEduard Zingerman 1951501b536SEduard Zingerman static bool is_imm(struct scev *scev, int id, s64 *imm) 1961501b536SEduard Zingerman { 1971501b536SEduard Zingerman if (scev->exprs[id].op != IMM) 1981501b536SEduard Zingerman return false; 1991501b536SEduard Zingerman *imm = scev->exprs[id].imm; 2001501b536SEduard Zingerman return true; 2011501b536SEduard Zingerman } 2021501b536SEduard Zingerman 2031501b536SEduard Zingerman static bool is_op(struct scev *scev, int id, u32 op) 2041501b536SEduard Zingerman { 2051501b536SEduard Zingerman if (scev->exprs[id].op != op) 2061501b536SEduard Zingerman return false; 2071501b536SEduard Zingerman return true; 2081501b536SEduard Zingerman } 2091501b536SEduard Zingerman 2101501b536SEduard Zingerman static bool is_unop(struct scev *scev, enum expr_op op, int id, u32 *p0) 2111501b536SEduard Zingerman { 2121501b536SEduard Zingerman if (scev->exprs[id].op != op) 2131501b536SEduard Zingerman return false; 2141501b536SEduard Zingerman *p0 = scev->exprs[id].params[0]; 2151501b536SEduard Zingerman return true; 2161501b536SEduard Zingerman } 2171501b536SEduard Zingerman 2181501b536SEduard Zingerman static bool is_binop(struct scev *scev, enum expr_op op, int id, u32 *p0, u32 *p1) 2191501b536SEduard Zingerman { 2201501b536SEduard Zingerman if (scev->exprs[id].op != op) 2211501b536SEduard Zingerman return false; 2221501b536SEduard Zingerman *p0 = scev->exprs[id].params[0]; 2231501b536SEduard Zingerman *p1 = scev->exprs[id].params[1]; 2241501b536SEduard Zingerman return true; 2251501b536SEduard Zingerman } 2261501b536SEduard Zingerman 2271501b536SEduard Zingerman static bool is_reg(struct scev *scev, int id, u32 *reg) 2281501b536SEduard Zingerman { 2291501b536SEduard Zingerman return is_unop(scev, REG, id, reg); 2301501b536SEduard Zingerman } 2311501b536SEduard Zingerman 2321501b536SEduard Zingerman static bool is_add(struct scev *scev, int id, u32 *left, u32 *right) 2331501b536SEduard Zingerman { 2341501b536SEduard Zingerman return is_binop(scev, BPF_ADD, id, left, right); 2351501b536SEduard Zingerman } 2361501b536SEduard Zingerman 2371501b536SEduard Zingerman static bool is_zext32(struct scev *scev, int id, u32 *left) 2381501b536SEduard Zingerman { 2391501b536SEduard Zingerman return is_unop(scev, ZEXT32, id, left); 2401501b536SEduard Zingerman } 2411501b536SEduard Zingerman 2421501b536SEduard Zingerman static bool is_any(struct scev *scev, int id, u32 *left, u32 *right) 2431501b536SEduard Zingerman { 2441501b536SEduard Zingerman return is_binop(scev, ANY, id, left, right); 2451501b536SEduard Zingerman } 2461501b536SEduard Zingerman 2471501b536SEduard Zingerman static bool is_linear(struct scev *scev, int id, u32 *base, u32 *slope) 2481501b536SEduard Zingerman { 2491501b536SEduard Zingerman return is_binop(scev, LINEAR_SCEV, id, base, slope); 2501501b536SEduard Zingerman } 2511501b536SEduard Zingerman 252*32e96257SEduard Zingerman static bool is_linear_or_linear32(struct scev *scev, int id, u32 *base, u32 *slope, bool *zext32) 253*32e96257SEduard Zingerman { 254*32e96257SEduard Zingerman u32 t; 255*32e96257SEduard Zingerman 256*32e96257SEduard Zingerman *zext32 = is_zext32(scev, id, &t); 257*32e96257SEduard Zingerman return is_linear(scev, *zext32 ? t : id, base, slope); 258*32e96257SEduard Zingerman } 259*32e96257SEduard Zingerman 2601501b536SEduard Zingerman static bool is_opaque(struct scev *scev, int id) 2611501b536SEduard Zingerman { 2621501b536SEduard Zingerman return is_op(scev, id, OPAQUE); 2631501b536SEduard Zingerman } 2641501b536SEduard Zingerman 2651501b536SEduard Zingerman static void log_reg(struct bpf_verifier_env *env, u32 reg) 2661501b536SEduard Zingerman { 2671501b536SEduard Zingerman if (reg < MAX_BPF_REG) 2681501b536SEduard Zingerman bpf_log(&env->log, "r%d", reg); 2691501b536SEduard Zingerman else 2701501b536SEduard Zingerman bpf_log(&env->log, "*fp%d", (MAX_BPF_REG - reg - 1) * 8); 2711501b536SEduard Zingerman } 2721501b536SEduard Zingerman 2731501b536SEduard Zingerman static const char *op_str(u32 op) 2741501b536SEduard Zingerman { 2751501b536SEduard Zingerman switch (op) { 2761501b536SEduard Zingerman case BPF_ADD: return "+"; 2771501b536SEduard Zingerman case BPF_SUB: return "-"; 2781501b536SEduard Zingerman case BPF_MUL: return "*"; 2791501b536SEduard Zingerman case BPF_DIV: return "/"; 2801501b536SEduard Zingerman case SDIV: return "s/"; 2811501b536SEduard Zingerman case BPF_OR: return "|"; 2821501b536SEduard Zingerman case BPF_AND: return "&"; 2831501b536SEduard Zingerman case BPF_LSH: return "<<"; 2841501b536SEduard Zingerman case BPF_RSH: return ">>"; 2851501b536SEduard Zingerman case BPF_NEG: return "-"; 2861501b536SEduard Zingerman case BPF_MOD: return "%"; 2871501b536SEduard Zingerman case SMOD: return "s%"; 2881501b536SEduard Zingerman case BPF_XOR: return "^"; 2891501b536SEduard Zingerman case BPF_ARSH: return "s>>"; 2901501b536SEduard Zingerman case SEXT8: return "sext8"; 2911501b536SEduard Zingerman case SEXT16: return "sext16"; 2921501b536SEduard Zingerman case SEXT32: return "sext32"; 2931501b536SEduard Zingerman case ZEXT8: return "zext8"; 2941501b536SEduard Zingerman case ZEXT16: return "zext16"; 2951501b536SEduard Zingerman case ZEXT32: return "zext32"; 2961501b536SEduard Zingerman case BSWAP16: return "bswap16"; 2971501b536SEduard Zingerman case BSWAP32: return "bswap32"; 2981501b536SEduard Zingerman case BSWAP64: return "bswap64"; 2991501b536SEduard Zingerman case SPILL8: return "spill8"; 3001501b536SEduard Zingerman case SPILL16: return "spill16"; 3011501b536SEduard Zingerman case SPILL32: return "spill32"; 3021501b536SEduard Zingerman case ANY: return "any"; 3031501b536SEduard Zingerman case LINEAR_SCEV: return "linear"; 3041501b536SEduard Zingerman } 3051501b536SEduard Zingerman return NULL; 3061501b536SEduard Zingerman } 3071501b536SEduard Zingerman 3081501b536SEduard Zingerman static u32 op_params_num(u32 op) 3091501b536SEduard Zingerman { 3101501b536SEduard Zingerman switch (op) { 3111501b536SEduard Zingerman case BPF_ADD: 3121501b536SEduard Zingerman case BPF_SUB: 3131501b536SEduard Zingerman case BPF_MUL: 3141501b536SEduard Zingerman case BPF_DIV: 3151501b536SEduard Zingerman case BPF_MOD: 3161501b536SEduard Zingerman case BPF_OR: 3171501b536SEduard Zingerman case BPF_XOR: 3181501b536SEduard Zingerman case BPF_AND: 3191501b536SEduard Zingerman case BPF_LSH: 3201501b536SEduard Zingerman case BPF_RSH: 3211501b536SEduard Zingerman case BPF_ARSH: 3221501b536SEduard Zingerman case SDIV: 3231501b536SEduard Zingerman case SMOD: 3241501b536SEduard Zingerman case ANY: 3251501b536SEduard Zingerman case LINEAR_SCEV: 3261501b536SEduard Zingerman return 2; 3271501b536SEduard Zingerman case BPF_NEG: 3281501b536SEduard Zingerman case SEXT8: 3291501b536SEduard Zingerman case SEXT16: 3301501b536SEduard Zingerman case SEXT32: 3311501b536SEduard Zingerman case ZEXT8: 3321501b536SEduard Zingerman case ZEXT16: 3331501b536SEduard Zingerman case ZEXT32: 3341501b536SEduard Zingerman case BSWAP16: 3351501b536SEduard Zingerman case BSWAP32: 3361501b536SEduard Zingerman case BSWAP64: 3371501b536SEduard Zingerman case SPILL8: 3381501b536SEduard Zingerman case SPILL16: 3391501b536SEduard Zingerman case SPILL32: 3401501b536SEduard Zingerman return 1; 3411501b536SEduard Zingerman case REG: 3421501b536SEduard Zingerman case IMM: 3431501b536SEduard Zingerman case OPAQUE: 3441501b536SEduard Zingerman return 0; 3451501b536SEduard Zingerman default: 3461501b536SEduard Zingerman return 0; 3471501b536SEduard Zingerman } 3481501b536SEduard Zingerman } 3491501b536SEduard Zingerman 3501501b536SEduard Zingerman static bool expr_stack_push(struct scev *scev, u32 id) 3511501b536SEduard Zingerman { 3521501b536SEduard Zingerman if (scev->stack_sz >= EXPR_STACK_DEPTH) 3531501b536SEduard Zingerman return false; 3541501b536SEduard Zingerman scev->expr_stack[scev->stack_sz].id = id; 3551501b536SEduard Zingerman scev->expr_stack[scev->stack_sz].pre = true; 3561501b536SEduard Zingerman scev->expr_stack[scev->stack_sz].next_param = 0; 3571501b536SEduard Zingerman scev->stack_sz++; 3581501b536SEduard Zingerman return true; 3591501b536SEduard Zingerman } 3601501b536SEduard Zingerman 3611501b536SEduard Zingerman enum { 3621501b536SEduard Zingerman PRE = BIT(1), POST = BIT(2), DEPTH_LIMIT = BIT(3) 3631501b536SEduard Zingerman }; 3641501b536SEduard Zingerman 3651501b536SEduard Zingerman static bool expr_next(struct scev *scev, u32 *id, u32 *order) 3661501b536SEduard Zingerman { 3671501b536SEduard Zingerman struct expr_stack_elt *elt; 3681501b536SEduard Zingerman struct expr *expr; 3691501b536SEduard Zingerman u32 num_params; 3701501b536SEduard Zingerman 3711501b536SEduard Zingerman if (scev->stack_sz == 0) 3721501b536SEduard Zingerman return false; 3731501b536SEduard Zingerman 3741501b536SEduard Zingerman elt = &scev->expr_stack[scev->stack_sz - 1]; 3751501b536SEduard Zingerman *id = elt->id; 3761501b536SEduard Zingerman *order = 0; 3771501b536SEduard Zingerman expr = &scev->exprs[elt->id]; 3781501b536SEduard Zingerman num_params = op_params_num(expr->op); 3791501b536SEduard Zingerman if (elt->pre) { 3801501b536SEduard Zingerman elt->pre = false; 3811501b536SEduard Zingerman *order = PRE; 3821501b536SEduard Zingerman return true; 3831501b536SEduard Zingerman } 3841501b536SEduard Zingerman if (elt->next_param == num_params) { 3851501b536SEduard Zingerman *order = POST; 3861501b536SEduard Zingerman scev->stack_sz--; 3871501b536SEduard Zingerman return true; 3881501b536SEduard Zingerman } 3891501b536SEduard Zingerman if (scev->stack_sz == EXPR_STACK_DEPTH) { 3901501b536SEduard Zingerman *order = POST | DEPTH_LIMIT; 3911501b536SEduard Zingerman scev->stack_sz--; 3921501b536SEduard Zingerman return true; 3931501b536SEduard Zingerman } 3941501b536SEduard Zingerman expr_stack_push(scev, expr->params[elt->next_param]); 3951501b536SEduard Zingerman elt->next_param++; 3961501b536SEduard Zingerman return expr_next(scev, id, order); 3971501b536SEduard Zingerman } 3981501b536SEduard Zingerman 3991501b536SEduard Zingerman static void log_expr(struct bpf_verifier_env *env, u32 id) 4001501b536SEduard Zingerman { 4011501b536SEduard Zingerman struct bpf_verifier_log *log = &env->log; 4021501b536SEduard Zingerman struct scev *scev = env->scev; 4031501b536SEduard Zingerman struct expr *expr; 4041501b536SEduard Zingerman const char *str; 4051501b536SEduard Zingerman u32 order; 4061501b536SEduard Zingerman 4071501b536SEduard Zingerman scev->stack_sz = 0; 4081501b536SEduard Zingerman expr_stack_push(scev, id); 4091501b536SEduard Zingerman while (expr_next(scev, &id, &order)) { 4101501b536SEduard Zingerman if ((order & PRE) && scev->stack_sz > 1) 4111501b536SEduard Zingerman bpf_log(log, " "); 4121501b536SEduard Zingerman expr = &scev->exprs[id]; 4131501b536SEduard Zingerman switch (expr->op) { 4141501b536SEduard Zingerman case UNKNOWN: 4151501b536SEduard Zingerman if (order & PRE) 4161501b536SEduard Zingerman bpf_log(log, "?"); 4171501b536SEduard Zingerman break; 4181501b536SEduard Zingerman case OPAQUE: 4191501b536SEduard Zingerman if (order & PRE) 4201501b536SEduard Zingerman bpf_log(log, "_"); 4211501b536SEduard Zingerman break; 4221501b536SEduard Zingerman case REG: 4231501b536SEduard Zingerman if (order & PRE) 4241501b536SEduard Zingerman log_reg(env, expr->params[0]); 4251501b536SEduard Zingerman break; 4261501b536SEduard Zingerman case IMM: 4271501b536SEduard Zingerman if (order & PRE) 4281501b536SEduard Zingerman bpf_log(log, "%lld", expr->imm); 4291501b536SEduard Zingerman break; 4301501b536SEduard Zingerman default: 4311501b536SEduard Zingerman if (order & PRE) { 4321501b536SEduard Zingerman str = op_str(expr->op); 4331501b536SEduard Zingerman bpf_log(log, "("); 4341501b536SEduard Zingerman if (str) 4351501b536SEduard Zingerman bpf_log(log, "%s", str); 4361501b536SEduard Zingerman else 4371501b536SEduard Zingerman bpf_log(log, "bad-expr-op %x", expr->op); 4381501b536SEduard Zingerman } 4391501b536SEduard Zingerman if (order & DEPTH_LIMIT) 4401501b536SEduard Zingerman bpf_log(log, "..."); 4411501b536SEduard Zingerman if (order & POST) 4421501b536SEduard Zingerman bpf_log(log, ")"); 4431501b536SEduard Zingerman } 4441501b536SEduard Zingerman } 4451501b536SEduard Zingerman } 4461501b536SEduard Zingerman 4471501b536SEduard Zingerman static bool reg_alive_at(struct bpf_verifier_env *env, u32 reg, u32 insn_idx) 4481501b536SEduard Zingerman { 4491501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 4501501b536SEduard Zingerman u16 live_regs = aux[insn_idx].live_regs_before; 4511501b536SEduard Zingerman 4521501b536SEduard Zingerman return reg < MAX_BPF_REG 4531501b536SEduard Zingerman ? (BIT(reg) & live_regs) 4541501b536SEduard Zingerman : test_bit(reg - MAX_BPF_REG, aux[insn_idx].live_stack_before); 4551501b536SEduard Zingerman } 4561501b536SEduard Zingerman 4571501b536SEduard Zingerman static void print_env(struct bpf_verifier_env *env, struct env *e, u32 insn_idx) 4581501b536SEduard Zingerman { 4591501b536SEduard Zingerman struct bpf_verifier_log *log = &env->log; 4601501b536SEduard Zingerman struct scev *scev = env->scev; 4611501b536SEduard Zingerman bool printed_some = false; 4621501b536SEduard Zingerman bool is_self_scev; 4631501b536SEduard Zingerman bool is_self_reg; 4641501b536SEduard Zingerman int i, r; 4651501b536SEduard Zingerman 4661501b536SEduard Zingerman if (e->empty) { 4671501b536SEduard Zingerman bpf_log(log, " <empty>\n"); 4681501b536SEduard Zingerman return; 4691501b536SEduard Zingerman } 4701501b536SEduard Zingerman 4711501b536SEduard Zingerman for (i = 0; i < REGS_NUM; i++) { 4721501b536SEduard Zingerman if (!reg_alive_at(env, i, insn_idx)) 4731501b536SEduard Zingerman continue; 4741501b536SEduard Zingerman is_self_reg = is_reg(scev, e->reg2expr[i], &r) && i == r; 4751501b536SEduard Zingerman is_self_scev = is_reg(scev, e->reg2scev[i], &r) && i == r; 4761501b536SEduard Zingerman if (is_self_reg && is_self_scev) 4771501b536SEduard Zingerman continue; 4781501b536SEduard Zingerman printed_some = true; 4791501b536SEduard Zingerman bpf_log(log, " "); 4801501b536SEduard Zingerman log_reg(env, i); 4811501b536SEduard Zingerman bpf_log(log, "="); 4821501b536SEduard Zingerman log_expr(env, e->reg2expr[i]); 4831501b536SEduard Zingerman if (e->reg2expr[i] != UNKNOWN_EXPR_ID) { 4841501b536SEduard Zingerman bpf_log(log, " / "); 4851501b536SEduard Zingerman log_expr(env, e->reg2scev[i]); 4861501b536SEduard Zingerman } 4871501b536SEduard Zingerman bpf_log(log, "\n"); 4881501b536SEduard Zingerman } 4891501b536SEduard Zingerman if (!printed_some) 4901501b536SEduard Zingerman bpf_log(log, " <all regs unchanged>\n"); 4911501b536SEduard Zingerman } 4921501b536SEduard Zingerman static struct env *find_loop_env(struct scev *scev, int loop_header, int insn_idx) 4931501b536SEduard Zingerman { 4941501b536SEduard Zingerman struct insn_envs *envs = scev->envs[insn_idx]; 4951501b536SEduard Zingerman u32 i; 4961501b536SEduard Zingerman 4971501b536SEduard Zingerman if (!envs) 4981501b536SEduard Zingerman return NULL; 4991501b536SEduard Zingerman for (i = 0; i < envs->cnt; i++) 5001501b536SEduard Zingerman if (envs->entries[i].loop_header == loop_header) 5011501b536SEduard Zingerman return envs->entries[i].env; 5021501b536SEduard Zingerman return NULL; 5031501b536SEduard Zingerman } 5041501b536SEduard Zingerman 5051501b536SEduard Zingerman static struct env *find_header_env(struct scev *scev, int header) 5061501b536SEduard Zingerman { 5071501b536SEduard Zingerman return find_loop_env(scev, header, header); 5081501b536SEduard Zingerman } 5091501b536SEduard Zingerman 5101501b536SEduard Zingerman static struct env *get_loop_env(struct scev *scev, int loop_header, int insn_idx) 5111501b536SEduard Zingerman { 5121501b536SEduard Zingerman struct insn_envs *envs = scev->envs[insn_idx]; 5131501b536SEduard Zingerman u32 cnt = envs ? envs->cnt : 0; 5141501b536SEduard Zingerman struct insn_envs *tmp; 5151501b536SEduard Zingerman struct env *e; 5161501b536SEduard Zingerman 5171501b536SEduard Zingerman e = find_loop_env(scev, loop_header, insn_idx); 5181501b536SEduard Zingerman if (e) 5191501b536SEduard Zingerman return e; 5201501b536SEduard Zingerman 5211501b536SEduard Zingerman e = kzalloc(sizeof(*e), GFP_KERNEL_ACCOUNT); 5221501b536SEduard Zingerman if (!e) 5231501b536SEduard Zingerman return NULL; 5241501b536SEduard Zingerman 5251501b536SEduard Zingerman tmp = krealloc(envs, struct_size(envs, entries, cnt + 1), GFP_KERNEL_ACCOUNT); 5261501b536SEduard Zingerman if (!tmp) { 5271501b536SEduard Zingerman kfree(e); 5281501b536SEduard Zingerman return NULL; 5291501b536SEduard Zingerman } 5301501b536SEduard Zingerman 5311501b536SEduard Zingerman e->empty = true; 5321501b536SEduard Zingerman tmp->entries[cnt].loop_header = loop_header; 5331501b536SEduard Zingerman tmp->entries[cnt].env = e; 5341501b536SEduard Zingerman tmp->cnt = cnt + 1; 5351501b536SEduard Zingerman scev->envs[insn_idx] = tmp; 5361501b536SEduard Zingerman return e; 5371501b536SEduard Zingerman } 5381501b536SEduard Zingerman 5391501b536SEduard Zingerman static int replace_reg(struct scev *scev, struct env *e, u32 reg, int id) 5401501b536SEduard Zingerman { 5411501b536SEduard Zingerman if (id < 0) 5421501b536SEduard Zingerman return id; 5431501b536SEduard Zingerman e->reg2expr[reg] = id; 5441501b536SEduard Zingerman return 0; 5451501b536SEduard Zingerman } 5461501b536SEduard Zingerman 5471501b536SEduard Zingerman static int setup_initial_loop_env(struct bpf_verifier_env *env, struct env *e, int insn_idx) 5481501b536SEduard Zingerman { 5491501b536SEduard Zingerman struct scev *scev = env->scev; 5501501b536SEduard Zingerman int i, err; 5511501b536SEduard Zingerman 5521501b536SEduard Zingerman /* 5531501b536SEduard Zingerman * Initial assignments are of form rX -> rX are needed as seeds for subsequent 5541501b536SEduard Zingerman * work queue pop / transfer() calls. Because e->empty is true, the first backedge 5551501b536SEduard Zingerman * join() will overwrite the them. compute_header_scevs() accounts for register 5561501b536SEduard Zingerman * states at loop entry. 5571501b536SEduard Zingerman */ 5581501b536SEduard Zingerman for (i = 0; i < REGS_NUM; i++) { 5591501b536SEduard Zingerman err = replace_reg(scev, e, i, expr1(scev, REG, i)); 5601501b536SEduard Zingerman if (err) 5611501b536SEduard Zingerman return err; 5621501b536SEduard Zingerman } 5631501b536SEduard Zingerman return 0; 5641501b536SEduard Zingerman } 5651501b536SEduard Zingerman 5661501b536SEduard Zingerman static void forget_call_regs(struct env *e) 5671501b536SEduard Zingerman { 5681501b536SEduard Zingerman int i; 5691501b536SEduard Zingerman 5701501b536SEduard Zingerman for (i = BPF_REG_0; i <= BPF_REG_5; i++) 5711501b536SEduard Zingerman e->reg2expr[i] = UNKNOWN_EXPR_ID; 5721501b536SEduard Zingerman } 5731501b536SEduard Zingerman 5741501b536SEduard Zingerman static u32 spill_spi(struct bpf_insn *insn) 5751501b536SEduard Zingerman { 5761501b536SEduard Zingerman return -insn->off / BPF_REG_SIZE - 1; 5771501b536SEduard Zingerman } 5781501b536SEduard Zingerman 5791501b536SEduard Zingerman static u32 off_to_reg(struct bpf_insn *insn) 5801501b536SEduard Zingerman { 5811501b536SEduard Zingerman return spill_spi(insn) + MAX_BPF_REG; 5821501b536SEduard Zingerman } 5831501b536SEduard Zingerman 5841501b536SEduard Zingerman static bool is_spill_off(int off) 5851501b536SEduard Zingerman { 5861501b536SEduard Zingerman return off % BPF_REG_SIZE == 0 && 5871501b536SEduard Zingerman off <= -BPF_REG_SIZE && 5881501b536SEduard Zingerman off >= -MAX_BPF_STACK_JIT; 5891501b536SEduard Zingerman } 5901501b536SEduard Zingerman 5911501b536SEduard Zingerman static void mark_opaque(struct env *e, int off, int size) 5921501b536SEduard Zingerman { 5931501b536SEduard Zingerman int b, spi; 5941501b536SEduard Zingerman 5951501b536SEduard Zingerman for (b = off; b < off + size; b++) { 5961501b536SEduard Zingerman if (b >= 0 || b < -MAX_BPF_STACK_JIT) 5971501b536SEduard Zingerman continue; 5981501b536SEduard Zingerman spi = (-b - 1) / BPF_REG_SIZE; 5991501b536SEduard Zingerman e->reg2expr[MAX_BPF_REG + spi] = OPAQUE_EXPR_ID; 6001501b536SEduard Zingerman } 6011501b536SEduard Zingerman } 6021501b536SEduard Zingerman 6031501b536SEduard Zingerman static int mk_spill(struct scev *scev, u8 size, int id) 6041501b536SEduard Zingerman { 6051501b536SEduard Zingerman switch (size) { 6061501b536SEduard Zingerman case BPF_B: return expr1(scev, SPILL8, id); 6071501b536SEduard Zingerman case BPF_H: return expr1(scev, SPILL16, id); 6081501b536SEduard Zingerman case BPF_W: return expr1(scev, SPILL32, id); 6091501b536SEduard Zingerman case BPF_DW: return id; 6101501b536SEduard Zingerman } 6111501b536SEduard Zingerman return UNKNOWN_EXPR_ID; 6121501b536SEduard Zingerman } 6131501b536SEduard Zingerman 6141501b536SEduard Zingerman static int mk_fill(struct scev *scev, int id, u8 code) 6151501b536SEduard Zingerman { 6161501b536SEduard Zingerman bool sx = BPF_MODE(code) == BPF_MEMSX; 6171501b536SEduard Zingerman 6181501b536SEduard Zingerman #ifdef __BIG_ENDIAN 6191501b536SEduard Zingerman /* A narrow fill from a DW spill reads high bits on big-endian. */ 6201501b536SEduard Zingerman if (BPF_SIZE(code) != BPF_DW) 6211501b536SEduard Zingerman return OPAQUE_EXPR_ID; 6221501b536SEduard Zingerman #endif 6231501b536SEduard Zingerman 6241501b536SEduard Zingerman switch (BPF_SIZE(code)) { 6251501b536SEduard Zingerman case BPF_B: return expr1(scev, sx ? SEXT8 : ZEXT8, id); 6261501b536SEduard Zingerman case BPF_H: return expr1(scev, sx ? SEXT16 : ZEXT16, id); 6271501b536SEduard Zingerman case BPF_W: return expr1(scev, sx ? SEXT32 : ZEXT32, id); 6281501b536SEduard Zingerman case BPF_DW: return sx ? UNKNOWN_EXPR_ID : id; /* DW sign-extended load is invalid */ 6291501b536SEduard Zingerman } 6301501b536SEduard Zingerman return UNKNOWN_EXPR_ID; 6311501b536SEduard Zingerman } 6321501b536SEduard Zingerman 6331501b536SEduard Zingerman static int maybe_store_fp(struct scev *scev, struct env *e, struct bpf_insn *insn, int id) 6341501b536SEduard Zingerman { 6351501b536SEduard Zingerman u8 size = BPF_SIZE(insn->code); 6361501b536SEduard Zingerman 6371501b536SEduard Zingerman if (insn->dst_reg != BPF_REG_FP) 6381501b536SEduard Zingerman return 0; 6391501b536SEduard Zingerman if (is_spill_off(insn->off)) 6401501b536SEduard Zingerman return replace_reg(scev, e, off_to_reg(insn), mk_spill(scev, size, id)); 6411501b536SEduard Zingerman mark_opaque(e, insn->off, bpf_size_to_bytes(size)); 6421501b536SEduard Zingerman return 0; 6431501b536SEduard Zingerman } 6441501b536SEduard Zingerman 6451501b536SEduard Zingerman static int maybe_load_fp(struct scev *scev, struct env *e, struct bpf_insn *insn) 6461501b536SEduard Zingerman { 6471501b536SEduard Zingerman int id; 6481501b536SEduard Zingerman 6491501b536SEduard Zingerman if (insn->src_reg == BPF_REG_FP && is_spill_off(insn->off)) 6501501b536SEduard Zingerman id = mk_fill(scev, e->reg2expr[off_to_reg(insn)], insn->code); 6511501b536SEduard Zingerman else 6521501b536SEduard Zingerman id = OPAQUE_EXPR_ID; 6531501b536SEduard Zingerman return replace_reg(scev, e, insn->dst_reg, id); 6541501b536SEduard Zingerman } 6551501b536SEduard Zingerman 6561501b536SEduard Zingerman static int transfer(struct bpf_verifier_env *env, struct env *e, int idx) 6571501b536SEduard Zingerman { 6581501b536SEduard Zingerman const bool little_endian = htons(0x3412) == 0x1234; 6591501b536SEduard Zingerman struct bpf_insn *insn = &env->prog->insnsi[idx]; 6601501b536SEduard Zingerman struct scev *scev = env->scev; 6611501b536SEduard Zingerman u32 *reg2expr = e->reg2expr; 6621501b536SEduard Zingerman u8 class = BPF_CLASS(insn->code); 6631501b536SEduard Zingerman u8 x_or_k = BPF_SRC(insn->code); 6641501b536SEduard Zingerman u8 opcode = BPF_OP(insn->code); 6651501b536SEduard Zingerman u8 mode = BPF_MODE(insn->code); 6661501b536SEduard Zingerman u32 dst = insn->dst_reg; 6671501b536SEduard Zingerman u32 src = insn->src_reg; 6681501b536SEduard Zingerman u32 op, sext; 6691501b536SEduard Zingerman bool need_bswap; 6701501b536SEduard Zingerman int i, id; 6711501b536SEduard Zingerman s64 imm; 6721501b536SEduard Zingerman 6731501b536SEduard Zingerman switch (class) { 6741501b536SEduard Zingerman case BPF_ALU: 6751501b536SEduard Zingerman case BPF_ALU64: 6761501b536SEduard Zingerman switch (opcode) { 6771501b536SEduard Zingerman case BPF_MOV: 6781501b536SEduard Zingerman switch (insn->off) { 6791501b536SEduard Zingerman case 0: sext = 0; break; 6801501b536SEduard Zingerman case 8: sext = SEXT8; break; 6811501b536SEduard Zingerman case 16: sext = SEXT16; break; 6821501b536SEduard Zingerman case 32: sext = SEXT32; break; 6831501b536SEduard Zingerman default: 6841501b536SEduard Zingerman goto mark_dst_unknown; 6851501b536SEduard Zingerman } 6861501b536SEduard Zingerman 6871501b536SEduard Zingerman if (x_or_k == BPF_X && insn->imm == 0) 6881501b536SEduard Zingerman id = reg2expr[src]; 6891501b536SEduard Zingerman else if (x_or_k == BPF_K && src == 0 && insn->off == 0) 6901501b536SEduard Zingerman id = imm_expr(scev, insn->imm); 6911501b536SEduard Zingerman else 6921501b536SEduard Zingerman goto mark_dst_unknown; 6931501b536SEduard Zingerman 6941501b536SEduard Zingerman if (sext) 6951501b536SEduard Zingerman id = expr1(scev, sext, id); 6961501b536SEduard Zingerman if (class == BPF_ALU) 6971501b536SEduard Zingerman id = expr1(scev, ZEXT32, id); 6981501b536SEduard Zingerman 6991501b536SEduard Zingerman return replace_reg(scev, e, dst, id); 7001501b536SEduard Zingerman 7011501b536SEduard Zingerman case BPF_ADD: 7021501b536SEduard Zingerman case BPF_SUB: 7031501b536SEduard Zingerman case BPF_MUL: 7041501b536SEduard Zingerman case BPF_DIV: 7051501b536SEduard Zingerman case BPF_MOD: 7061501b536SEduard Zingerman case BPF_OR: 7071501b536SEduard Zingerman case BPF_XOR: 7081501b536SEduard Zingerman case BPF_AND: 7091501b536SEduard Zingerman case BPF_LSH: 7101501b536SEduard Zingerman case BPF_RSH: 7111501b536SEduard Zingerman case BPF_ARSH: 7121501b536SEduard Zingerman if (opcode == BPF_DIV && insn->off == 1) 7131501b536SEduard Zingerman op = SDIV; 7141501b536SEduard Zingerman else if (opcode == BPF_MOD && insn->off == 1) 7151501b536SEduard Zingerman op = SMOD; 7161501b536SEduard Zingerman else if (insn->off == 0) 7171501b536SEduard Zingerman op = opcode; 7181501b536SEduard Zingerman else 7191501b536SEduard Zingerman goto mark_dst_unknown; 7201501b536SEduard Zingerman 7211501b536SEduard Zingerman if (x_or_k == BPF_X && insn->imm == 0) 7221501b536SEduard Zingerman id = reg2expr[src]; 7231501b536SEduard Zingerman else if (x_or_k == BPF_K && src == 0) 7241501b536SEduard Zingerman id = imm_expr(scev, insn->imm); 7251501b536SEduard Zingerman else 7261501b536SEduard Zingerman goto mark_dst_unknown; 7271501b536SEduard Zingerman 7281501b536SEduard Zingerman id = expr2(scev, op, reg2expr[dst], id); 7291501b536SEduard Zingerman 7301501b536SEduard Zingerman if (class == BPF_ALU) 7311501b536SEduard Zingerman id = expr1(scev, ZEXT32, id); 7321501b536SEduard Zingerman 7331501b536SEduard Zingerman return replace_reg(scev, e, dst, id); 7341501b536SEduard Zingerman 7351501b536SEduard Zingerman case BPF_NEG: 7361501b536SEduard Zingerman if (src == 0 && insn->off == 0 && insn->imm == 0) 7371501b536SEduard Zingerman id = expr1(scev, BPF_NEG, reg2expr[dst]); 7381501b536SEduard Zingerman else 7391501b536SEduard Zingerman goto mark_dst_unknown; 7401501b536SEduard Zingerman 7411501b536SEduard Zingerman if (class == BPF_ALU) 7421501b536SEduard Zingerman id = expr1(scev, ZEXT32, id); 7431501b536SEduard Zingerman 7441501b536SEduard Zingerman return replace_reg(scev, e, dst, id); 7451501b536SEduard Zingerman 7461501b536SEduard Zingerman case BPF_END: 7471501b536SEduard Zingerman if (src != 0 || insn->off != 0 || (class == BPF_ALU64 && x_or_k != 0)) 7481501b536SEduard Zingerman goto mark_dst_unknown; 7491501b536SEduard Zingerman 7501501b536SEduard Zingerman need_bswap = class == BPF_ALU64 || ((x_or_k == BPF_TO_LE) != little_endian); 7511501b536SEduard Zingerman switch (insn->imm) { 7521501b536SEduard Zingerman case 16: op = need_bswap ? BSWAP16 : ZEXT16; break; 7531501b536SEduard Zingerman case 32: op = need_bswap ? BSWAP32 : ZEXT32; break; 7541501b536SEduard Zingerman case 64: op = need_bswap ? BSWAP64 : 0; break; 7551501b536SEduard Zingerman default: 7561501b536SEduard Zingerman goto mark_dst_unknown; 7571501b536SEduard Zingerman } 7581501b536SEduard Zingerman 7591501b536SEduard Zingerman id = reg2expr[dst]; 7601501b536SEduard Zingerman if (op) 7611501b536SEduard Zingerman id = expr1(scev, op, reg2expr[dst]); 7621501b536SEduard Zingerman 7631501b536SEduard Zingerman return replace_reg(scev, e, dst, id); 7641501b536SEduard Zingerman default: 7651501b536SEduard Zingerman goto mark_dst_unknown; 7661501b536SEduard Zingerman } 7671501b536SEduard Zingerman break; 7681501b536SEduard Zingerman case BPF_LDX: 7691501b536SEduard Zingerman switch (mode) { 7701501b536SEduard Zingerman case BPF_MEM: 7711501b536SEduard Zingerman case BPF_MEMSX: 7721501b536SEduard Zingerman return maybe_load_fp(scev, e, insn); 7731501b536SEduard Zingerman default: 7741501b536SEduard Zingerman goto mark_dst_unknown; 7751501b536SEduard Zingerman } 7761501b536SEduard Zingerman case BPF_STX: 7771501b536SEduard Zingerman switch (mode) { 7781501b536SEduard Zingerman case BPF_MEM: 7791501b536SEduard Zingerman return maybe_store_fp(scev, e, insn, reg2expr[src]); 7801501b536SEduard Zingerman case BPF_ATOMIC: 7811501b536SEduard Zingerman if (insn->imm == BPF_LOAD_ACQ) 7821501b536SEduard Zingerman return maybe_load_fp(scev, e, insn); 7831501b536SEduard Zingerman if (insn->imm == BPF_STORE_REL) { 7841501b536SEduard Zingerman return maybe_store_fp(scev, e, insn, reg2expr[src]); 7851501b536SEduard Zingerman } 7861501b536SEduard Zingerman /* 7871501b536SEduard Zingerman * verifier does not track other atomic ops precisely, 7881501b536SEduard Zingerman * hence mark the results as opaque. 7891501b536SEduard Zingerman */ 7901501b536SEduard Zingerman if (insn->dst_reg == BPF_REG_FP) 7911501b536SEduard Zingerman mark_opaque(e, insn->off, bpf_size_to_bytes(BPF_SIZE(insn->code))); 7921501b536SEduard Zingerman if (insn->imm == BPF_CMPXCHG) 7931501b536SEduard Zingerman return replace_reg(scev, e, BPF_REG_0, OPAQUE_EXPR_ID); 7941501b536SEduard Zingerman if (insn->imm & BPF_FETCH) 7951501b536SEduard Zingerman return replace_reg(scev, e, src, OPAQUE_EXPR_ID); 7961501b536SEduard Zingerman break; 7971501b536SEduard Zingerman } 7981501b536SEduard Zingerman break; 7991501b536SEduard Zingerman case BPF_ST: 8001501b536SEduard Zingerman if (insn->dst_reg == BPF_REG_FP) { 8011501b536SEduard Zingerman id = imm_expr(scev, insn->imm); 8021501b536SEduard Zingerman if (id < 0) 8031501b536SEduard Zingerman return id; 8041501b536SEduard Zingerman return maybe_store_fp(scev, e, insn, id); 8051501b536SEduard Zingerman } 8061501b536SEduard Zingerman break; 8071501b536SEduard Zingerman case BPF_JMP: 8081501b536SEduard Zingerman case BPF_JMP32: 8091501b536SEduard Zingerman if (opcode == BPF_CALL) 8101501b536SEduard Zingerman forget_call_regs(e); 8111501b536SEduard Zingerman /* for non-CALL there are no changes in register states */ 8121501b536SEduard Zingerman break; 8131501b536SEduard Zingerman case BPF_LD: 8141501b536SEduard Zingerman switch (mode) { 8151501b536SEduard Zingerman case BPF_IMM: 8161501b536SEduard Zingerman /* rX = imm ll */ 8171501b536SEduard Zingerman if (BPF_SIZE(insn->code) == BPF_DW && insn->src_reg == 0) { 8181501b536SEduard Zingerman imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm; 8191501b536SEduard Zingerman return replace_reg(scev, e, dst, imm_expr(scev, imm)); 8201501b536SEduard Zingerman } 8211501b536SEduard Zingerman /* map, map value, BTF id, function */ 8221501b536SEduard Zingerman if (BPF_SIZE(insn->code) == BPF_DW) 8231501b536SEduard Zingerman return replace_reg(scev, e, dst, OPAQUE_EXPR_ID); 8241501b536SEduard Zingerman goto mark_dst_unknown; 8251501b536SEduard Zingerman case BPF_ABS: 8261501b536SEduard Zingerman case BPF_IND: 8271501b536SEduard Zingerman forget_call_regs(e); 8281501b536SEduard Zingerman break; 8291501b536SEduard Zingerman default: 8301501b536SEduard Zingerman goto mark_dst_unknown; 8311501b536SEduard Zingerman } 8321501b536SEduard Zingerman break; 8331501b536SEduard Zingerman default: 8341501b536SEduard Zingerman /* unknown instruction, nuke state */ 8351501b536SEduard Zingerman for (i = 0; i < REGS_NUM; i++) 8361501b536SEduard Zingerman reg2expr[i] = UNKNOWN_EXPR_ID; 8371501b536SEduard Zingerman break; 8381501b536SEduard Zingerman } 8391501b536SEduard Zingerman return 0; 8401501b536SEduard Zingerman 8411501b536SEduard Zingerman mark_dst_unknown: 8421501b536SEduard Zingerman reg2expr[dst] = UNKNOWN_EXPR_ID; 8431501b536SEduard Zingerman return 0; 8441501b536SEduard Zingerman } 8451501b536SEduard Zingerman 8461501b536SEduard Zingerman /* 8471501b536SEduard Zingerman * Construct minimal 'ANY' expression by traversing 'a' and 'b' 8481501b536SEduard Zingerman * and accumulating non-duplicated non-ANY entries. 8491501b536SEduard Zingerman */ 8501501b536SEduard Zingerman static int mk_any(struct scev *scev, int a, int b) 8511501b536SEduard Zingerman { 8521501b536SEduard Zingerman struct expr_stack_elt *elt; 8531501b536SEduard Zingerman struct expr *expr; 8541501b536SEduard Zingerman u32 i, j, ids_buf_sz; 8551501b536SEduard Zingerman u32 roots[2] = {a, b}; 8561501b536SEduard Zingerman int id; 8571501b536SEduard Zingerman 8581501b536SEduard Zingerman if (a < 0) 8591501b536SEduard Zingerman return a; 8601501b536SEduard Zingerman if (b < 0) 8611501b536SEduard Zingerman return b; 8621501b536SEduard Zingerman ids_buf_sz = 0; 8631501b536SEduard Zingerman for (i = 0; i < ARRAY_SIZE(roots); i++) { 8641501b536SEduard Zingerman scev->stack_sz = 0; 8651501b536SEduard Zingerman expr_stack_push(scev, roots[i]); 8661501b536SEduard Zingerman while (scev->stack_sz) { 8671501b536SEduard Zingerman elt = &scev->expr_stack[--scev->stack_sz]; 8681501b536SEduard Zingerman id = elt->id; 8691501b536SEduard Zingerman expr = &scev->exprs[elt->id]; 8701501b536SEduard Zingerman if (expr->op == ANY) { 8711501b536SEduard Zingerman if (!expr_stack_push(scev, expr->params[1]) || 8721501b536SEduard Zingerman !expr_stack_push(scev, expr->params[0])) 8731501b536SEduard Zingerman return UNKNOWN_EXPR_ID; 8741501b536SEduard Zingerman } else { 8751501b536SEduard Zingerman for (j = 0; j < ids_buf_sz; j++) { 8761501b536SEduard Zingerman if (same_exprs(scev, scev->ids_buf[j], id)) 8771501b536SEduard Zingerman goto next; 8781501b536SEduard Zingerman } 8791501b536SEduard Zingerman if (ids_buf_sz == ARRAY_SIZE(scev->ids_buf)) 8801501b536SEduard Zingerman return UNKNOWN_EXPR_ID; 8811501b536SEduard Zingerman scev->ids_buf[ids_buf_sz++] = id; 8821501b536SEduard Zingerman } 8831501b536SEduard Zingerman next:; 8841501b536SEduard Zingerman } 8851501b536SEduard Zingerman } 8861501b536SEduard Zingerman if (WARN_ON(ids_buf_sz == 0)) 8871501b536SEduard Zingerman return -EFAULT; 8881501b536SEduard Zingerman id = scev->ids_buf[0]; 8891501b536SEduard Zingerman for (i = 1; i < ids_buf_sz; i++) { 8901501b536SEduard Zingerman id = expr2(scev, ANY, id, scev->ids_buf[i]); 8911501b536SEduard Zingerman if (id < 0) 8921501b536SEduard Zingerman return id; 8931501b536SEduard Zingerman } 8941501b536SEduard Zingerman return id; 8951501b536SEduard Zingerman } 8961501b536SEduard Zingerman 8971501b536SEduard Zingerman static int join(struct scev *scev, struct env *acc, struct env *cur) 8981501b536SEduard Zingerman { 8991501b536SEduard Zingerman int i, id; 9001501b536SEduard Zingerman 9011501b536SEduard Zingerman if (acc->empty) { 9021501b536SEduard Zingerman memcpy(acc, cur, sizeof(*acc)); 9031501b536SEduard Zingerman acc->empty = false; 9041501b536SEduard Zingerman return 0; 9051501b536SEduard Zingerman } 9061501b536SEduard Zingerman 9071501b536SEduard Zingerman for (i = 0; i < REGS_NUM; i++) { 9081501b536SEduard Zingerman if (!same_exprs(scev, acc->reg2expr[i], cur->reg2expr[i])) { 9091501b536SEduard Zingerman id = mk_any(scev, acc->reg2expr[i], cur->reg2expr[i]); 9101501b536SEduard Zingerman if (id < 0) 9111501b536SEduard Zingerman return id; 9121501b536SEduard Zingerman acc->reg2expr[i] = id; 9131501b536SEduard Zingerman } 9141501b536SEduard Zingerman } 9151501b536SEduard Zingerman return 0; 9161501b536SEduard Zingerman } 9171501b536SEduard Zingerman 9181501b536SEduard Zingerman /* Mark any register modified in 'e' as unknown in 'acc'. */ 9191501b536SEduard Zingerman static void forget_modified_regs(struct scev *scev, struct env *acc, struct env *e) 9201501b536SEduard Zingerman { 9211501b536SEduard Zingerman u32 i, reg; 9221501b536SEduard Zingerman 9231501b536SEduard Zingerman for (i = 0; i < REGS_NUM; i++) { 9241501b536SEduard Zingerman if (e && is_reg(scev, e->reg2expr[i], ®) && reg == i) 9251501b536SEduard Zingerman continue; 9261501b536SEduard Zingerman acc->reg2expr[i] = UNKNOWN_EXPR_ID; 9271501b536SEduard Zingerman } 9281501b536SEduard Zingerman } 9291501b536SEduard Zingerman 9301501b536SEduard Zingerman /* For a loop H at `header`, mark any register modified as a result of H execution as unknown. */ 9311501b536SEduard Zingerman static void forget_non_invariants(struct bpf_verifier_env *env, struct env *acc, int header) 9321501b536SEduard Zingerman { 9331501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 9341501b536SEduard Zingerman struct bpf_loop *loop = aux[header].loop; 9351501b536SEduard Zingerman struct scev *scev = env->scev; 9361501b536SEduard Zingerman int i, idx, h; 9371501b536SEduard Zingerman 9381501b536SEduard Zingerman acc->empty = false; 9391501b536SEduard Zingerman forget_modified_regs(scev, acc, find_header_env(scev, header)); 9401501b536SEduard Zingerman for (i = 0; i < loop->exits_cnt; i++) { 9411501b536SEduard Zingerman idx = loop->exits[i].from; 9421501b536SEduard Zingerman h = bpf_loop_at_index(env, idx); 9431501b536SEduard Zingerman /* 9441501b536SEduard Zingerman * In order to account for situations like this: 9451501b536SEduard Zingerman * 9461501b536SEduard Zingerman * header: 9471501b536SEduard Zingerman * do { 9481501b536SEduard Zingerman * saved = rX; 9491501b536SEduard Zingerman * rX = -1000; 9501501b536SEduard Zingerman * do { // H 9511501b536SEduard Zingerman * if (random()) 9521501b536SEduard Zingerman * goto out; // E 9531501b536SEduard Zingerman * } while (inner_again); 9541501b536SEduard Zingerman * rX = saved; 9551501b536SEduard Zingerman * } while (outer_again); 9561501b536SEduard Zingerman * out: 9571501b536SEduard Zingerman * 9581501b536SEduard Zingerman * For exits originating in nested loops check that rX is invariant 9591501b536SEduard Zingerman * both at the header (H) and at exit (E). 9601501b536SEduard Zingerman */ 9611501b536SEduard Zingerman while (h != header) { 9621501b536SEduard Zingerman forget_modified_regs(scev, acc, find_header_env(scev, h)); 9631501b536SEduard Zingerman forget_modified_regs(scev, acc, find_loop_env(scev, h, idx)); 9641501b536SEduard Zingerman idx = h; 9651501b536SEduard Zingerman h = aux[h].loop_header; 9661501b536SEduard Zingerman } 9671501b536SEduard Zingerman /* 9681501b536SEduard Zingerman * For exits originating at the same loop the header is already accounted for, 9691501b536SEduard Zingerman * check only the exit environment. 9701501b536SEduard Zingerman */ 9711501b536SEduard Zingerman forget_modified_regs(scev, acc, find_loop_env(scev, header, idx)); 9721501b536SEduard Zingerman } 9731501b536SEduard Zingerman } 9741501b536SEduard Zingerman 9751501b536SEduard Zingerman /* Order worklist in reverse post-order. */ 9761501b536SEduard Zingerman static bool reverse_postorder_less(const void *a, const void *b, void *arg) 9771501b536SEduard Zingerman { 9781501b536SEduard Zingerman const int *rank = arg; 9791501b536SEduard Zingerman 9801501b536SEduard Zingerman return rank[*(const int *)a] > rank[*(const int *)b]; 9811501b536SEduard Zingerman } 9821501b536SEduard Zingerman 9831501b536SEduard Zingerman static const struct min_heap_callbacks worklist_cb = { 9841501b536SEduard Zingerman .less = reverse_postorder_less, 9851501b536SEduard Zingerman }; 9861501b536SEduard Zingerman 9871501b536SEduard Zingerman static int worklist_push(struct bpf_verifier_env *env, int loop_header, int idx) 9881501b536SEduard Zingerman { 9891501b536SEduard Zingerman struct scev *scev = env->scev; 9901501b536SEduard Zingerman struct scev_worklist *worklist = &scev->worklist; 9911501b536SEduard Zingerman u32 tag = (u32)loop_header + 1; 9921501b536SEduard Zingerman 9931501b536SEduard Zingerman if (scev->discovered[idx] == tag) 9941501b536SEduard Zingerman return 0; 9951501b536SEduard Zingerman 9961501b536SEduard Zingerman if (min_heap_full_inline(worklist)) { 9971501b536SEduard Zingerman size_t size = worklist->size ? worklist->size * 2 : 16; 9981501b536SEduard Zingerman int *data; 9991501b536SEduard Zingerman 10001501b536SEduard Zingerman data = kvrealloc(worklist->data, array_size(size, sizeof(*data)), 10011501b536SEduard Zingerman GFP_KERNEL_ACCOUNT); 10021501b536SEduard Zingerman if (!data) 10031501b536SEduard Zingerman return -ENOMEM; 10041501b536SEduard Zingerman worklist->data = data; 10051501b536SEduard Zingerman worklist->size = size; 10061501b536SEduard Zingerman } 10071501b536SEduard Zingerman if (!min_heap_push_inline(worklist, &idx, &worklist_cb, env->cfg.postorder_nums)) 10081501b536SEduard Zingerman return -EFAULT; 10091501b536SEduard Zingerman 10101501b536SEduard Zingerman scev->discovered[idx] = tag; 10111501b536SEduard Zingerman return 0; 10121501b536SEduard Zingerman } 10131501b536SEduard Zingerman 10141501b536SEduard Zingerman static bool reg_alive_at_succ(struct bpf_verifier_env *env, u32 r, u32 insn_idx) 10151501b536SEduard Zingerman { 10161501b536SEduard Zingerman struct bpf_iarray *succ = bpf_insn_successors(env, insn_idx); 10171501b536SEduard Zingerman u32 i; 10181501b536SEduard Zingerman 10191501b536SEduard Zingerman for (i = 0; i < succ->cnt; i++) 10201501b536SEduard Zingerman if (reg_alive_at(env, r, succ->items[i])) 10211501b536SEduard Zingerman return true; 10221501b536SEduard Zingerman return false; 10231501b536SEduard Zingerman } 10241501b536SEduard Zingerman 10251501b536SEduard Zingerman enum changes_at { 10261501b536SEduard Zingerman LOG_AT_TRANSFER, 10271501b536SEduard Zingerman LOG_AT_JOIN, 10281501b536SEduard Zingerman }; 10291501b536SEduard Zingerman 10301501b536SEduard Zingerman static void log_env_changes(struct bpf_verifier_env *env, enum changes_at at, 10311501b536SEduard Zingerman struct env *old, struct env *new, int insn_idx) 10321501b536SEduard Zingerman { 10331501b536SEduard Zingerman struct bpf_verifier_log *log = &env->log; 10341501b536SEduard Zingerman struct scev *scev = env->scev; 10351501b536SEduard Zingerman u64 null_pos = log->end_pos; 10361501b536SEduard Zingerman u32 old_id, new_id, regno; 10371501b536SEduard Zingerman bool any_changes = false; 10381501b536SEduard Zingerman bool is_self_scev; 10391501b536SEduard Zingerman u64 len; 10401501b536SEduard Zingerman int r; 10411501b536SEduard Zingerman 10421501b536SEduard Zingerman bpf_log(log, "%s %4d: ", at == LOG_AT_TRANSFER ? "t" : "j", insn_idx); 10431501b536SEduard Zingerman bpf_verbose_insn(env, &env->prog->insnsi[insn_idx]); 10441501b536SEduard Zingerman len = log->end_pos - null_pos; 10451501b536SEduard Zingerman bpf_log(log, "%*s", max(37 - (int)len, 1), " "); 10461501b536SEduard Zingerman bpf_log(log, " ; "); 10471501b536SEduard Zingerman for (r = 0; r < REGS_NUM; r++) { 10481501b536SEduard Zingerman old_id = old->reg2expr[r]; 10491501b536SEduard Zingerman new_id = new->reg2expr[r]; 10501501b536SEduard Zingerman if (at == LOG_AT_TRANSFER && !reg_alive_at_succ(env, r, insn_idx)) 10511501b536SEduard Zingerman continue; 10521501b536SEduard Zingerman if (at == LOG_AT_JOIN && !reg_alive_at(env, r, insn_idx)) 10531501b536SEduard Zingerman continue; 10541501b536SEduard Zingerman if (same_exprs(scev, old_id, new_id)) 10551501b536SEduard Zingerman continue; 10561501b536SEduard Zingerman is_self_scev = is_reg(scev, new_id, ®no) && r == regno; 10571501b536SEduard Zingerman if (old->empty && is_self_scev) 10581501b536SEduard Zingerman continue; 10591501b536SEduard Zingerman if (any_changes) 10601501b536SEduard Zingerman bpf_log(log, ", "); 10611501b536SEduard Zingerman log_reg(env, r); 10621501b536SEduard Zingerman bpf_log(log, " "); 10631501b536SEduard Zingerman log_expr(env, old_id); 10641501b536SEduard Zingerman bpf_log(log, " -> "); 10651501b536SEduard Zingerman log_expr(env, new_id); 10661501b536SEduard Zingerman any_changes = true; 10671501b536SEduard Zingerman } 10681501b536SEduard Zingerman if (old->empty && !any_changes) 10691501b536SEduard Zingerman bpf_log(log, "<empty join>"); 10701501b536SEduard Zingerman bpf_log(log, "\n"); 10711501b536SEduard Zingerman if (!old->empty && !any_changes) 10721501b536SEduard Zingerman bpf_vlog_reset(log, null_pos); 10731501b536SEduard Zingerman } 10741501b536SEduard Zingerman 10751501b536SEduard Zingerman static bool is_probe_read_helper(u32 func_id) 10761501b536SEduard Zingerman { 10771501b536SEduard Zingerman return func_id == BPF_FUNC_probe_read || 10781501b536SEduard Zingerman func_id == BPF_FUNC_probe_read_kernel || 10791501b536SEduard Zingerman func_id == BPF_FUNC_probe_read_user || 10801501b536SEduard Zingerman func_id == BPF_FUNC_probe_read_str || 10811501b536SEduard Zingerman func_id == BPF_FUNC_probe_read_kernel_str || 10821501b536SEduard Zingerman func_id == BPF_FUNC_probe_read_user_str; 10831501b536SEduard Zingerman } 10841501b536SEduard Zingerman 10851501b536SEduard Zingerman /* 10861501b536SEduard Zingerman * If instruction is an indirect write to stack, invalidate SCEVs for spi's 10871501b536SEduard Zingerman * that this instruction can touch. 10881501b536SEduard Zingerman */ 10891501b536SEduard Zingerman static void reset_scevs_at_indirect_writes(struct bpf_verifier_env *env, struct env *cur_env, int idx) 10901501b536SEduard Zingerman { 10911501b536SEduard Zingerman struct bpf_insn *insn = &env->prog->insnsi[idx]; 10921501b536SEduard Zingerman struct scev *scev = env->scev; 10931501b536SEduard Zingerman u8 class = BPF_CLASS(insn->code); 10941501b536SEduard Zingerman const unsigned long *mask; 10951501b536SEduard Zingerman u32 spi, reg; 10961501b536SEduard Zingerman bool opaque; 10971501b536SEduard Zingerman 10981501b536SEduard Zingerman /* Direct fp stores are fine. */ 10991501b536SEduard Zingerman if ((class == BPF_ST || class == BPF_STX) && insn->dst_reg == BPF_REG_FP) 11001501b536SEduard Zingerman return; 11011501b536SEduard Zingerman 11021501b536SEduard Zingerman mask = bpf_may_write_mask(env, idx); 11031501b536SEduard Zingerman opaque = bpf_helper_call(insn) && is_probe_read_helper(insn->imm); 11041501b536SEduard Zingerman for_each_set_bit(spi, mask, MAX_BPF_STACK_SLOTS) { 11051501b536SEduard Zingerman reg = MAX_BPF_REG + spi; 11061501b536SEduard Zingerman if (cur_env->reg2expr[reg] == UNKNOWN_EXPR_ID) 11071501b536SEduard Zingerman continue; 11081501b536SEduard Zingerman replace_reg(scev, cur_env, reg, opaque ? OPAQUE_EXPR_ID : UNKNOWN_EXPR_ID); 11091501b536SEduard Zingerman } 11101501b536SEduard Zingerman } 11111501b536SEduard Zingerman 1112088a5477SEduard Zingerman /* 1113088a5477SEduard Zingerman * Collect loop-entry registers referenced by expr 'id', best effort. 1114088a5477SEduard Zingerman * DEPTH_LIMIT may leave dependencies unrecorded. This mask only avoids 1115088a5477SEduard Zingerman * widening that would lose stack-access precision; missing dependencies 1116088a5477SEduard Zingerman * may cause false rejections, but this is not a soundness issue. 1117088a5477SEduard Zingerman */ 1118088a5477SEduard Zingerman static void or_expr_regs(struct bpf_verifier_env *env, u32 id, unsigned long *mask) 1119088a5477SEduard Zingerman { 1120088a5477SEduard Zingerman struct scev *scev = env->scev; 1121088a5477SEduard Zingerman u32 order; 1122088a5477SEduard Zingerman 1123088a5477SEduard Zingerman scev->stack_sz = 0; 1124088a5477SEduard Zingerman expr_stack_push(scev, id); 1125088a5477SEduard Zingerman while (expr_next(scev, &id, &order)) { 1126088a5477SEduard Zingerman if ((order & PRE) && scev->exprs[id].op == REG) 1127088a5477SEduard Zingerman __set_bit(scev->exprs[id].params[0], mask); 1128088a5477SEduard Zingerman } 1129088a5477SEduard Zingerman } 1130088a5477SEduard Zingerman 1131088a5477SEduard Zingerman /* Mask of argument registers (R1..R5) a call at 'idx' passes by register. */ 1132088a5477SEduard Zingerman static u16 call_params_mask(struct bpf_verifier_env *env, int idx) 1133088a5477SEduard Zingerman { 1134088a5477SEduard Zingerman struct bpf_insn *insn = &env->prog->insnsi[idx]; 1135088a5477SEduard Zingerman struct bpf_call_summary cs; 1136088a5477SEduard Zingerman int n = bpf_get_call_summary(env, insn, &cs) ? cs.arg_slot_cnt : MAX_BPF_FUNC_REG_ARGS; 1137088a5477SEduard Zingerman 1138088a5477SEduard Zingerman return n ? GENMASK(BPF_REG_1 + n - 1, BPF_REG_1) : 0; 1139088a5477SEduard Zingerman } 1140088a5477SEduard Zingerman 1141088a5477SEduard Zingerman /* 1142088a5477SEduard Zingerman * For instructions like: 1143088a5477SEduard Zingerman * - *(u64 *)(rBase + off) = rX 1144088a5477SEduard Zingerman * - rX = *(u64 *)(rBase + off) 1145088a5477SEduard Zingerman * - calls that construct objects on stack (e.g. dynptr_from_mem(rBase, ...)) 1146088a5477SEduard Zingerman * When 'rBase' can be a stack pointer and is derived from some registers Rs 1147088a5477SEduard Zingerman * defined at loop entry, record Rs into 'mask'. 1148088a5477SEduard Zingerman */ 1149088a5477SEduard Zingerman static void collect_store_base_regs(struct bpf_verifier_env *env, 1150088a5477SEduard Zingerman struct env *cur_env, int idx, unsigned long *mask) 1151088a5477SEduard Zingerman { 1152088a5477SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 1153088a5477SEduard Zingerman struct bpf_insn *insn = &env->prog->insnsi[idx]; 1154088a5477SEduard Zingerman u8 class = BPF_CLASS(insn->code); 1155088a5477SEduard Zingerman u8 size = BPF_SIZE(insn->code); 1156088a5477SEduard Zingerman u16 base_regs = 0; 1157088a5477SEduard Zingerman u32 r; 1158088a5477SEduard Zingerman 1159088a5477SEduard Zingerman if (size == BPF_W || size == BPF_DW) { 1160088a5477SEduard Zingerman if ((class == BPF_STX || class == BPF_ST) && insn->dst_reg != BPF_REG_FP) 1161088a5477SEduard Zingerman base_regs |= BIT(insn->dst_reg); 1162088a5477SEduard Zingerman else if (class == BPF_LDX && insn->src_reg != BPF_REG_FP) 1163088a5477SEduard Zingerman base_regs |= BIT(insn->src_reg); 1164088a5477SEduard Zingerman } 1165088a5477SEduard Zingerman 1166088a5477SEduard Zingerman if (class == BPF_JMP && BPF_OP(insn->code) == BPF_CALL && 1167088a5477SEduard Zingerman bpf_needs_fixed_stack_off(env, idx)) 1168088a5477SEduard Zingerman base_regs |= call_params_mask(env, idx); 1169088a5477SEduard Zingerman 1170088a5477SEduard Zingerman base_regs &= aux[idx].stack_ptrs; 1171088a5477SEduard Zingerman for (r = 0; r < MAX_BPF_REG; r++) 1172088a5477SEduard Zingerman if (base_regs & BIT(r)) 1173088a5477SEduard Zingerman or_expr_regs(env, cur_env->reg2expr[r], mask); 1174088a5477SEduard Zingerman } 1175088a5477SEduard Zingerman 11761501b536SEduard Zingerman /* Find the topmost loop header containing idx inside cur_header, or -1 if none. */ 11771501b536SEduard Zingerman static int topmost_nested_loop(struct bpf_verifier_env *env, int idx, int cur_header) 11781501b536SEduard Zingerman { 11791501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 11801501b536SEduard Zingerman int header; 11811501b536SEduard Zingerman 11821501b536SEduard Zingerman for (header = bpf_loop_at_index(env, idx); header >= 0; 11831501b536SEduard Zingerman header = aux[header].loop_header) 11841501b536SEduard Zingerman if (aux[header].loop_header == cur_header) 11851501b536SEduard Zingerman return header; 11861501b536SEduard Zingerman 11871501b536SEduard Zingerman return -1; 11881501b536SEduard Zingerman } 11891501b536SEduard Zingerman 11901501b536SEduard Zingerman /* 11911501b536SEduard Zingerman * Join cur_env into the successor's environment and schedule their traversal. 11921501b536SEduard Zingerman * Map successors in nested loops to their topmost nested header. 11931501b536SEduard Zingerman * Ignore successors outside the current loop and its nested loops. 11941501b536SEduard Zingerman */ 11951501b536SEduard Zingerman static int join_successor(struct bpf_verifier_env *env, int cur_header, int succ_idx, 11961501b536SEduard Zingerman struct env *old_env, struct env *cur_env) 11971501b536SEduard Zingerman { 11981501b536SEduard Zingerman bool log_level2 = env->log.level & BPF_LOG_LEVEL2; 11991501b536SEduard Zingerman struct scev *scev = env->scev; 12001501b536SEduard Zingerman int err, nested_header; 12011501b536SEduard Zingerman struct env *succ_env; 12021501b536SEduard Zingerman 12031501b536SEduard Zingerman /* 12041501b536SEduard Zingerman * There are several possibilities for a successor: 12051501b536SEduard Zingerman * - succ_idx can be a part of a loop outside of the cur_header's loop, 12061501b536SEduard Zingerman * such edges are ignored. 12071501b536SEduard Zingerman * - succ_idx can be a part of the same loop as cur_header, 12081501b536SEduard Zingerman * for such edges succ_idx environment is updated: 12091501b536SEduard Zingerman * e[succ_idx] = join(e[succ_idx], cur_env) 12101501b536SEduard Zingerman * - succ_idx can be a part of some loop inner to cur_header, 12111501b536SEduard Zingerman * in such a case there exists some loop header H, 12121501b536SEduard Zingerman * such that H.loop_header == cur_header 12131501b536SEduard Zingerman * and H is the same as succ_idx's loop or contains it. 12141501b536SEduard Zingerman */ 12151501b536SEduard Zingerman if (bpf_loop_at_index(env, succ_idx) != cur_header) { 12161501b536SEduard Zingerman /* 12171501b536SEduard Zingerman * topmost_nested_loop() either finds H or returns -1, 12181501b536SEduard Zingerman * in case if succ_idx is a part of a loop outer to cur_header. 12191501b536SEduard Zingerman */ 12201501b536SEduard Zingerman nested_header = topmost_nested_loop(env, succ_idx, cur_header); 12211501b536SEduard Zingerman if (nested_header < 0) 12221501b536SEduard Zingerman return 0; 12231501b536SEduard Zingerman succ_idx = nested_header; 12241501b536SEduard Zingerman } 12251501b536SEduard Zingerman succ_env = get_loop_env(scev, cur_header, succ_idx); 12261501b536SEduard Zingerman if (!succ_env) 12271501b536SEduard Zingerman return -ENOMEM; 12281501b536SEduard Zingerman if (log_level2) 12291501b536SEduard Zingerman memcpy(old_env, succ_env, sizeof(*old_env)); 12301501b536SEduard Zingerman err = join(scev, succ_env, cur_env); 12311501b536SEduard Zingerman if (err) 12321501b536SEduard Zingerman return err; 12331501b536SEduard Zingerman err = worklist_push(env, cur_header, succ_idx); 12341501b536SEduard Zingerman if (err) 12351501b536SEduard Zingerman return err; 12361501b536SEduard Zingerman if (log_level2) 12371501b536SEduard Zingerman log_env_changes(env, LOG_AT_JOIN, old_env, succ_env, succ_idx); 12381501b536SEduard Zingerman return 0; 12391501b536SEduard Zingerman } 12401501b536SEduard Zingerman 12411501b536SEduard Zingerman /* Unsupported loops get only an unknown header environment. */ 12421501b536SEduard Zingerman static bool can_compute_loop_scev(const struct bpf_loop *loop) 12431501b536SEduard Zingerman { 12441501b536SEduard Zingerman return !loop->irreducible && !loop->exits_overflow; 12451501b536SEduard Zingerman } 12461501b536SEduard Zingerman 12471501b536SEduard Zingerman static int compute_scev_for_loop(struct bpf_verifier_env *env, int cur_header) 12481501b536SEduard Zingerman { 12491501b536SEduard Zingerman struct scev_worklist *worklist = &env->scev->worklist; 12501501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 12511501b536SEduard Zingerman struct bpf_loop *cur_loop = aux[cur_header].loop; 12521501b536SEduard Zingerman struct env *header_env; 12531501b536SEduard Zingerman struct scev *scev = env->scev; 12541501b536SEduard Zingerman struct bpf_loop *nested_loop; 12551501b536SEduard Zingerman struct env *cur_env = NULL; 12561501b536SEduard Zingerman struct env *old_env = NULL; 12571501b536SEduard Zingerman struct bpf_iarray *succ; 12581501b536SEduard Zingerman bool log_level2 = env->log.level & BPF_LOG_LEVEL2; 12591501b536SEduard Zingerman int s, i, err, idx, succ_idx; 1260088a5477SEduard Zingerman u32 r; 12611501b536SEduard Zingerman 12621501b536SEduard Zingerman if (log_level2) 12631501b536SEduard Zingerman bpf_log(&env->log, "Computing SCEV for loop at %d:\n", cur_header); 12641501b536SEduard Zingerman 12651501b536SEduard Zingerman /* 12661501b536SEduard Zingerman * For irreducible loops, and for loops nesting a loop with a truncated 12671501b536SEduard Zingerman * exit list, just assume that everything is clobbered for now. 12681501b536SEduard Zingerman */ 12691501b536SEduard Zingerman if (!can_compute_loop_scev(cur_loop)) { 12701501b536SEduard Zingerman header_env = get_loop_env(scev, cur_header, cur_header); 12711501b536SEduard Zingerman if (!header_env) 12721501b536SEduard Zingerman return -ENOMEM; 12731501b536SEduard Zingerman /* The freshly allocated environment has all expressions unknown. */ 1274088a5477SEduard Zingerman bitmap_fill(cur_loop->store_base_regs, REGS_NUM); 12751501b536SEduard Zingerman header_env->empty = false; 12761501b536SEduard Zingerman return 0; 12771501b536SEduard Zingerman } 12781501b536SEduard Zingerman 12791501b536SEduard Zingerman cur_env = kzalloc(sizeof(*cur_env), GFP_KERNEL_ACCOUNT); 12801501b536SEduard Zingerman if (!cur_env) 12811501b536SEduard Zingerman goto nomem; 12821501b536SEduard Zingerman if (log_level2) { 12831501b536SEduard Zingerman old_env = kzalloc(sizeof(*old_env), GFP_KERNEL_ACCOUNT); 12841501b536SEduard Zingerman if (!old_env) 12851501b536SEduard Zingerman goto nomem; 12861501b536SEduard Zingerman } 12871501b536SEduard Zingerman header_env = get_loop_env(scev, cur_header, cur_header); 12881501b536SEduard Zingerman if (!header_env) 12891501b536SEduard Zingerman goto nomem; 12901501b536SEduard Zingerman err = setup_initial_loop_env(env, header_env, cur_header); 12911501b536SEduard Zingerman if (err) 12921501b536SEduard Zingerman goto out; 12931501b536SEduard Zingerman err = worklist_push(env, cur_header, cur_header); 12941501b536SEduard Zingerman if (err) 12951501b536SEduard Zingerman goto out; 12961501b536SEduard Zingerman 12971501b536SEduard Zingerman while (worklist->nr) { 12981501b536SEduard Zingerman idx = *min_heap_peek_inline(worklist); 12991501b536SEduard Zingerman min_heap_pop_inline(worklist, &worklist_cb, env->cfg.postorder_nums); 13001501b536SEduard Zingerman 13011501b536SEduard Zingerman /* join_successor() maps nested-loop entries to their representative header. */ 13021501b536SEduard Zingerman nested_loop = idx != cur_header ? aux[idx].loop : NULL; 13031501b536SEduard Zingerman memcpy(cur_env, find_loop_env(scev, cur_header, idx), sizeof(*cur_env)); 13041501b536SEduard Zingerman if (nested_loop) { 13051501b536SEduard Zingerman /* 13061501b536SEduard Zingerman * Process nested loop as a single instruction by 13071501b536SEduard Zingerman * forgetting anything non-invariant in the nested loop 13081501b536SEduard Zingerman */ 13091501b536SEduard Zingerman if (log_level2) 13101501b536SEduard Zingerman memcpy(old_env, cur_env, sizeof(*old_env)); 1311088a5477SEduard Zingerman /* Pull the nested loop's stack-store base dependencies up. */ 1312088a5477SEduard Zingerman for_each_set_bit(r, nested_loop->store_base_regs, BPF_SCEV_REGS_NUM) 1313088a5477SEduard Zingerman or_expr_regs(env, cur_env->reg2expr[r], cur_loop->store_base_regs); 13141501b536SEduard Zingerman forget_non_invariants(env, cur_env, idx); 13151501b536SEduard Zingerman if (log_level2) 13161501b536SEduard Zingerman log_env_changes(env, LOG_AT_TRANSFER, old_env, cur_env, idx); 13171501b536SEduard Zingerman /* 13181501b536SEduard Zingerman * Treat nested loop exits as successors, 13191501b536SEduard Zingerman * join cur_env into successor's envs. 13201501b536SEduard Zingerman */ 13211501b536SEduard Zingerman for (i = 0; i < nested_loop->exits_cnt; i++) { 13221501b536SEduard Zingerman s = nested_loop->exits[i].to; 13231501b536SEduard Zingerman err = join_successor(env, cur_header, s, old_env, cur_env); 13241501b536SEduard Zingerman if (err) 13251501b536SEduard Zingerman goto out; 13261501b536SEduard Zingerman } 13271501b536SEduard Zingerman } else { 13281501b536SEduard Zingerman /* 13291501b536SEduard Zingerman * Iterate instructions within a single basic block 13301501b536SEduard Zingerman * starting at 'idx' mutating 'cur_env'. 13311501b536SEduard Zingerman */ 13321501b536SEduard Zingerman for (;;) { 13331501b536SEduard Zingerman if (log_level2) 13341501b536SEduard Zingerman memcpy(old_env, cur_env, sizeof(*old_env)); 1335088a5477SEduard Zingerman collect_store_base_regs(env, cur_env, idx, cur_loop->store_base_regs); 13361501b536SEduard Zingerman err = transfer(env, cur_env, idx); 13371501b536SEduard Zingerman if (err) 13381501b536SEduard Zingerman goto out; 13391501b536SEduard Zingerman reset_scevs_at_indirect_writes(env, cur_env, idx); 13401501b536SEduard Zingerman if (log_level2) 13411501b536SEduard Zingerman log_env_changes(env, LOG_AT_TRANSFER, old_env, cur_env, idx); 13421501b536SEduard Zingerman succ = bpf_insn_successors(env, idx); 13431501b536SEduard Zingerman if (succ->cnt != 1) 13441501b536SEduard Zingerman break; 13451501b536SEduard Zingerman succ_idx = succ->items[0]; 13461501b536SEduard Zingerman if (aux[idx].bb_end || aux[succ_idx].need_scev || 13471501b536SEduard Zingerman bpf_loop_at_index(env, succ_idx) != cur_header) 13481501b536SEduard Zingerman break; 13491501b536SEduard Zingerman idx = succ_idx; 13501501b536SEduard Zingerman } 13511501b536SEduard Zingerman /* Join cur_env into basic block successor's envs. */ 13521501b536SEduard Zingerman iarray_for_each(s, succ) { 13531501b536SEduard Zingerman err = join_successor(env, cur_header, s, old_env, cur_env); 13541501b536SEduard Zingerman if (err) 13551501b536SEduard Zingerman goto out; 13561501b536SEduard Zingerman } 13571501b536SEduard Zingerman } 13581501b536SEduard Zingerman } 13591501b536SEduard Zingerman 13601501b536SEduard Zingerman err = 0; 13611501b536SEduard Zingerman out: 13621501b536SEduard Zingerman kfree(cur_env); 13631501b536SEduard Zingerman kfree(old_env); 13641501b536SEduard Zingerman return err; 13651501b536SEduard Zingerman nomem: 13661501b536SEduard Zingerman err = -ENOMEM; 13671501b536SEduard Zingerman goto out; 13681501b536SEduard Zingerman } 13691501b536SEduard Zingerman 13701501b536SEduard Zingerman static void mark_latches(struct bpf_verifier_env *env) 13711501b536SEduard Zingerman { 13721501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 13731501b536SEduard Zingerman struct bpf_loop *loop; 13741501b536SEduard Zingerman int len = env->prog->len; 13751501b536SEduard Zingerman int i, j, k, from; 13761501b536SEduard Zingerman 13771501b536SEduard Zingerman for (i = 0; i < len; i++) { 13781501b536SEduard Zingerman loop = aux[i].loop; 13791501b536SEduard Zingerman if (!loop) 13801501b536SEduard Zingerman continue; 13811501b536SEduard Zingerman aux[i].need_scev = true; 13821501b536SEduard Zingerman if (!can_compute_loop_scev(loop)) 13831501b536SEduard Zingerman continue; 13841501b536SEduard Zingerman /* 13851501b536SEduard Zingerman * Make sure to only set .need_scev for exits and latches 13861501b536SEduard Zingerman * belonging to the loop at `i`. If can_compute_loop_scev() 13871501b536SEduard Zingerman * fails for a loop, it should hide it's instructions from 13881501b536SEduard Zingerman * compute_insn_scevs(). 13891501b536SEduard Zingerman */ 13901501b536SEduard Zingerman for (j = 0; j < loop->backedges_cnt; j++) 13911501b536SEduard Zingerman for (k = 0; k < loop->backedges[j].latches_cnt; k++) 13921501b536SEduard Zingerman aux[loop->backedges[j].latches[k]].need_scev = true; 13931501b536SEduard Zingerman for (j = 0; j < loop->exits_cnt; j++) { 13941501b536SEduard Zingerman from = loop->exits[j].from; 13951501b536SEduard Zingerman if (bpf_loop_at_index(env, from) == i) 13961501b536SEduard Zingerman aux[from].need_scev = true; 13971501b536SEduard Zingerman } 13981501b536SEduard Zingerman } 13991501b536SEduard Zingerman } 14001501b536SEduard Zingerman 14011501b536SEduard Zingerman static bool is_any_imm_reg_opaque(struct scev *scev, u32 id) 14021501b536SEduard Zingerman { 14031501b536SEduard Zingerman u32 l, r, reg, order; 14041501b536SEduard Zingerman s64 imm; 14051501b536SEduard Zingerman 14061501b536SEduard Zingerman scev->stack_sz = 0; 14071501b536SEduard Zingerman expr_stack_push(scev, id); 14081501b536SEduard Zingerman while (expr_next(scev, &id, &order)) { 14091501b536SEduard Zingerman if (order & DEPTH_LIMIT) 14101501b536SEduard Zingerman return false; 14111501b536SEduard Zingerman if (!(order & PRE) || 14121501b536SEduard Zingerman is_imm(scev, id, &imm) || 14131501b536SEduard Zingerman is_reg(scev, id, ®) || 14141501b536SEduard Zingerman is_opaque(scev, id) || 14151501b536SEduard Zingerman is_any(scev, id, &l, &r)) 14161501b536SEduard Zingerman continue; 14171501b536SEduard Zingerman return false; 14181501b536SEduard Zingerman } 14191501b536SEduard Zingerman return true; 14201501b536SEduard Zingerman } 14211501b536SEduard Zingerman 14221501b536SEduard Zingerman /* 14231501b536SEduard Zingerman * Can implement explicit stack version, but it is harder to read. 14241501b536SEduard Zingerman * Stick with recursive version for now. 14251501b536SEduard Zingerman */ 14261501b536SEduard Zingerman static int transform_expr_once(struct scev *scev, u32 lvl, u32 root, void *priv, 14271501b536SEduard Zingerman int (*fn)(struct scev *scev, u32 id, void *priv)) 14281501b536SEduard Zingerman { 14291501b536SEduard Zingerman struct expr expr; 14301501b536SEduard Zingerman int p0, p1, id; 14311501b536SEduard Zingerman 14321501b536SEduard Zingerman if (lvl >= EXPR_STACK_DEPTH) 14331501b536SEduard Zingerman return UNKNOWN_EXPR_ID; 14341501b536SEduard Zingerman 14351501b536SEduard Zingerman expr = scev->exprs[root]; /* snapshot the expr before potential realloc */ 14361501b536SEduard Zingerman switch (op_params_num(expr.op)) { 14371501b536SEduard Zingerman case 0: 14381501b536SEduard Zingerman id = root; 14391501b536SEduard Zingerman break; 14401501b536SEduard Zingerman case 1: 14411501b536SEduard Zingerman p0 = transform_expr_once(scev, lvl + 1, expr.params[0], priv, fn); 14421501b536SEduard Zingerman id = expr1(scev, expr.op, p0); 14431501b536SEduard Zingerman break; 14441501b536SEduard Zingerman case 2: 14451501b536SEduard Zingerman p0 = transform_expr_once(scev, lvl + 1, expr.params[0], priv, fn); 14461501b536SEduard Zingerman p1 = transform_expr_once(scev, lvl + 1, expr.params[1], priv, fn); 14471501b536SEduard Zingerman id = expr2(scev, expr.op, p0, p1); 14481501b536SEduard Zingerman break; 14491501b536SEduard Zingerman } 14501501b536SEduard Zingerman return id < 0 ? id : fn(scev, id, priv); 14511501b536SEduard Zingerman } 14521501b536SEduard Zingerman 14531501b536SEduard Zingerman static int transform_expr(struct scev *scev, u32 root, void *priv, 14541501b536SEduard Zingerman int (*fn)(struct scev *scev, u32 id, void *priv)) 14551501b536SEduard Zingerman { 14561501b536SEduard Zingerman int i = 0, id_old, id_new = root; 14571501b536SEduard Zingerman 14581501b536SEduard Zingerman do { 14591501b536SEduard Zingerman /* 14601501b536SEduard Zingerman * The depth limit is somewhat arbitrary and is essentially a failsafe. 14611501b536SEduard Zingerman * oscillation should not really happen. Still, it seems harsh to error out. 14621501b536SEduard Zingerman */ 14631501b536SEduard Zingerman if (i++ == 4 * EXPR_STACK_DEPTH) 14641501b536SEduard Zingerman return UNKNOWN_EXPR_ID; 14651501b536SEduard Zingerman id_old = id_new; 14661501b536SEduard Zingerman id_new = transform_expr_once(scev, 0, id_old, priv, fn); 14671501b536SEduard Zingerman if (id_new < 0) 14681501b536SEduard Zingerman return id_new; 14691501b536SEduard Zingerman } while (id_old != id_new); 14701501b536SEduard Zingerman return id_new; 14711501b536SEduard Zingerman } 14721501b536SEduard Zingerman 14731501b536SEduard Zingerman static int simplify(struct scev *scev, u32 id, void *priv) 14741501b536SEduard Zingerman { 1475*32e96257SEduard Zingerman int a, b, l, r, t, base, slope; 14761501b536SEduard Zingerman s64 imm1, imm2; 14771501b536SEduard Zingerman 14781501b536SEduard Zingerman /* (+ (linear base slope) imm) -> (linear (+ base imm) slope) */ 14791501b536SEduard Zingerman if (is_add(scev, id, &l, &r) && 14801501b536SEduard Zingerman is_linear(scev, l, &base, &slope) && 14811501b536SEduard Zingerman is_imm(scev, r, &imm1)) 14821501b536SEduard Zingerman return expr2(scev, LINEAR_SCEV, expr2(scev, BPF_ADD, base, r), slope); 14831501b536SEduard Zingerman 14841501b536SEduard Zingerman /* (+ imm imm) -> imm */ 14851501b536SEduard Zingerman if (is_add(scev, id, &l, &r) && 14861501b536SEduard Zingerman is_imm(scev, l, &imm1) && 14871501b536SEduard Zingerman is_imm(scev, r, &imm2)) 14881501b536SEduard Zingerman return imm_expr(scev, imm1 + imm2); 14891501b536SEduard Zingerman 14901501b536SEduard Zingerman /* (zext32 (imm X)) -> (imm (u32)X) */ 14911501b536SEduard Zingerman if (is_zext32(scev, id, &l) && is_imm(scev, l, &imm1)) 14921501b536SEduard Zingerman return imm_expr(scev, (u64)(u32)imm1); 14931501b536SEduard Zingerman 1494*32e96257SEduard Zingerman /* 1495*32e96257SEduard Zingerman * (zext32 (+ (zext32 $a) $b)) -> (zext32 (+ $a $b)) 1496*32e96257SEduard Zingerman * (zext32 (+ $a (zext32 $b))) -> (zext32 (+ $a $b)) 1497*32e96257SEduard Zingerman */ 1498*32e96257SEduard Zingerman if ((is_zext32(scev, id, &t) && is_add(scev, t, &l, &b) && is_zext32(scev, l, &a)) || 1499*32e96257SEduard Zingerman (is_zext32(scev, id, &t) && is_add(scev, t, &a, &r) && is_zext32(scev, r, &b))) { 1500*32e96257SEduard Zingerman t = expr2(scev, BPF_ADD, a, b); 1501*32e96257SEduard Zingerman t = expr1(scev, ZEXT32, t); 1502*32e96257SEduard Zingerman return t; 1503*32e96257SEduard Zingerman } 1504*32e96257SEduard Zingerman 15051501b536SEduard Zingerman return id; 15061501b536SEduard Zingerman } 15071501b536SEduard Zingerman 15081501b536SEduard Zingerman static int compute_header_scevs(struct bpf_verifier_env *env, struct env *header_env) 15091501b536SEduard Zingerman { 15101501b536SEduard Zingerman struct scev *scev = env->scev; 1511*32e96257SEduard Zingerman int l, r, t, id, ra, rb, ra_expr; 15121501b536SEduard Zingerman s64 imm; 15131501b536SEduard Zingerman 15141501b536SEduard Zingerman /* 15151501b536SEduard Zingerman * Note: 15161501b536SEduard Zingerman * reg2expr[ra] describes a change in rA's value over a single loop iteration. 15171501b536SEduard Zingerman * It does not account for rA's entry value. However, the SCEV constructed for rA 15181501b536SEduard Zingerman * must include an additional rA entry edge. For example: 15191501b536SEduard Zingerman * 15201501b536SEduard Zingerman * r0 = ..., r1 = 7 15211501b536SEduard Zingerman * l: if r0 == 10 goto e // reg2expr[r1] == (imm 42) => reg2scev[r1] == (any r1 42) 15221501b536SEduard Zingerman * r0 += 1 15231501b536SEduard Zingerman * r1 = 42 15241501b536SEduard Zingerman * goto l 15251501b536SEduard Zingerman * e: 15261501b536SEduard Zingerman * ... at exit r1 is in {7,42} ... 15271501b536SEduard Zingerman */ 15281501b536SEduard Zingerman for (ra = 0; ra < REGS_NUM; ra++) { 15291501b536SEduard Zingerman ra_expr = transform_expr(scev, header_env->reg2expr[ra], NULL, simplify); 15301501b536SEduard Zingerman if (ra_expr < 0) 15311501b536SEduard Zingerman return ra_expr; 15321501b536SEduard Zingerman header_env->reg2expr[ra] = ra_expr; 15331501b536SEduard Zingerman /* rA = (+ rA IMM) -> (linear rA IMM) */ 15341501b536SEduard Zingerman if (is_add(scev, ra_expr, &l, &r) && 15351501b536SEduard Zingerman is_reg(scev, l, &rb) && 15361501b536SEduard Zingerman is_imm(scev, r, &imm) && 15371501b536SEduard Zingerman ra == rb) { 15381501b536SEduard Zingerman id = expr2(scev, LINEAR_SCEV, l, r); 15391501b536SEduard Zingerman if (id < 0) 15401501b536SEduard Zingerman return id; 15411501b536SEduard Zingerman header_env->reg2scev[ra] = id; 15421501b536SEduard Zingerman continue; 15431501b536SEduard Zingerman } 1544*32e96257SEduard Zingerman /* rA = (is_zext32 (+ rA IMM)) -> (is_zext32 (linear rA IMM)) */ 1545*32e96257SEduard Zingerman if (is_zext32(scev, ra_expr, &t) && 1546*32e96257SEduard Zingerman is_add(scev, t, &l, &r) && 1547*32e96257SEduard Zingerman is_reg(scev, l, &rb) && 1548*32e96257SEduard Zingerman is_imm(scev, r, &imm) && 1549*32e96257SEduard Zingerman ra == rb) { 1550*32e96257SEduard Zingerman id = expr2(scev, LINEAR_SCEV, l, r); 1551*32e96257SEduard Zingerman id = expr1(scev, ZEXT32, id); 1552*32e96257SEduard Zingerman if (id < 0) 1553*32e96257SEduard Zingerman return id; 1554*32e96257SEduard Zingerman header_env->reg2scev[ra] = id; 1555*32e96257SEduard Zingerman continue; 1556*32e96257SEduard Zingerman } 15571501b536SEduard Zingerman /* rA = rA -> rA*/ 15581501b536SEduard Zingerman if (is_reg(scev, ra_expr, &rb) && ra == rb) { 15591501b536SEduard Zingerman header_env->reg2scev[ra] = ra_expr; 15601501b536SEduard Zingerman continue; 15611501b536SEduard Zingerman } 15621501b536SEduard Zingerman /* rA = (any 1 2 3 4 ...) -> (any rA 1 2 3 4 ...) */ 15631501b536SEduard Zingerman if (is_any_imm_reg_opaque(scev, ra_expr)) { 15641501b536SEduard Zingerman id = mk_any(scev, expr1(scev, REG, ra), ra_expr); 15651501b536SEduard Zingerman if (id < 0) 15661501b536SEduard Zingerman return id; 15671501b536SEduard Zingerman header_env->reg2scev[ra] = id; 15681501b536SEduard Zingerman continue; 15691501b536SEduard Zingerman } 15701501b536SEduard Zingerman 15711501b536SEduard Zingerman } 15721501b536SEduard Zingerman return 0; 15731501b536SEduard Zingerman } 15741501b536SEduard Zingerman static int instantiate_header_scevs(struct scev *scev, u32 id, void *priv) 15751501b536SEduard Zingerman { 15761501b536SEduard Zingerman u32 reg, *reg2scev = priv; 15771501b536SEduard Zingerman 15781501b536SEduard Zingerman /* (reg r) -> ... equation at header ... */ 15791501b536SEduard Zingerman if (is_reg(scev, id, ®)) 15801501b536SEduard Zingerman return reg2scev[reg]; 15811501b536SEduard Zingerman /* keep expression shapes */ 15821501b536SEduard Zingerman return id; 15831501b536SEduard Zingerman } 15841501b536SEduard Zingerman 15851501b536SEduard Zingerman static int compute_insn_scevs(struct bpf_verifier_env *env, struct env *eheader, struct env *einsn) 15861501b536SEduard Zingerman { 15871501b536SEduard Zingerman struct scev *scev = env->scev; 15881501b536SEduard Zingerman int id, reg; 15891501b536SEduard Zingerman 15901501b536SEduard Zingerman for (reg = 0; reg < REGS_NUM; reg++) { 15911501b536SEduard Zingerman id = einsn->reg2expr[reg]; 15921501b536SEduard Zingerman id = transform_expr_once(scev, 0, id, eheader->reg2scev, instantiate_header_scevs); 15931501b536SEduard Zingerman if (id < 0) 15941501b536SEduard Zingerman return id; 15951501b536SEduard Zingerman id = transform_expr(scev, id, NULL, simplify); 15961501b536SEduard Zingerman if (id < 0) 15971501b536SEduard Zingerman return id; 15981501b536SEduard Zingerman einsn->reg2scev[reg] = id; 15991501b536SEduard Zingerman } 16001501b536SEduard Zingerman 16011501b536SEduard Zingerman return 0; 16021501b536SEduard Zingerman } 16031501b536SEduard Zingerman 16041501b536SEduard Zingerman static int log_scevs(struct bpf_verifier_env *env) 16051501b536SEduard Zingerman { 16061501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 16071501b536SEduard Zingerman struct bpf_verifier_log *log = &env->log; 16081501b536SEduard Zingerman struct env *header_env, *latch_env; 16091501b536SEduard Zingerman struct scev *scev = env->scev; 16101501b536SEduard Zingerman struct bpf_loop *loop; 16111501b536SEduard Zingerman int i, j, k, len, latch; 16121501b536SEduard Zingerman 16131501b536SEduard Zingerman len = env->prog->len; 16141501b536SEduard Zingerman for (i = 0; i < len; i++) { 16151501b536SEduard Zingerman loop = aux[i].loop; 16161501b536SEduard Zingerman if (!loop) 16171501b536SEduard Zingerman continue; 16181501b536SEduard Zingerman header_env = find_header_env(scev, i); 16191501b536SEduard Zingerman bpf_log(log, "scev at header %d:\n", i); 16201501b536SEduard Zingerman print_env(env, header_env, i); 16211501b536SEduard Zingerman if (!can_compute_loop_scev(loop)) 16221501b536SEduard Zingerman continue; 16231501b536SEduard Zingerman for (j = 0; j < loop->backedges_cnt; j++) { 16241501b536SEduard Zingerman for (k = 0; k < loop->backedges[j].latches_cnt; k++) { 16251501b536SEduard Zingerman latch = loop->backedges[j].latches[k]; 16261501b536SEduard Zingerman bpf_log(log, " scev at %s %d:\n", k ? "exit" : "latch", latch); 16271501b536SEduard Zingerman latch_env = find_loop_env(scev, i, latch); 16281501b536SEduard Zingerman if (verifier_bug_if(!latch_env, env, "i=%d, latch=%d", i, latch)) 16291501b536SEduard Zingerman return -EFAULT; 16301501b536SEduard Zingerman print_env(env, latch_env, latch); 16311501b536SEduard Zingerman } 16321501b536SEduard Zingerman } 16331501b536SEduard Zingerman } 16341501b536SEduard Zingerman return 0; 16351501b536SEduard Zingerman } 16361501b536SEduard Zingerman 16371501b536SEduard Zingerman int bpf_compute_scev(struct bpf_verifier_env *env) 16381501b536SEduard Zingerman { 16391501b536SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 16401501b536SEduard Zingerman struct scev *scev = env->scev; 16411501b536SEduard Zingerman int *postorder = env->cfg.insn_postorder; 16421501b536SEduard Zingerman int cnt = env->cfg.cur_postorder; 16431501b536SEduard Zingerman int i, idx, err, header; 16441501b536SEduard Zingerman 16451501b536SEduard Zingerman mark_latches(env); 16461501b536SEduard Zingerman /* 16471501b536SEduard Zingerman * Visit loop headers in postorder, to guarantee that scevs 16481501b536SEduard Zingerman * for innermost loops are computed first. 16491501b536SEduard Zingerman */ 16501501b536SEduard Zingerman for (i = 0; i < cnt; i++) { 16511501b536SEduard Zingerman idx = postorder[i]; 16521501b536SEduard Zingerman if (!aux[idx].loop) 16531501b536SEduard Zingerman continue; 16541501b536SEduard Zingerman err = compute_scev_for_loop(env, idx); 16551501b536SEduard Zingerman if (err) 16561501b536SEduard Zingerman return err; 16571501b536SEduard Zingerman } 16581501b536SEduard Zingerman 16591501b536SEduard Zingerman /* 16601501b536SEduard Zingerman * Compute scevs from exprs collected on a previous step. Iterate instructions in 16611501b536SEduard Zingerman * reverse post-order so that each loop header is processed before instructions 16621501b536SEduard Zingerman * reachable from it. 16631501b536SEduard Zingerman */ 16641501b536SEduard Zingerman for (i = cnt - 1; i >= 0; i--) { 16651501b536SEduard Zingerman idx = postorder[i]; 16661501b536SEduard Zingerman if (!aux[idx].need_scev) 16671501b536SEduard Zingerman continue; 16681501b536SEduard Zingerman header = bpf_loop_at_index(env, idx); 16691501b536SEduard Zingerman err = aux[idx].loop 16701501b536SEduard Zingerman ? compute_header_scevs(env, find_header_env(scev, header)) 16711501b536SEduard Zingerman : compute_insn_scevs(env, 16721501b536SEduard Zingerman find_header_env(scev, header), 16731501b536SEduard Zingerman find_loop_env(scev, header, idx)); 16741501b536SEduard Zingerman if (err) 16751501b536SEduard Zingerman return err; 16761501b536SEduard Zingerman } 16771501b536SEduard Zingerman 16781501b536SEduard Zingerman for (i = 0; i < env->prog->len; i++) 16791501b536SEduard Zingerman if (aux[i].loop) 16801501b536SEduard Zingerman aux[i].prune_point = true; 16811501b536SEduard Zingerman 16821501b536SEduard Zingerman if (env->log.level & BPF_LOG_LEVEL2) { 16831501b536SEduard Zingerman err = log_scevs(env); 16841501b536SEduard Zingerman if (err) 16851501b536SEduard Zingerman return err; 16861501b536SEduard Zingerman } 16871501b536SEduard Zingerman 16881501b536SEduard Zingerman return 0; 16891501b536SEduard Zingerman } 16901501b536SEduard Zingerman 16911501b536SEduard Zingerman void bpf_free_scev(struct bpf_verifier_env *env) 16921501b536SEduard Zingerman { 16931501b536SEduard Zingerman struct scev *scev = env->scev; 16941501b536SEduard Zingerman struct insn_envs *envs; 16951501b536SEduard Zingerman int i; 16961501b536SEduard Zingerman u32 j; 16971501b536SEduard Zingerman 16981501b536SEduard Zingerman if (!scev) 16991501b536SEduard Zingerman return; 17001501b536SEduard Zingerman for (i = 0; i < scev->envs_cnt; i++) { 17011501b536SEduard Zingerman envs = scev->envs[i]; 17021501b536SEduard Zingerman if (!envs) 17031501b536SEduard Zingerman continue; 17041501b536SEduard Zingerman for (j = 0; j < envs->cnt; j++) 17051501b536SEduard Zingerman kfree(envs->entries[j].env); 17061501b536SEduard Zingerman kfree(envs); 17071501b536SEduard Zingerman } 17081501b536SEduard Zingerman if (scev->exprs_ht) 17091501b536SEduard Zingerman for (i = 0; i < scev->exprs_ht_cnt; i++) 17101501b536SEduard Zingerman kvfree(scev->exprs_ht[i]); 17111501b536SEduard Zingerman kvfree(scev->exprs_ht); 17121501b536SEduard Zingerman kvfree(scev->worklist.data); 17131501b536SEduard Zingerman kvfree(scev->envs); 17141501b536SEduard Zingerman kvfree(scev->exprs); 17151501b536SEduard Zingerman kvfree(scev->discovered); 17161501b536SEduard Zingerman kfree(scev); 17171501b536SEduard Zingerman env->scev = NULL; 17181501b536SEduard Zingerman } 17191501b536SEduard Zingerman 17201501b536SEduard Zingerman int bpf_init_scev(struct bpf_verifier_env *env) 17211501b536SEduard Zingerman { 17221501b536SEduard Zingerman struct scev *scev; 17231501b536SEduard Zingerman 17241501b536SEduard Zingerman scev = kzalloc(sizeof(struct scev), GFP_KERNEL_ACCOUNT); 17251501b536SEduard Zingerman if (!scev) 17261501b536SEduard Zingerman return -ENOMEM; 17271501b536SEduard Zingerman env->scev = scev; 17286ccf49f7SEduard Zingerman bpf_mark_reg_known_scalar(&scev->zero_reg, 0); 17296ccf49f7SEduard Zingerman bpf_mark_reg_unknown_imprecise(&scev->unknown_reg); 17301501b536SEduard Zingerman /* A power of two for hash & (exprs_ht_cnt - 1)` indexing. */ 17311501b536SEduard Zingerman scev->exprs_ht_cnt = roundup_pow_of_two(max(256U, DIV_ROUND_UP(env->prog->len, 4))); 17321501b536SEduard Zingerman scev->exprs_ht = kvcalloc(scev->exprs_ht_cnt, sizeof(*scev->exprs_ht), GFP_KERNEL_ACCOUNT); 17331501b536SEduard Zingerman if (!scev->exprs_ht) 17341501b536SEduard Zingerman goto nomem; 17351501b536SEduard Zingerman if (expr0(scev, UNKNOWN) < 0 || expr0(scev, OPAQUE) < 0) 17361501b536SEduard Zingerman goto nomem; 17371501b536SEduard Zingerman scev->envs = kvcalloc(env->prog->len, sizeof(*scev->envs), GFP_KERNEL_ACCOUNT); 17381501b536SEduard Zingerman scev->discovered = kvcalloc(env->prog->len, sizeof(*scev->discovered), GFP_KERNEL_ACCOUNT); 17391501b536SEduard Zingerman if (!scev->envs || !scev->discovered) 17401501b536SEduard Zingerman goto nomem; 17411501b536SEduard Zingerman /* 17421501b536SEduard Zingerman * Remember original program length, in case bpf_free_scev() 17431501b536SEduard Zingerman * is called after bpf program rewrites that increase program 17441501b536SEduard Zingerman * length. 17451501b536SEduard Zingerman */ 17461501b536SEduard Zingerman scev->envs_cnt = env->prog->len; 17471501b536SEduard Zingerman return 0; 17481501b536SEduard Zingerman nomem: 17491501b536SEduard Zingerman bpf_free_scev(env); 17501501b536SEduard Zingerman return -ENOMEM; 17511501b536SEduard Zingerman } 17526ccf49f7SEduard Zingerman 17536ccf49f7SEduard Zingerman static struct bpf_stack_state *scev_regno_to_stack(const struct bpf_func_state *st, u32 r) 17546ccf49f7SEduard Zingerman { 17556ccf49f7SEduard Zingerman int spi, slots_available; 17566ccf49f7SEduard Zingerman 17576ccf49f7SEduard Zingerman if (r < MAX_BPF_REG) 17586ccf49f7SEduard Zingerman return NULL; 17596ccf49f7SEduard Zingerman 17606ccf49f7SEduard Zingerman slots_available = st->allocated_stack / BPF_REG_SIZE; 17616ccf49f7SEduard Zingerman spi = r - MAX_BPF_REG; 17626ccf49f7SEduard Zingerman if (spi < slots_available) 17636ccf49f7SEduard Zingerman return &st->stack[spi]; 17646ccf49f7SEduard Zingerman 17656ccf49f7SEduard Zingerman return NULL; 17666ccf49f7SEduard Zingerman } 17676ccf49f7SEduard Zingerman 17686ccf49f7SEduard Zingerman static struct bpf_reg_state *scev_regno_to_reg(struct bpf_func_state *st, u32 r) 17696ccf49f7SEduard Zingerman { 17706ccf49f7SEduard Zingerman return r < MAX_BPF_REG ? &st->regs[r] : NULL; 17716ccf49f7SEduard Zingerman } 17726ccf49f7SEduard Zingerman 17736ccf49f7SEduard Zingerman /* Linear widening requires a physical register or a full spill. */ 17746ccf49f7SEduard Zingerman static struct bpf_reg_state *scev_reg_for_linear(struct bpf_func_state *st, u32 r) 17756ccf49f7SEduard Zingerman { 17766ccf49f7SEduard Zingerman struct bpf_stack_state *stack; 17776ccf49f7SEduard Zingerman 17786ccf49f7SEduard Zingerman if (r < MAX_BPF_REG) 17796ccf49f7SEduard Zingerman return scev_regno_to_reg(st, r); 17806ccf49f7SEduard Zingerman stack = scev_regno_to_stack(st, r); 17816ccf49f7SEduard Zingerman if (!stack || bpf_spill_size(stack) != BPF_REG_SIZE) 17826ccf49f7SEduard Zingerman return NULL; 17836ccf49f7SEduard Zingerman return &stack->spilled_ptr; 17846ccf49f7SEduard Zingerman } 17856ccf49f7SEduard Zingerman 17866ccf49f7SEduard Zingerman /* 17876ccf49f7SEduard Zingerman * Return a borrowed value; never use it as a widening destination. 17886ccf49f7SEduard Zingerman * NULL denotes no readable value. 17896ccf49f7SEduard Zingerman */ 17906ccf49f7SEduard Zingerman static const struct bpf_reg_state * 17916ccf49f7SEduard Zingerman scev_reg_for_read(struct bpf_verifier_env *env, const struct bpf_func_state *st, u32 r) 17926ccf49f7SEduard Zingerman { 17936ccf49f7SEduard Zingerman const struct bpf_stack_state *stack; 17946ccf49f7SEduard Zingerman bool zero = true; 17956ccf49f7SEduard Zingerman int i; 17966ccf49f7SEduard Zingerman 17976ccf49f7SEduard Zingerman if (r < MAX_BPF_REG) 17986ccf49f7SEduard Zingerman return st->regs[r].type == NOT_INIT ? NULL : &st->regs[r]; 17996ccf49f7SEduard Zingerman if (r >= REGS_NUM || r - MAX_BPF_REG >= env->stack_limit / BPF_REG_SIZE) 18006ccf49f7SEduard Zingerman return NULL; 18016ccf49f7SEduard Zingerman 18026ccf49f7SEduard Zingerman stack = scev_regno_to_stack(st, r); 18036ccf49f7SEduard Zingerman if (!stack) 18046ccf49f7SEduard Zingerman return &env->scev->unknown_reg; 18056ccf49f7SEduard Zingerman if (bpf_spill_size(stack) == BPF_REG_SIZE) 18066ccf49f7SEduard Zingerman return &stack->spilled_ptr; 18076ccf49f7SEduard Zingerman 18086ccf49f7SEduard Zingerman /* Partial spills do not describe the value of the whole slot. */ 18096ccf49f7SEduard Zingerman for (i = 0; i < BPF_REG_SIZE; i++) { 18106ccf49f7SEduard Zingerman switch (stack->slot_type[i]) { 18116ccf49f7SEduard Zingerman case STACK_ZERO: 18126ccf49f7SEduard Zingerman break; 18136ccf49f7SEduard Zingerman case STACK_INVALID: 18146ccf49f7SEduard Zingerman case STACK_POISON: 18156ccf49f7SEduard Zingerman case STACK_MISC: 18166ccf49f7SEduard Zingerman zero = false; 18176ccf49f7SEduard Zingerman break; 18186ccf49f7SEduard Zingerman case STACK_SPILL: 18196ccf49f7SEduard Zingerman if (!bpf_is_spilled_scalar_reg(stack)) 18206ccf49f7SEduard Zingerman return NULL; 18216ccf49f7SEduard Zingerman zero = false; 18226ccf49f7SEduard Zingerman break; 18236ccf49f7SEduard Zingerman default: 18246ccf49f7SEduard Zingerman return NULL; 18256ccf49f7SEduard Zingerman } 18266ccf49f7SEduard Zingerman } 18276ccf49f7SEduard Zingerman return zero ? &env->scev->zero_reg : &env->scev->unknown_reg; 18286ccf49f7SEduard Zingerman } 18296ccf49f7SEduard Zingerman 18306ccf49f7SEduard Zingerman /* Materialize a writable value in the current state, growing its stack if needed. */ 18316ccf49f7SEduard Zingerman static int scev_reg_for_write(struct bpf_verifier_env *env, struct bpf_func_state *st, 18326ccf49f7SEduard Zingerman u32 r, struct bpf_reg_state **out) 18336ccf49f7SEduard Zingerman { 18346ccf49f7SEduard Zingerman const struct bpf_reg_state *value; 18356ccf49f7SEduard Zingerman struct bpf_stack_state *stack; 18366ccf49f7SEduard Zingerman u32 spi; 18376ccf49f7SEduard Zingerman int err; 18386ccf49f7SEduard Zingerman 18396ccf49f7SEduard Zingerman *out = scev_regno_to_reg(st, r); 18406ccf49f7SEduard Zingerman if (*out) 18416ccf49f7SEduard Zingerman return 0; 18426ccf49f7SEduard Zingerman if (r >= REGS_NUM || r - MAX_BPF_REG >= env->stack_limit / BPF_REG_SIZE) 18436ccf49f7SEduard Zingerman return -EINVAL; 18446ccf49f7SEduard Zingerman 18456ccf49f7SEduard Zingerman spi = r - MAX_BPF_REG; 18466ccf49f7SEduard Zingerman err = bpf_grow_stack_state(env, st, (spi + 1) * BPF_REG_SIZE); 18476ccf49f7SEduard Zingerman if (err) 18486ccf49f7SEduard Zingerman return err; 18496ccf49f7SEduard Zingerman 18506ccf49f7SEduard Zingerman /* Resolve pointers after growth, which may relocate the stack. */ 18516ccf49f7SEduard Zingerman value = scev_reg_for_read(env, st, r); 18526ccf49f7SEduard Zingerman if (!value) 18536ccf49f7SEduard Zingerman return -EINVAL; 18546ccf49f7SEduard Zingerman stack = scev_regno_to_stack(st, r); 18556ccf49f7SEduard Zingerman stack->spilled_ptr = *value; 18566ccf49f7SEduard Zingerman memset(stack->slot_type, STACK_SPILL, sizeof(stack->slot_type)); 18576ccf49f7SEduard Zingerman *out = &stack->spilled_ptr; 18586ccf49f7SEduard Zingerman return 0; 18596ccf49f7SEduard Zingerman } 18606ccf49f7SEduard Zingerman 18616ccf49f7SEduard Zingerman static bool scev_reg_alive(struct bpf_verifier_env *env, struct bpf_verifier_state *st, u32 r) 18626ccf49f7SEduard Zingerman { 18636ccf49f7SEduard Zingerman int insn_idx = bpf_frame_insn_idx(st, st->curframe); 18646ccf49f7SEduard Zingerman u16 live_regs = env->insn_aux_data[insn_idx].live_regs_before; 18656ccf49f7SEduard Zingerman int spi; 18666ccf49f7SEduard Zingerman 18676ccf49f7SEduard Zingerman if (r < MAX_BPF_REG) { 18686ccf49f7SEduard Zingerman return BIT(r) & live_regs; 18696ccf49f7SEduard Zingerman } else { 18706ccf49f7SEduard Zingerman spi = r - MAX_BPF_REG; 18716ccf49f7SEduard Zingerman return bpf_stack_slot_alive(env, st->curframe, spi * 2) || 18726ccf49f7SEduard Zingerman bpf_stack_slot_alive(env, st->curframe, spi * 2 + 1); 18736ccf49f7SEduard Zingerman } 18746ccf49f7SEduard Zingerman } 18756ccf49f7SEduard Zingerman 18766ccf49f7SEduard Zingerman /* 18776ccf49f7SEduard Zingerman * Latch is a condition deciding if execution remains inside a loop. 18786ccf49f7SEduard Zingerman * Linear latch represents a condition 'if <reg> <op> <loop invariant> goto <loop-header>', 18796ccf49f7SEduard Zingerman * where equation '<base> + i * <step> <op> <bound>' describes values taken by register <reg>, 18806ccf49f7SEduard Zingerman * 'i' is the loop iteration number, starting from 0. 1881*32e96257SEduard Zingerman * 'zext32' indicates the latch is for (zext32 (linear ...)) SCEV. 1882*32e96257SEduard Zingerman * 'jmp32' indicates that the latch is a JMP32 instruction. 18836ccf49f7SEduard Zingerman */ 18846ccf49f7SEduard Zingerman struct linear_latch { 18856ccf49f7SEduard Zingerman u32 insn_idx; 18866ccf49f7SEduard Zingerman u32 base_expr; 18876ccf49f7SEduard Zingerman u32 step_expr; 18886ccf49f7SEduard Zingerman u32 bound_expr; 1889*32e96257SEduard Zingerman u8 op; 1890*32e96257SEduard Zingerman bool zext32; 1891*32e96257SEduard Zingerman bool jmp32; 18926ccf49f7SEduard Zingerman }; 18936ccf49f7SEduard Zingerman 18946ccf49f7SEduard Zingerman static bool loop_invariant(struct scev *scev, u32 id) 18956ccf49f7SEduard Zingerman { 18966ccf49f7SEduard Zingerman s64 imm; 18976ccf49f7SEduard Zingerman u32 reg; 18986ccf49f7SEduard Zingerman 18996ccf49f7SEduard Zingerman return is_reg(scev, id, ®) || is_imm(scev, id, &imm); 19006ccf49f7SEduard Zingerman } 19016ccf49f7SEduard Zingerman 19026ccf49f7SEduard Zingerman static int match_linear_latch(struct bpf_verifier_env *env, 19036ccf49f7SEduard Zingerman u32 header, 19046ccf49f7SEduard Zingerman u32 latch_idx, 19056ccf49f7SEduard Zingerman struct linear_latch *latch) 19066ccf49f7SEduard Zingerman { 19076ccf49f7SEduard Zingerman struct bpf_insn *insn = &env->prog->insnsi[latch_idx]; 19086ccf49f7SEduard Zingerman struct scev *scev = env->scev; 19096ccf49f7SEduard Zingerman struct env *latch_env; 19106ccf49f7SEduard Zingerman u32 true_branch_loop; 19116ccf49f7SEduard Zingerman u32 true_branch_tgt; 19126ccf49f7SEduard Zingerman u32 src_reg_scev; 19136ccf49f7SEduard Zingerman u32 dst_reg_scev; 19146ccf49f7SEduard Zingerman u32 t, l, r, op; 19156ccf49f7SEduard Zingerman int id; 19166ccf49f7SEduard Zingerman 19176ccf49f7SEduard Zingerman op = BPF_OP(insn->code); 1918*32e96257SEduard Zingerman latch->jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 19196ccf49f7SEduard Zingerman /* Flip the condition if true branch jumps out of the loop. */ 19206ccf49f7SEduard Zingerman true_branch_tgt = latch_idx + bpf_jmp_offset(insn) + 1; 19216ccf49f7SEduard Zingerman true_branch_loop = bpf_loop_at_index(env, true_branch_tgt); 19226ccf49f7SEduard Zingerman if (true_branch_loop != header && 19236ccf49f7SEduard Zingerman !bpf_is_nested_loop(env, true_branch_loop, header)) 19246ccf49f7SEduard Zingerman op = bpf_rev_opcode(op); 19256ccf49f7SEduard Zingerman switch (op) { 19266ccf49f7SEduard Zingerman case BPF_JSLT: 19276ccf49f7SEduard Zingerman case BPF_JSLE: 19286ccf49f7SEduard Zingerman case BPF_JSGT: 19296ccf49f7SEduard Zingerman case BPF_JSGE: 19306ccf49f7SEduard Zingerman case BPF_JLT: 19316ccf49f7SEduard Zingerman case BPF_JLE: 19326ccf49f7SEduard Zingerman case BPF_JGT: 19336ccf49f7SEduard Zingerman case BPF_JGE: 19346ccf49f7SEduard Zingerman case BPF_JNE: 19356ccf49f7SEduard Zingerman break; 19366ccf49f7SEduard Zingerman default: 19376ccf49f7SEduard Zingerman return false; 19386ccf49f7SEduard Zingerman } 19396ccf49f7SEduard Zingerman 19406ccf49f7SEduard Zingerman latch->insn_idx = latch_idx; 19416ccf49f7SEduard Zingerman 19426ccf49f7SEduard Zingerman latch_env = find_loop_env(scev, header, latch_idx); 19436ccf49f7SEduard Zingerman if (verifier_bug_if(!latch_env, env, "header_idx=%d, latch_idx=%d\n", header, latch_idx)) 19446ccf49f7SEduard Zingerman return -EFAULT; 19456ccf49f7SEduard Zingerman dst_reg_scev = latch_env->reg2scev[insn->dst_reg]; 19466ccf49f7SEduard Zingerman src_reg_scev = latch_env->reg2scev[insn->src_reg]; 19476ccf49f7SEduard Zingerman /* 19486ccf49f7SEduard Zingerman * Make sure (linear ...) is in dst_reg_scev: 19496ccf49f7SEduard Zingerman * 'if <invariant> <op> <linear>' ⇔ 19506ccf49f7SEduard Zingerman * 'if <linear> <flip(op)> <invariant>'. 19516ccf49f7SEduard Zingerman */ 1952*32e96257SEduard Zingerman if (BPF_SRC(insn->code) == BPF_X && 1953*32e96257SEduard Zingerman is_linear_or_linear32(scev, src_reg_scev, &l, &r, &latch->zext32)) { 19546ccf49f7SEduard Zingerman swap(dst_reg_scev, src_reg_scev); 19556ccf49f7SEduard Zingerman op = bpf_flip_opcode(op); 19566ccf49f7SEduard Zingerman } 19576ccf49f7SEduard Zingerman latch->op = op; 19586ccf49f7SEduard Zingerman /* 19596ccf49f7SEduard Zingerman * simplify() produces two shapes for linear latches: 19606ccf49f7SEduard Zingerman * - (linear register step) 19616ccf49f7SEduard Zingerman * ^----------------------------+-- base_expr 19626ccf49f7SEduard Zingerman * base_expr | 19636ccf49f7SEduard Zingerman * - (linear (+ register imm) step) | 19646ccf49f7SEduard Zingerman * ^----------------------------' 19656ccf49f7SEduard Zingerman */ 1966*32e96257SEduard Zingerman if (!is_linear_or_linear32(scev, dst_reg_scev, 1967*32e96257SEduard Zingerman &latch->base_expr, &latch->step_expr, &latch->zext32)) 19686ccf49f7SEduard Zingerman return false; 19696ccf49f7SEduard Zingerman 19706ccf49f7SEduard Zingerman if (BPF_SRC(insn->code) == BPF_K) { 19716ccf49f7SEduard Zingerman id = imm_expr(scev, insn->imm); 19726ccf49f7SEduard Zingerman if (id < 0) 19736ccf49f7SEduard Zingerman return id; 19746ccf49f7SEduard Zingerman latch->bound_expr = id; 19756ccf49f7SEduard Zingerman } else { 19766ccf49f7SEduard Zingerman latch->bound_expr = src_reg_scev; 19776ccf49f7SEduard Zingerman } 19786ccf49f7SEduard Zingerman 19796ccf49f7SEduard Zingerman if (!loop_invariant(scev, latch->step_expr) || 19806ccf49f7SEduard Zingerman !loop_invariant(scev, latch->bound_expr)) 19816ccf49f7SEduard Zingerman return false; 19826ccf49f7SEduard Zingerman 19836ccf49f7SEduard Zingerman /* (linear register step) */ 19846ccf49f7SEduard Zingerman if (is_reg(scev, latch->base_expr, &t)) 19856ccf49f7SEduard Zingerman return true; 19866ccf49f7SEduard Zingerman 19876ccf49f7SEduard Zingerman /* (linear (+ register imm) step) */ 19886ccf49f7SEduard Zingerman if (is_add(scev, latch->base_expr, &l, &r) && 19896ccf49f7SEduard Zingerman is_reg(scev, l, &t) && 19906ccf49f7SEduard Zingerman loop_invariant(scev, r)) 19916ccf49f7SEduard Zingerman return true; 19926ccf49f7SEduard Zingerman 19936ccf49f7SEduard Zingerman return false; 19946ccf49f7SEduard Zingerman } 19956ccf49f7SEduard Zingerman 19966ccf49f7SEduard Zingerman struct scev_value { 19976ccf49f7SEduard Zingerman u64 value; /* scalar value or a pointer offset */ 19986ccf49f7SEduard Zingerman int ptr_reg; /* SCEV register identifying the pointer origin, or -1. */ 19996ccf49f7SEduard Zingerman }; 20006ccf49f7SEduard Zingerman 20016ccf49f7SEduard Zingerman static void log_scev_value(struct bpf_verifier_env *env, struct bpf_func_state *st, 20026ccf49f7SEduard Zingerman const struct scev_value *v) 20036ccf49f7SEduard Zingerman { 20046ccf49f7SEduard Zingerman const struct bpf_reg_state *reg; 20056ccf49f7SEduard Zingerman 20066ccf49f7SEduard Zingerman if (v->ptr_reg >= 0) { 20076ccf49f7SEduard Zingerman reg = scev_reg_for_read(env, st, v->ptr_reg); 20086ccf49f7SEduard Zingerman log_reg(env, v->ptr_reg); 20096ccf49f7SEduard Zingerman bpf_log(&env->log, " (%s)", reg ? reg_type_str(env, reg->type) : "unavailable"); 20106ccf49f7SEduard Zingerman } else { 20116ccf49f7SEduard Zingerman bpf_log(&env->log, "scalar %llu", v->value); 20126ccf49f7SEduard Zingerman } 20136ccf49f7SEduard Zingerman } 20146ccf49f7SEduard Zingerman 20156ccf49f7SEduard Zingerman static void log_incompatible_scev_values(struct bpf_verifier_env *env, const char *reason, 20166ccf49f7SEduard Zingerman struct bpf_func_state *st, 20176ccf49f7SEduard Zingerman const struct scev_value *a, const struct scev_value *b) 20186ccf49f7SEduard Zingerman { 20196ccf49f7SEduard Zingerman bpf_log(&env->log, "scev: %s ", reason); 20206ccf49f7SEduard Zingerman log_scev_value(env, st, a); 20216ccf49f7SEduard Zingerman bpf_log(&env->log, ", "); 20226ccf49f7SEduard Zingerman log_scev_value(env, st, b); 20236ccf49f7SEduard Zingerman bpf_log(&env->log, "\n"); 20246ccf49f7SEduard Zingerman } 20256ccf49f7SEduard Zingerman 20266ccf49f7SEduard Zingerman static bool scev_value_compatible(struct bpf_verifier_env *env, struct bpf_func_state *st, 20276ccf49f7SEduard Zingerman const struct scev_value *a, const struct scev_value *b) 20286ccf49f7SEduard Zingerman { 20296ccf49f7SEduard Zingerman const struct bpf_reg_state *ra, *rb; 20306ccf49f7SEduard Zingerman 20316ccf49f7SEduard Zingerman if (a->ptr_reg < 0 || b->ptr_reg < 0) { 20326ccf49f7SEduard Zingerman if (a->ptr_reg < 0 && b->ptr_reg < 0) 20336ccf49f7SEduard Zingerman return true; 20346ccf49f7SEduard Zingerman goto incompatible; 20356ccf49f7SEduard Zingerman } 20366ccf49f7SEduard Zingerman ra = scev_reg_for_read(env, st, a->ptr_reg); 20376ccf49f7SEduard Zingerman rb = scev_reg_for_read(env, st, b->ptr_reg); 20386ccf49f7SEduard Zingerman if (ra && rb && bpf_same_memory_origin(ra, rb)) 20396ccf49f7SEduard Zingerman return true; 20406ccf49f7SEduard Zingerman 20416ccf49f7SEduard Zingerman incompatible: 20426ccf49f7SEduard Zingerman if (env->log.level & BPF_LOG_LEVEL2) 20436ccf49f7SEduard Zingerman log_incompatible_scev_values(env, "incompatible latch operands", st, a, b); 20446ccf49f7SEduard Zingerman return false; 20456ccf49f7SEduard Zingerman } 20466ccf49f7SEduard Zingerman 20476ccf49f7SEduard Zingerman static bool scev_value_add(struct bpf_verifier_env *env, struct bpf_func_state *st, 20486ccf49f7SEduard Zingerman const struct scev_value *a, const struct scev_value *b, 20496ccf49f7SEduard Zingerman struct scev_value *result) 20506ccf49f7SEduard Zingerman { 20516ccf49f7SEduard Zingerman if (a->ptr_reg >= 0 && b->ptr_reg >= 0) { 20526ccf49f7SEduard Zingerman if (env->log.level & BPF_LOG_LEVEL2) 20536ccf49f7SEduard Zingerman log_incompatible_scev_values(env, "can't add two pointers", st, a, b); 20546ccf49f7SEduard Zingerman return false; 20556ccf49f7SEduard Zingerman } 20566ccf49f7SEduard Zingerman result->value = a->value + b->value; 20576ccf49f7SEduard Zingerman result->ptr_reg = a->ptr_reg >= 0 ? a->ptr_reg : b->ptr_reg; 20586ccf49f7SEduard Zingerman return true; 20596ccf49f7SEduard Zingerman } 20606ccf49f7SEduard Zingerman 20616ccf49f7SEduard Zingerman static bool eval_expr(struct bpf_verifier_env *env, struct scev *scev, 20626ccf49f7SEduard Zingerman struct bpf_func_state *st, u32 id, struct scev_value *result) 20636ccf49f7SEduard Zingerman { 20646ccf49f7SEduard Zingerman struct scev_value lval, rval; 20656ccf49f7SEduard Zingerman const struct bpf_reg_state *reg; 20666ccf49f7SEduard Zingerman u32 l, r, regno; 20676ccf49f7SEduard Zingerman s64 imm; 20686ccf49f7SEduard Zingerman 20696ccf49f7SEduard Zingerman if (is_reg(scev, id, ®no)) { 20706ccf49f7SEduard Zingerman reg = scev_reg_for_read(env, st, regno); 20716ccf49f7SEduard Zingerman if (!reg || reg->type == NOT_INIT || !tnum_is_const(reg->var_off)) 20726ccf49f7SEduard Zingerman return false; 20736ccf49f7SEduard Zingerman result->value = reg->var_off.value; 20746ccf49f7SEduard Zingerman result->ptr_reg = reg->type == SCALAR_VALUE ? -1 : (int)regno; 20756ccf49f7SEduard Zingerman return true; 20766ccf49f7SEduard Zingerman } else if (is_imm(scev, id, &imm)) { 20776ccf49f7SEduard Zingerman result->value = imm; 20786ccf49f7SEduard Zingerman result->ptr_reg = -1; 20796ccf49f7SEduard Zingerman return true; 20806ccf49f7SEduard Zingerman } else if (is_add(scev, id, &l, &r) && 20816ccf49f7SEduard Zingerman eval_expr(env, scev, st, l, &lval) && 20826ccf49f7SEduard Zingerman eval_expr(env, scev, st, r, &rval)) { 20836ccf49f7SEduard Zingerman return scev_value_add(env, st, &lval, &rval, result); 20846ccf49f7SEduard Zingerman } 20856ccf49f7SEduard Zingerman return false; 20866ccf49f7SEduard Zingerman } 20876ccf49f7SEduard Zingerman 2088*32e96257SEduard Zingerman static bool is_signed_op(u8 op) 20896ccf49f7SEduard Zingerman { 2090*32e96257SEduard Zingerman switch (op) { 2091*32e96257SEduard Zingerman case BPF_JSLT: 2092*32e96257SEduard Zingerman case BPF_JSLE: 2093*32e96257SEduard Zingerman case BPF_JSGT: 2094*32e96257SEduard Zingerman case BPF_JSGE: 2095*32e96257SEduard Zingerman return true; 2096*32e96257SEduard Zingerman default: 2097*32e96257SEduard Zingerman return false; 2098*32e96257SEduard Zingerman } 2099*32e96257SEduard Zingerman } 2100*32e96257SEduard Zingerman 2101*32e96257SEduard Zingerman static bool compute_backedge_taken_count(u8 op, u64 initial, u64 step, u64 bound, u64 *result) 2102*32e96257SEduard Zingerman { 2103*32e96257SEduard Zingerman u64 rem, diff, backedge_taken_count; 21046ccf49f7SEduard Zingerman bool up, down; 21056ccf49f7SEduard Zingerman 21066ccf49f7SEduard Zingerman if (step == 0) 21076ccf49f7SEduard Zingerman return false; 21086ccf49f7SEduard Zingerman down = (s64)step < 0; 21096ccf49f7SEduard Zingerman up = (s64)step > 0; 21106ccf49f7SEduard Zingerman diff = bound - initial; 21116ccf49f7SEduard Zingerman switch (op) { 21126ccf49f7SEduard Zingerman case BPF_JLT: 21136ccf49f7SEduard Zingerman /* 21146ccf49f7SEduard Zingerman * E.g.: 3 + 2*i < 7 ⇔ 2*i < 4 ⇔ i ∈ [0,1]. 21156ccf49f7SEduard Zingerman * Here the inequality describes a set of values `i` might take 21166ccf49f7SEduard Zingerman * while the latch condition remains true (the backedge is taken). 21176ccf49f7SEduard Zingerman * The backedge_taken_count is the size of this set. 21186ccf49f7SEduard Zingerman */ 21196ccf49f7SEduard Zingerman if (/* 21206ccf49f7SEduard Zingerman * If the condition is initially true, decreasing values won't 21216ccf49f7SEduard Zingerman * change that without underflow. If the condition is initially false, 21226ccf49f7SEduard Zingerman * the main pass would do a single iteration anyway. 21236ccf49f7SEduard Zingerman */ 21246ccf49f7SEduard Zingerman down || 21256ccf49f7SEduard Zingerman /* Is the latch condition false on the first iteration? */ 21266ccf49f7SEduard Zingerman initial >= bound || 21276ccf49f7SEduard Zingerman /* Count iterations satisfying the strict inequality, including i=0. */ 21284cce2861SEduard Zingerman check_add_overflow(div64_u64(diff - 1, step), 1, &backedge_taken_count) || 21296ccf49f7SEduard Zingerman /* 21306ccf49f7SEduard Zingerman * Check if the last iteration overflows the counter: 21316ccf49f7SEduard Zingerman * initial + backedge_taken_count * step > U64_MAX 21326ccf49f7SEduard Zingerman */ 21334cce2861SEduard Zingerman backedge_taken_count > div64_u64(U64_MAX - initial, step)) 21346ccf49f7SEduard Zingerman return false; 21356ccf49f7SEduard Zingerman break; 21366ccf49f7SEduard Zingerman case BPF_JLE: 21376ccf49f7SEduard Zingerman /* E.g.: 3 + 2*i ≤ 7 ⇔ 2*i ≤ 4 ⇔ i ∈ [0,1,2]. */ 21386ccf49f7SEduard Zingerman if (down || initial > bound || 21396ccf49f7SEduard Zingerman /* Count iterations satisfying the non-strict inequality. */ 21404cce2861SEduard Zingerman check_add_overflow(div64_u64(diff, step), 1, &backedge_taken_count) || 21414cce2861SEduard Zingerman backedge_taken_count > div64_u64(U64_MAX - initial, step)) 21426ccf49f7SEduard Zingerman return false; 21436ccf49f7SEduard Zingerman break; 21446ccf49f7SEduard Zingerman case BPF_JGT: 21456ccf49f7SEduard Zingerman /* E.g.: 7 - 2*i > 3 ⇔ 2*i < 4 ⇔ i ∈ [0,1]. */ 21466ccf49f7SEduard Zingerman if (up || initial <= bound || 21474cce2861SEduard Zingerman check_add_overflow(div64_u64(-diff - 1, -step), 1, &backedge_taken_count) || 21486ccf49f7SEduard Zingerman /* 21496ccf49f7SEduard Zingerman * The last iteration underflows the counter if: 21506ccf49f7SEduard Zingerman * initial + backedge_taken_count * step < 0 ⇔ 21516ccf49f7SEduard Zingerman * backedge_taken_count * step < -initial ⇔ 21526ccf49f7SEduard Zingerman * backedge_taken_count > initial / -step 21536ccf49f7SEduard Zingerman * (direction flips because step < 0) 21546ccf49f7SEduard Zingerman */ 21554cce2861SEduard Zingerman backedge_taken_count > div64_u64(initial, -step)) 21566ccf49f7SEduard Zingerman return false; 21576ccf49f7SEduard Zingerman break; 21586ccf49f7SEduard Zingerman case BPF_JGE: 21596ccf49f7SEduard Zingerman /* E.g.: 7 - 2*i ≥ 3 ⇔ 2*i ≤ 4 ⇔ i ∈ [0,1,2]. */ 21606ccf49f7SEduard Zingerman if (up || initial < bound || 21614cce2861SEduard Zingerman check_add_overflow(div64_u64(-diff, -step), 1, &backedge_taken_count) || 21624cce2861SEduard Zingerman backedge_taken_count > div64_u64(initial, -step)) 21636ccf49f7SEduard Zingerman return false; 21646ccf49f7SEduard Zingerman break; 21656ccf49f7SEduard Zingerman case BPF_JSLT: 21666ccf49f7SEduard Zingerman if (down || (s64)initial >= (s64)bound || 21674cce2861SEduard Zingerman check_add_overflow(div64_u64(diff - 1, step), 1, &backedge_taken_count) || 21686ccf49f7SEduard Zingerman /* 21696ccf49f7SEduard Zingerman * Check if the last iteration overflows the signed counter: 21706ccf49f7SEduard Zingerman * (s64)initial + backedge_taken_count * step > S64_MAX 21716ccf49f7SEduard Zingerman */ 21724cce2861SEduard Zingerman backedge_taken_count > div64_u64((u64)S64_MAX - initial, step)) 21736ccf49f7SEduard Zingerman return false; 21746ccf49f7SEduard Zingerman break; 21756ccf49f7SEduard Zingerman case BPF_JSLE: 21766ccf49f7SEduard Zingerman if (down || (s64)initial > (s64)bound || 21774cce2861SEduard Zingerman check_add_overflow(div64_u64(diff, step), 1, &backedge_taken_count) || 21784cce2861SEduard Zingerman backedge_taken_count > div64_u64((u64)S64_MAX - initial, step)) 21796ccf49f7SEduard Zingerman return false; 21806ccf49f7SEduard Zingerman break; 21816ccf49f7SEduard Zingerman case BPF_JSGT: 21826ccf49f7SEduard Zingerman if (up || (s64)initial <= (s64)bound || 21834cce2861SEduard Zingerman check_add_overflow(div64_u64(-diff - 1, -step), 1, &backedge_taken_count) || 21846ccf49f7SEduard Zingerman /* 21856ccf49f7SEduard Zingerman * The last iteration underflows the signed counter if: 21866ccf49f7SEduard Zingerman * (s64)initial + backedge_taken_count * step < S64_MIN ⇔ 21876ccf49f7SEduard Zingerman * backedge_taken_count * step < S64_MIN - (s64)initial ⇔ 21886ccf49f7SEduard Zingerman * backedge_taken_count > initial - (u64)S64_MIN / -step 21896ccf49f7SEduard Zingerman * (direction flips because step < 0) 21906ccf49f7SEduard Zingerman */ 21914cce2861SEduard Zingerman backedge_taken_count > div64_u64(initial - (u64)S64_MIN, -step)) 21926ccf49f7SEduard Zingerman return false; 21936ccf49f7SEduard Zingerman break; 21946ccf49f7SEduard Zingerman case BPF_JSGE: 21956ccf49f7SEduard Zingerman if (up || (s64)initial < (s64)bound || 21964cce2861SEduard Zingerman check_add_overflow(div64_u64(-diff, -step), 1, &backedge_taken_count) || 21974cce2861SEduard Zingerman backedge_taken_count > div64_u64(initial - (u64)S64_MIN, -step)) 21986ccf49f7SEduard Zingerman return false; 21996ccf49f7SEduard Zingerman break; 22006ccf49f7SEduard Zingerman case BPF_JNE: 22016ccf49f7SEduard Zingerman /* 22026ccf49f7SEduard Zingerman * For a decreasing counter flip the diff and step: 22036ccf49f7SEduard Zingerman * 7 - 2*i ≠ 3 ⇔ 2*i ≠ 7 - 3. 22046ccf49f7SEduard Zingerman */ 22056ccf49f7SEduard Zingerman diff = down ? -diff : diff; 22066ccf49f7SEduard Zingerman step = down ? -step : step; 22074cce2861SEduard Zingerman backedge_taken_count = div64_u64_rem(diff, step, &rem); 22084cce2861SEduard Zingerman if (diff == 0 || rem != 0) 22096ccf49f7SEduard Zingerman return false; 22106ccf49f7SEduard Zingerman break; 22116ccf49f7SEduard Zingerman default: 22126ccf49f7SEduard Zingerman return false; 22136ccf49f7SEduard Zingerman } 22146ccf49f7SEduard Zingerman 2215*32e96257SEduard Zingerman *result = backedge_taken_count; 2216*32e96257SEduard Zingerman return true; 2217*32e96257SEduard Zingerman } 2218*32e96257SEduard Zingerman 2219*32e96257SEduard Zingerman /* 2220*32e96257SEduard Zingerman * Loop with post-condition: 2221*32e96257SEduard Zingerman * 2222*32e96257SEduard Zingerman * r0 = 0 2223*32e96257SEduard Zingerman * l: ... r0 ∈ [0,1,2] header executed 3 times 2224*32e96257SEduard Zingerman * r0 += 1 r0 ∈ [0,1,2] 2225*32e96257SEduard Zingerman * ... r0 ∈ [1,2,3] 2226*32e96257SEduard Zingerman * if r0 != 3 goto l r0 ∈ [1,2,3] backedge taken 2 times 2227*32e96257SEduard Zingerman * ... r0 ∈ [3] 2228*32e96257SEduard Zingerman * 2229*32e96257SEduard Zingerman * SCEV at header: r0 = k 2230*32e96257SEduard Zingerman * SCEV at latch: r0 = 1 + k 2231*32e96257SEduard Zingerman * 2232*32e96257SEduard Zingerman * Loop with pre-condition: 2233*32e96257SEduard Zingerman * 2234*32e96257SEduard Zingerman * r0 = 0 2235*32e96257SEduard Zingerman * l: ... r0 ∈ [0,1,2,3] header executed 4 times 2236*32e96257SEduard Zingerman * if r0 == 3 goto e r0 ∈ [0,1,2,3] backedge taken 3 times 2237*32e96257SEduard Zingerman * r0 += 1 r0 ∈ [0,1,2] 2238*32e96257SEduard Zingerman * ... r0 ∈ [1,2,3] 2239*32e96257SEduard Zingerman * goto l r0 ∈ [1,2,3] 2240*32e96257SEduard Zingerman * e: ... r0 ∈ [3] 2241*32e96257SEduard Zingerman * 2242*32e96257SEduard Zingerman * SCEV at header: r0 = k 2243*32e96257SEduard Zingerman * SCEV at latch: r0 = k 2244*32e96257SEduard Zingerman */ 2245*32e96257SEduard Zingerman static bool compute_max_iters(struct bpf_verifier_env *env, 2246*32e96257SEduard Zingerman struct bpf_func_state *st, 2247*32e96257SEduard Zingerman struct linear_latch *latch, 2248*32e96257SEduard Zingerman struct bpf_loop_iters *iters) 2249*32e96257SEduard Zingerman { 2250*32e96257SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 2251*32e96257SEduard Zingerman struct bpf_loop *loop = aux[bpf_loop_at_index(env, latch->insn_idx)].loop; 2252*32e96257SEduard Zingerman struct scev *scev = env->scev; 2253*32e96257SEduard Zingerman struct scev_value initial_val, step_val, bound_val; 2254*32e96257SEduard Zingerman u64 step, bound, initial, total_change, backedge_taken_count; 2255*32e96257SEduard Zingerman u8 op = latch->op; 2256*32e96257SEduard Zingerman 2257*32e96257SEduard Zingerman if (!eval_expr(env, scev, st, latch->base_expr, &initial_val) || 2258*32e96257SEduard Zingerman !eval_expr(env, scev, st, latch->step_expr, &step_val) || 2259*32e96257SEduard Zingerman !eval_expr(env, scev, st, latch->bound_expr, &bound_val)) 2260*32e96257SEduard Zingerman return false; 2261*32e96257SEduard Zingerman 2262*32e96257SEduard Zingerman if (step_val.ptr_reg >= 0) { 2263*32e96257SEduard Zingerman if (env->log.level & BPF_LOG_LEVEL2) { 2264*32e96257SEduard Zingerman bpf_log(&env->log, "scev: latch step is a pointer "); 2265*32e96257SEduard Zingerman log_scev_value(env, st, &step_val); 2266*32e96257SEduard Zingerman bpf_log(&env->log, "\n"); 2267*32e96257SEduard Zingerman } 2268*32e96257SEduard Zingerman return false; 2269*32e96257SEduard Zingerman } 2270*32e96257SEduard Zingerman if (!scev_value_compatible(env, st, &initial_val, &bound_val)) 2271*32e96257SEduard Zingerman return false; 2272*32e96257SEduard Zingerman 2273*32e96257SEduard Zingerman initial = initial_val.value; 2274*32e96257SEduard Zingerman step = step_val.value; 2275*32e96257SEduard Zingerman bound = bound_val.value; 2276*32e96257SEduard Zingerman 2277*32e96257SEduard Zingerman /* 2278*32e96257SEduard Zingerman * The code below only handles mixed 64-bit/32-bit comparisons/recurrences 2279*32e96257SEduard Zingerman * when initial bounds and step fit in 32-bit domain. 2280*32e96257SEduard Zingerman */ 2281*32e96257SEduard Zingerman if (latch->zext32 || latch->jmp32) { 2282*32e96257SEduard Zingerman /* 2283*32e96257SEduard Zingerman * With the above constraint doing `l: w0 += 1; if r0 s< 256 goto l;` 2284*32e96257SEduard Zingerman * is equivalent to `l: w0 += 1; if r0 < 256 goto l;` 2285*32e96257SEduard Zingerman */ 2286*32e96257SEduard Zingerman if (latch->jmp32 && is_signed_op(op)) { 2287*32e96257SEduard Zingerman initial = (s64)(s32)(u32)initial; 2288*32e96257SEduard Zingerman bound = (s64)(s32)(u32)bound; 2289*32e96257SEduard Zingerman step = (s64)(s32)(u32)step; 2290*32e96257SEduard Zingerman } else { 2291*32e96257SEduard Zingerman initial = (u32)initial; 2292*32e96257SEduard Zingerman bound = (u32)bound; 2293*32e96257SEduard Zingerman step = (s64)(s32)(u32)step; 2294*32e96257SEduard Zingerman } 2295*32e96257SEduard Zingerman } 2296*32e96257SEduard Zingerman if (latch->zext32 ^ latch->jmp32 && (initial != initial_val.value || 2297*32e96257SEduard Zingerman bound != bound_val.value || 2298*32e96257SEduard Zingerman step != step_val.value)) { 2299*32e96257SEduard Zingerman if (env->log.level & BPF_LOG_LEVEL2) 2300*32e96257SEduard Zingerman bpf_log(&env->log, 2301*32e96257SEduard Zingerman "scev: mixed-width latch has operands outside 32-bit ranges\n"); 2302*32e96257SEduard Zingerman return false; 2303*32e96257SEduard Zingerman } 2304*32e96257SEduard Zingerman 2305*32e96257SEduard Zingerman 2306*32e96257SEduard Zingerman if (!compute_backedge_taken_count(op, initial, step, bound, &backedge_taken_count)) 2307*32e96257SEduard Zingerman return false; 2308*32e96257SEduard Zingerman 2309*32e96257SEduard Zingerman if (latch->zext32 || latch->jmp32) { 2310*32e96257SEduard Zingerman /* 2311*32e96257SEduard Zingerman * compute_backedge_taken_count() guarantees that 'total_change' 2312*32e96257SEduard Zingerman * does not overflow in 64-bit domain. 2313*32e96257SEduard Zingerman */ 2314*32e96257SEduard Zingerman total_change = initial + step * backedge_taken_count; 2315*32e96257SEduard Zingerman if (latch->jmp32 && is_signed_op(op)) { 2316*32e96257SEduard Zingerman if ((s64)total_change < S32_MIN || (s64)total_change > S32_MAX) 2317*32e96257SEduard Zingerman return false; 2318*32e96257SEduard Zingerman } else { 2319*32e96257SEduard Zingerman if (total_change > U32_MAX) 2320*32e96257SEduard Zingerman return false; 2321*32e96257SEduard Zingerman } 2322*32e96257SEduard Zingerman } 2323*32e96257SEduard Zingerman 23246ccf49f7SEduard Zingerman /* 23256ccf49f7SEduard Zingerman * max_header_count is u32 and U32_MAX means "infinite", 23266ccf49f7SEduard Zingerman * check to avoid overflow below. 23276ccf49f7SEduard Zingerman */ 23286ccf49f7SEduard Zingerman if (backedge_taken_count >= U32_MAX - 1) 23296ccf49f7SEduard Zingerman return false; 23306ccf49f7SEduard Zingerman 23316ccf49f7SEduard Zingerman /* The header executes once on entry and once for each taken backedge, hence +1. */ 23326ccf49f7SEduard Zingerman iters->max_header_count = backedge_taken_count + 1; 23336ccf49f7SEduard Zingerman /* 23346ccf49f7SEduard Zingerman * The latch is a conditional jump with one jump target exiting the loop. 23356ccf49f7SEduard Zingerman * Linear latch is matched only if the loop has a single backedge. 23366ccf49f7SEduard Zingerman * The loop still, however can have multiple exits. 23376ccf49f7SEduard Zingerman * In such case, conservatively assume that non-latch exit can happen 23386ccf49f7SEduard Zingerman * at any iteration, thus setting minimal number of iterations as 0. 23396ccf49f7SEduard Zingerman */ 23406ccf49f7SEduard Zingerman iters->min_header_count = loop->exits_cnt == 1 ? iters->max_header_count : 0; 23416ccf49f7SEduard Zingerman return true; 23426ccf49f7SEduard Zingerman } 23436ccf49f7SEduard Zingerman 23446ccf49f7SEduard Zingerman static void mark_scev_reg_scratched(struct bpf_verifier_env *env, u32 r) 23456ccf49f7SEduard Zingerman { 23466ccf49f7SEduard Zingerman if (r < MAX_BPF_REG) 23476ccf49f7SEduard Zingerman mark_reg_scratched(env, r); 23486ccf49f7SEduard Zingerman else 23496ccf49f7SEduard Zingerman mark_stack_slot_scratched(env, r - __MAX_BPF_REG); 23506ccf49f7SEduard Zingerman } 23516ccf49f7SEduard Zingerman 23526ccf49f7SEduard Zingerman /* 23536ccf49f7SEduard Zingerman * An unknown scalar is its own widening. 23546ccf49f7SEduard Zingerman * Stack bytes without a value are represented by scev->unknown_reg. 23556ccf49f7SEduard Zingerman */ 23566ccf49f7SEduard Zingerman static bool is_unbound_scev_reg(struct bpf_verifier_env *env, const struct bpf_func_state *st, 23576ccf49f7SEduard Zingerman u32 r) 23586ccf49f7SEduard Zingerman { 23596ccf49f7SEduard Zingerman const struct bpf_reg_state *reg = scev_reg_for_read(env, st, r); 23606ccf49f7SEduard Zingerman 23616ccf49f7SEduard Zingerman return reg && reg->type == SCALAR_VALUE && !reg->id && reg->step <= 1 && 23626ccf49f7SEduard Zingerman tnum_is_unknown(reg->var_off) && 23636ccf49f7SEduard Zingerman reg->r64.size == U64_MAX && reg->r32.size == U32_MAX; 23646ccf49f7SEduard Zingerman } 23656ccf49f7SEduard Zingerman 23666ccf49f7SEduard Zingerman /* Main logic in verifier.c forbids varying offsets for certain register types. */ 23676ccf49f7SEduard Zingerman static bool is_widenable_reg_type(const struct bpf_reg_state *reg) 23686ccf49f7SEduard Zingerman { 23696ccf49f7SEduard Zingerman if (type_may_be_null(reg->type)) 23706ccf49f7SEduard Zingerman return false; 23716ccf49f7SEduard Zingerman 23726ccf49f7SEduard Zingerman switch (base_type(reg->type)) { 23736ccf49f7SEduard Zingerman case SCALAR_VALUE: 23746ccf49f7SEduard Zingerman case PTR_TO_MAP_VALUE: 23756ccf49f7SEduard Zingerman case PTR_TO_MAP_KEY: 23766ccf49f7SEduard Zingerman case PTR_TO_STACK: 23776ccf49f7SEduard Zingerman case PTR_TO_PACKET: 23786ccf49f7SEduard Zingerman case PTR_TO_PACKET_META: 23796ccf49f7SEduard Zingerman case PTR_TO_MEM: 23806ccf49f7SEduard Zingerman case PTR_TO_BUF: 23816ccf49f7SEduard Zingerman case PTR_TO_BTF_ID: 23826ccf49f7SEduard Zingerman return true; 23836ccf49f7SEduard Zingerman default: 23846ccf49f7SEduard Zingerman return false; 23856ccf49f7SEduard Zingerman } 23866ccf49f7SEduard Zingerman } 23876ccf49f7SEduard Zingerman 23886ccf49f7SEduard Zingerman static void scratch_widened_reg_id(struct bpf_verifier_env *env, struct bpf_reg_state *reg) 23896ccf49f7SEduard Zingerman { 23906ccf49f7SEduard Zingerman switch (base_type(reg->type)) { 23916ccf49f7SEduard Zingerman case SCALAR_VALUE: 23926ccf49f7SEduard Zingerman reg->id = 0; 23936ccf49f7SEduard Zingerman break; 23946ccf49f7SEduard Zingerman case PTR_TO_PACKET: 23956ccf49f7SEduard Zingerman case PTR_TO_PACKET_META: 23966ccf49f7SEduard Zingerman reg->id = ++env->id_gen; 23976ccf49f7SEduard Zingerman break; 23986ccf49f7SEduard Zingerman default: 23996ccf49f7SEduard Zingerman break; 24006ccf49f7SEduard Zingerman } 24016ccf49f7SEduard Zingerman } 24026ccf49f7SEduard Zingerman 24036ccf49f7SEduard Zingerman /* Check that ANY leaves can be unioned with r's loop-entry value. */ 24046ccf49f7SEduard Zingerman static bool is_widenable_any(struct bpf_verifier_env *env, struct bpf_func_state *loop_entry, 24056ccf49f7SEduard Zingerman struct env *header_env, u32 r, u32 id) 24066ccf49f7SEduard Zingerman { 24076ccf49f7SEduard Zingerman const struct bpf_reg_state *reg, *leaf_reg; 24086ccf49f7SEduard Zingerman struct scev *scev = env->scev; 24096ccf49f7SEduard Zingerman u32 l, ra, rr, leaf, order; 24106ccf49f7SEduard Zingerman s64 imm; 24116ccf49f7SEduard Zingerman 24126ccf49f7SEduard Zingerman if (!is_any(scev, id, &l, &rr)) 24136ccf49f7SEduard Zingerman return false; 24146ccf49f7SEduard Zingerman reg = scev_reg_for_read(env, loop_entry, r); 24156ccf49f7SEduard Zingerman if (!reg || !is_widenable_reg_type(reg)) 24166ccf49f7SEduard Zingerman return false; 24176ccf49f7SEduard Zingerman 24186ccf49f7SEduard Zingerman scev->stack_sz = 0; 24196ccf49f7SEduard Zingerman expr_stack_push(scev, id); 24206ccf49f7SEduard Zingerman while (expr_next(scev, &id, &order)) { 24216ccf49f7SEduard Zingerman if (order & DEPTH_LIMIT) 24226ccf49f7SEduard Zingerman return false; 24236ccf49f7SEduard Zingerman if (!(order & PRE) || is_any(scev, id, &l, &rr)) 24246ccf49f7SEduard Zingerman continue; 24256ccf49f7SEduard Zingerman if (is_imm(scev, id, &imm)) { 24266ccf49f7SEduard Zingerman if (reg->type != SCALAR_VALUE) 24276ccf49f7SEduard Zingerman return false; 24286ccf49f7SEduard Zingerman } else if (is_reg(scev, id, &leaf)) { 24296ccf49f7SEduard Zingerman /* Other leaves must denote loop-invariant registers. */ 24306ccf49f7SEduard Zingerman if (leaf != r && 24316ccf49f7SEduard Zingerman !(is_reg(scev, header_env->reg2scev[leaf], &ra) && ra == leaf)) 24326ccf49f7SEduard Zingerman return false; 24336ccf49f7SEduard Zingerman leaf_reg = scev_reg_for_read(env, loop_entry, leaf); 24346ccf49f7SEduard Zingerman if (!leaf_reg || !bpf_reg_union_compatible(reg, leaf_reg)) 24356ccf49f7SEduard Zingerman return false; 24366ccf49f7SEduard Zingerman } else { 24376ccf49f7SEduard Zingerman return false; 24386ccf49f7SEduard Zingerman } 24396ccf49f7SEduard Zingerman } 24406ccf49f7SEduard Zingerman return true; 24416ccf49f7SEduard Zingerman } 24426ccf49f7SEduard Zingerman 24436ccf49f7SEduard Zingerman struct bounds { 2444*32e96257SEduard Zingerman struct cnum64 r64; 2445*32e96257SEduard Zingerman struct cnum32 r32; 24466ccf49f7SEduard Zingerman u16 base; 24476ccf49f7SEduard Zingerman u16 step; 24486ccf49f7SEduard Zingerman }; 24496ccf49f7SEduard Zingerman 2450*32e96257SEduard Zingerman static void log_bounds(struct bpf_verifier_env *env, const struct bounds *bounds) 2451*32e96257SEduard Zingerman { 2452*32e96257SEduard Zingerman struct bpf_verifier_log *log = &env->log; 2453*32e96257SEduard Zingerman 2454*32e96257SEduard Zingerman bpf_verbose_snum(env, cnum64_smin(bounds->r64)); 2455*32e96257SEduard Zingerman bpf_log(log, ".."); 2456*32e96257SEduard Zingerman bpf_verbose_snum(env, cnum64_smax(bounds->r64)); 2457*32e96257SEduard Zingerman if (bounds->r32.size < U32_MAX) { 2458*32e96257SEduard Zingerman bpf_log(log, " (s32 "); 2459*32e96257SEduard Zingerman bpf_verbose_snum(env, cnum32_smin(bounds->r32)); 2460*32e96257SEduard Zingerman bpf_log(log, ".."); 2461*32e96257SEduard Zingerman bpf_verbose_snum(env, cnum32_smax(bounds->r32)); 2462*32e96257SEduard Zingerman bpf_log(log, ")"); 2463*32e96257SEduard Zingerman } 2464*32e96257SEduard Zingerman bpf_log(log, " step %u", bounds->step); 2465*32e96257SEduard Zingerman } 2466*32e96257SEduard Zingerman 2467*32e96257SEduard Zingerman struct linear_coefs { 2468*32e96257SEduard Zingerman u32 base_reg; 2469*32e96257SEduard Zingerman s64 slope; 2470*32e96257SEduard Zingerman bool zext32; 2471*32e96257SEduard Zingerman }; 2472*32e96257SEduard Zingerman 2473*32e96257SEduard Zingerman static bool is_simple_linear(struct scev *scev, u32 id, struct linear_coefs *out) 24746ccf49f7SEduard Zingerman { 24756ccf49f7SEduard Zingerman u32 base, slope; 24766ccf49f7SEduard Zingerman 2477*32e96257SEduard Zingerman return is_linear_or_linear32(scev, id, &base, &slope, &out->zext32) && 2478*32e96257SEduard Zingerman is_reg(scev, base, &out->base_reg) && 2479*32e96257SEduard Zingerman is_imm(scev, slope, &out->slope) && 2480*32e96257SEduard Zingerman out->slope <= S16_MAX && 2481*32e96257SEduard Zingerman out->slope >= S16_MIN && 2482*32e96257SEduard Zingerman out->slope != 0; 24836ccf49f7SEduard Zingerman } 24846ccf49f7SEduard Zingerman 2485*32e96257SEduard Zingerman static struct cnum64 cnum64_zext32(struct cnum32 r32) 24866ccf49f7SEduard Zingerman { 2487*32e96257SEduard Zingerman return cnum64_from_urange(cnum32_umin(r32), cnum32_umax(r32)); 2488*32e96257SEduard Zingerman } 2489*32e96257SEduard Zingerman 2490*32e96257SEduard Zingerman /* Compute the range an induction variable in `reg` spans over the loop. */ 2491*32e96257SEduard Zingerman static void linear_bounds(struct bpf_reg_state *reg, u32 max_header_count, 2492*32e96257SEduard Zingerman struct linear_coefs *coefs, struct bounds *out) 2493*32e96257SEduard Zingerman { 2494*32e96257SEduard Zingerman s64 slope = coefs->slope; 24956ccf49f7SEduard Zingerman s64 slope_abs = slope < 0 ? -slope : slope; 24966ccf49f7SEduard Zingerman s64 min_val = reg_smin(reg); 24976ccf49f7SEduard Zingerman s64 max_val = reg_smax(reg); 2498*32e96257SEduard Zingerman struct cnum64 r64; 2499*32e96257SEduard Zingerman struct cnum32 r32; 25006ccf49f7SEduard Zingerman s64 total_change; 25016ccf49f7SEduard Zingerman bool overflow; 25026ccf49f7SEduard Zingerman 25036ccf49f7SEduard Zingerman overflow = check_mul_overflow(slope, (s64)max_header_count - 1, &total_change) || 25046ccf49f7SEduard Zingerman (slope > 0 && check_add_overflow(max_val, total_change, &max_val)) || 25056ccf49f7SEduard Zingerman (slope < 0 && check_add_overflow(min_val, total_change, &min_val)); 2506*32e96257SEduard Zingerman r64 = overflow ? CNUM64_UNBOUNDED : cnum64_from_srange(min_val, max_val); 2507*32e96257SEduard Zingerman r32 = CNUM32_UNBOUNDED; 2508*32e96257SEduard Zingerman if (coefs->zext32) { 2509*32e96257SEduard Zingerman r32 = cnum32_from_cnum64(r64); 2510*32e96257SEduard Zingerman r64 = cnum64_zext32(r32); 2511*32e96257SEduard Zingerman /* 2512*32e96257SEduard Zingerman * 32-bit iteration overflow is equivalent to subtracting N * 2**32: 2513*32e96257SEduard Zingerman * (base + slope * k) % slope ≠ (base + slope * k - N * 2**32) % slope. 2514*32e96257SEduard Zingerman */ 2515*32e96257SEduard Zingerman overflow |= cnum32_contains(r32, 0) && cnum32_contains(r32, U32_MAX); 2516*32e96257SEduard Zingerman /* 2517*32e96257SEduard Zingerman * The entry and zero-extended values must agree on how they define `base`, 2518*32e96257SEduard Zingerman * otherwise `base + slope * k` would define different sets of points between 2519*32e96257SEduard Zingerman * the two. 2520*32e96257SEduard Zingerman */ 2521*32e96257SEduard Zingerman overflow |= imod(reg_smin(reg), slope_abs) != 2522*32e96257SEduard Zingerman imod(cnum64_smin(r64), slope_abs); 2523*32e96257SEduard Zingerman /* 2524*32e96257SEduard Zingerman * Full range is a union of a reg's value at loop entry, 2525*32e96257SEduard Zingerman * plus a range produced by 32-bit iteration. 2526*32e96257SEduard Zingerman */ 2527*32e96257SEduard Zingerman r64 = cnum64_union(reg->r64, r64); 2528*32e96257SEduard Zingerman r32 = cnum32_union(reg->r32, r32); 2529*32e96257SEduard Zingerman } 25306ccf49f7SEduard Zingerman /* 25316ccf49f7SEduard Zingerman * If the entry value is a single point the value set is 'v + slope * k', 25326ccf49f7SEduard Zingerman * so the step is |slope|. Otherwise, only the power-of-two alignment 25336ccf49f7SEduard Zingerman * shared by the entry value and the slope. 25346ccf49f7SEduard Zingerman */ 25356ccf49f7SEduard Zingerman if (cnum64_is_const(reg->r64) && !overflow) { 25366ccf49f7SEduard Zingerman out->step = slope_abs; 2537*32e96257SEduard Zingerman out->base = imod(reg_smin(reg), out->step); 25386ccf49f7SEduard Zingerman } else { 25396ccf49f7SEduard Zingerman out->step = 1u << min_t(u32, tnum_alignment(reg->var_off), __ffs(slope_abs)); 25406ccf49f7SEduard Zingerman out->base = 0; 25416ccf49f7SEduard Zingerman } 2542*32e96257SEduard Zingerman out->r64 = r64; 2543*32e96257SEduard Zingerman out->r32 = r32; 25446ccf49f7SEduard Zingerman } 25456ccf49f7SEduard Zingerman 25466ccf49f7SEduard Zingerman static int mark_expr_precise(struct bpf_verifier_env *env, struct bpf_func_state *st, u32 id, 25476ccf49f7SEduard Zingerman unsigned long *precise_regs) 25486ccf49f7SEduard Zingerman { 25496ccf49f7SEduard Zingerman struct scev *scev = env->scev; 25506ccf49f7SEduard Zingerman struct bpf_reg_state *reg; 25516ccf49f7SEduard Zingerman u32 r, order; 25526ccf49f7SEduard Zingerman 25536ccf49f7SEduard Zingerman scev->stack_sz = 0; 25546ccf49f7SEduard Zingerman expr_stack_push(scev, id); 25556ccf49f7SEduard Zingerman while (expr_next(scev, &id, &order)) { 25566ccf49f7SEduard Zingerman if (order & DEPTH_LIMIT) { 25576ccf49f7SEduard Zingerman verifier_bug(env, "scev precision marking exceeds expression depth limit"); 25586ccf49f7SEduard Zingerman return -EFAULT; 25596ccf49f7SEduard Zingerman } 25606ccf49f7SEduard Zingerman if (!(order & PRE) || !is_reg(scev, id, &r)) 25616ccf49f7SEduard Zingerman continue; 25626ccf49f7SEduard Zingerman /* Synthetic values have no spilled register to mark precise. */ 25636ccf49f7SEduard Zingerman reg = scev_reg_for_linear(st, r); 25646ccf49f7SEduard Zingerman if (reg && reg->type == SCALAR_VALUE) 25656ccf49f7SEduard Zingerman __set_bit(r, precise_regs); 25666ccf49f7SEduard Zingerman } 25676ccf49f7SEduard Zingerman return 0; 25686ccf49f7SEduard Zingerman } 25696ccf49f7SEduard Zingerman 25706ccf49f7SEduard Zingerman int bpf_compute_loop_iters(struct bpf_verifier_env *env, struct bpf_verifier_state *st, 25716ccf49f7SEduard Zingerman struct bpf_loop_iters *iters) 25726ccf49f7SEduard Zingerman { 25736ccf49f7SEduard Zingerman struct bpf_func_state *cur_func = st->frame[st->curframe]; 25746ccf49f7SEduard Zingerman struct bpf_insn_aux_data *aux = env->insn_aux_data; 25756ccf49f7SEduard Zingerman struct bpf_verifier_log *log = &env->log; 25766ccf49f7SEduard Zingerman struct scev *scev = env->scev; 25776ccf49f7SEduard Zingerman struct env *header_env; 25786ccf49f7SEduard Zingerman struct linear_latch latch, best; 2579*32e96257SEduard Zingerman struct linear_coefs coefs; 25806ccf49f7SEduard Zingerman struct bpf_backedge *backedge; 25816ccf49f7SEduard Zingerman struct bpf_loop_iters tmp; 25826ccf49f7SEduard Zingerman struct bpf_loop *loop; 25836ccf49f7SEduard Zingerman int insn_idx = st->insn_idx; 25846ccf49f7SEduard Zingerman bool found = false; 25856ccf49f7SEduard Zingerman int linear_latch; 25866ccf49f7SEduard Zingerman int latch_idx; 25876ccf49f7SEduard Zingerman int err, j; 2588*32e96257SEduard Zingerman u32 r; 25896ccf49f7SEduard Zingerman 25906ccf49f7SEduard Zingerman if (!env->allow_uninit_stack) 25916ccf49f7SEduard Zingerman return 0; 25926ccf49f7SEduard Zingerman 25936ccf49f7SEduard Zingerman /* 25946ccf49f7SEduard Zingerman * If insn_idx is a loop header for a reducible loop with a single backedge. 25956ccf49f7SEduard Zingerman * loop is NULL for secondary entries to irreducible loops. 25966ccf49f7SEduard Zingerman */ 25976ccf49f7SEduard Zingerman loop = aux[insn_idx].loop; 25986ccf49f7SEduard Zingerman if (!loop || loop->irreducible || loop->backedges_cnt != 1 || loop->backedges_overflow || 25996ccf49f7SEduard Zingerman loop->exits_overflow) { 26006ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26016ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, unsupported loop:%s%s%s\n", insn_idx, 26026ccf49f7SEduard Zingerman !loop || loop->irreducible ? " irreducible" : "", 26036ccf49f7SEduard Zingerman loop && loop->backedges_cnt > 1 ? " multiple backedges" : "", 26046ccf49f7SEduard Zingerman loop && loop->exits_overflow ? " too many exits" : ""); 26056ccf49f7SEduard Zingerman return 0; 26066ccf49f7SEduard Zingerman } 26076ccf49f7SEduard Zingerman 26086ccf49f7SEduard Zingerman /* If this backedge has a latch */ 26096ccf49f7SEduard Zingerman backedge = &loop->backedges[0]; 26106ccf49f7SEduard Zingerman if (!backedge->latches_cnt) { 26116ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26126ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, latch not identified\n", insn_idx); 26136ccf49f7SEduard Zingerman return 0; 26146ccf49f7SEduard Zingerman } 26156ccf49f7SEduard Zingerman 26166ccf49f7SEduard Zingerman /* 26176ccf49f7SEduard Zingerman * Every condition dominating the backedge bounds the number of 26186ccf49f7SEduard Zingerman * iterations from above, keep the smallest bound. 26196ccf49f7SEduard Zingerman */ 26206ccf49f7SEduard Zingerman for (j = 0; j < backedge->latches_cnt; j++) { 26216ccf49f7SEduard Zingerman latch_idx = backedge->latches[j]; 26226ccf49f7SEduard Zingerman linear_latch = match_linear_latch(env, insn_idx, latch_idx, &latch); 26236ccf49f7SEduard Zingerman if (linear_latch < 0) 26246ccf49f7SEduard Zingerman return linear_latch; 26256ccf49f7SEduard Zingerman if (!linear_latch) { 26266ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26276ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, non-linear %s at %d\n", 26286ccf49f7SEduard Zingerman insn_idx, j ? "exit" : "latch", latch_idx); 26296ccf49f7SEduard Zingerman continue; 26306ccf49f7SEduard Zingerman } 26316ccf49f7SEduard Zingerman if (!compute_max_iters(env, cur_func, &latch, &tmp)) { 26326ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26336ccf49f7SEduard Zingerman bpf_log(log, 26346ccf49f7SEduard Zingerman "loop header at %d, can't compute iterations count at %d\n", 26356ccf49f7SEduard Zingerman insn_idx, latch_idx); 26366ccf49f7SEduard Zingerman continue; 26376ccf49f7SEduard Zingerman } 26386ccf49f7SEduard Zingerman if (!found || tmp.max_header_count < iters->max_header_count) { 26396ccf49f7SEduard Zingerman iters->max_header_count = tmp.max_header_count; 26406ccf49f7SEduard Zingerman best = latch; 26416ccf49f7SEduard Zingerman } 26426ccf49f7SEduard Zingerman iters->min_header_count = found ? min(iters->min_header_count, tmp.min_header_count) 26436ccf49f7SEduard Zingerman : tmp.min_header_count; 26446ccf49f7SEduard Zingerman found = true; 26456ccf49f7SEduard Zingerman } 26466ccf49f7SEduard Zingerman if (!found) { 26476ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26486ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, can't compute iterations count\n", insn_idx); 26496ccf49f7SEduard Zingerman return 0; 26506ccf49f7SEduard Zingerman } 26516ccf49f7SEduard Zingerman latch = best; 26526ccf49f7SEduard Zingerman 26536ccf49f7SEduard Zingerman if (iters->max_header_count == 0) { 26546ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26556ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, 0 iterations count\n", insn_idx); 26566ccf49f7SEduard Zingerman return 0; 26576ccf49f7SEduard Zingerman } 26586ccf49f7SEduard Zingerman 26596ccf49f7SEduard Zingerman if (iters->max_header_count == U32_MAX) { 26606ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) 26616ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, inf iterations count\n", insn_idx); 26626ccf49f7SEduard Zingerman return 0; 26636ccf49f7SEduard Zingerman } 26646ccf49f7SEduard Zingerman 26656ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) { 26666ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, header_count is ", insn_idx); 26676ccf49f7SEduard Zingerman if (iters->min_header_count == iters->max_header_count) 26686ccf49f7SEduard Zingerman bpf_log(log, "%u ", iters->max_header_count); 26696ccf49f7SEduard Zingerman else 26706ccf49f7SEduard Zingerman bpf_log(log, "[%u..%u] ", iters->min_header_count, iters->max_header_count); 26716ccf49f7SEduard Zingerman bpf_log(log, "\n"); 26726ccf49f7SEduard Zingerman } 26736ccf49f7SEduard Zingerman 26746ccf49f7SEduard Zingerman err = bpf_live_stack_query_init(env, st); 26756ccf49f7SEduard Zingerman if (err) 26766ccf49f7SEduard Zingerman return err; 26776ccf49f7SEduard Zingerman 26786ccf49f7SEduard Zingerman header_env = find_header_env(scev, insn_idx); 26796ccf49f7SEduard Zingerman for (r = 0; r < REGS_NUM; r++) { 26806ccf49f7SEduard Zingerman struct bpf_reg_state *reg; 26816ccf49f7SEduard Zingerman u32 ra, r_scev, r_expr; 2682088a5477SEduard Zingerman bool spill_base = false; 26836ccf49f7SEduard Zingerman 26846ccf49f7SEduard Zingerman if (!scev_reg_alive(env, st, r)) 26856ccf49f7SEduard Zingerman continue; 26866ccf49f7SEduard Zingerman /* 26876ccf49f7SEduard Zingerman * A heuristic: 26886ccf49f7SEduard Zingerman * Ignore SCEVs computed for unbound values and treat those as widened. 26896ccf49f7SEduard Zingerman * This is poor man's modelling of e.g. bpf_probe_read_kernel() effect 26906ccf49f7SEduard Zingerman * on stack, when called from a subprogram. Currently this would produce 26916ccf49f7SEduard Zingerman * an unknown ('?') SCEV as a summary of a subprogram call effects. 26926ccf49f7SEduard Zingerman * Ideally, this should be computed as an OPAQUE value. 26936ccf49f7SEduard Zingerman * However, that would require tracking STACK_MISC writes in the 26946ccf49f7SEduard Zingerman * liveness analysis. Not implemented yet. 26956ccf49f7SEduard Zingerman */ 26966ccf49f7SEduard Zingerman if (is_unbound_scev_reg(env, cur_func, r)) 26976ccf49f7SEduard Zingerman continue; 26986ccf49f7SEduard Zingerman 26996ccf49f7SEduard Zingerman r_scev = header_env->reg2scev[r]; 27006ccf49f7SEduard Zingerman reg = scev_reg_for_linear(cur_func, r); 27016ccf49f7SEduard Zingerman /* If SCEV for r is (linear <reg> <slope>) */ 2702*32e96257SEduard Zingerman if (reg && is_simple_linear(scev, r_scev, &coefs) && is_widenable_reg_type(reg)) { 2703088a5477SEduard Zingerman /* Spills at varying offsets lose precision */ 2704088a5477SEduard Zingerman if (test_bit(r, loop->store_base_regs)) { 2705088a5477SEduard Zingerman spill_base = true; 2706088a5477SEduard Zingerman goto cant_widen; 2707088a5477SEduard Zingerman } 27086ccf49f7SEduard Zingerman continue; 27096ccf49f7SEduard Zingerman } 27106ccf49f7SEduard Zingerman 27116ccf49f7SEduard Zingerman /* rA = rA, loop does not change this reg */ 27126ccf49f7SEduard Zingerman if (is_reg(scev, r_scev, &ra) && r == ra) 27136ccf49f7SEduard Zingerman continue; 27146ccf49f7SEduard Zingerman 27156ccf49f7SEduard Zingerman /* (any 1 (any 2 (any 3 4))) */ 27166ccf49f7SEduard Zingerman if (is_widenable_any(env, cur_func, header_env, r, r_scev)) { 2717088a5477SEduard Zingerman if (test_bit(r, loop->store_base_regs)) { 2718088a5477SEduard Zingerman spill_base = true; 2719088a5477SEduard Zingerman goto cant_widen; 2720088a5477SEduard Zingerman } 27216ccf49f7SEduard Zingerman continue; 27226ccf49f7SEduard Zingerman } 2723088a5477SEduard Zingerman cant_widen: 27246ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) { 27256ccf49f7SEduard Zingerman r_expr = header_env->reg2expr[r]; 27266ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, can't widen ", insn_idx); 27276ccf49f7SEduard Zingerman log_reg(env, r); 27286ccf49f7SEduard Zingerman bpf_log(log, ", expr is "); 27296ccf49f7SEduard Zingerman log_expr(env, r_expr); 2730088a5477SEduard Zingerman if (spill_base) 2731088a5477SEduard Zingerman bpf_log(log, ", requires exact stack-offset tracking"); 27326ccf49f7SEduard Zingerman bpf_log(log, "\n"); 27336ccf49f7SEduard Zingerman } 27346ccf49f7SEduard Zingerman return 0; 27356ccf49f7SEduard Zingerman } 27366ccf49f7SEduard Zingerman 27376ccf49f7SEduard Zingerman bitmap_zero(iters->precise_regs, REGS_NUM); 27386ccf49f7SEduard Zingerman err = mark_expr_precise(env, cur_func, latch.base_expr, iters->precise_regs); 27396ccf49f7SEduard Zingerman if (err) 27406ccf49f7SEduard Zingerman return err; 27416ccf49f7SEduard Zingerman err = mark_expr_precise(env, cur_func, latch.step_expr, iters->precise_regs); 27426ccf49f7SEduard Zingerman if (err) 27436ccf49f7SEduard Zingerman return err; 27446ccf49f7SEduard Zingerman err = mark_expr_precise(env, cur_func, latch.bound_expr, iters->precise_regs); 27456ccf49f7SEduard Zingerman if (err) 27466ccf49f7SEduard Zingerman return err; 27476ccf49f7SEduard Zingerman 27486ccf49f7SEduard Zingerman return 1; 27496ccf49f7SEduard Zingerman } 27506ccf49f7SEduard Zingerman 27516ccf49f7SEduard Zingerman /* bpf_compute_loop_iters() checked that every leaf can be unioned into acc. */ 27526ccf49f7SEduard Zingerman static int union_any_reg(struct bpf_verifier_env *env, struct bpf_func_state *loop_entry, 27536ccf49f7SEduard Zingerman struct bpf_reg_state *acc, u32 id) 27546ccf49f7SEduard Zingerman { 27556ccf49f7SEduard Zingerman struct bpf_reg_state *tmp = &env->fake_reg[0]; 27566ccf49f7SEduard Zingerman const struct bpf_reg_state *leaf_reg; 27576ccf49f7SEduard Zingerman struct scev *scev = env->scev; 27586ccf49f7SEduard Zingerman u32 l, r, leaf, order; 27596ccf49f7SEduard Zingerman s64 imm; 27606ccf49f7SEduard Zingerman int err; 27616ccf49f7SEduard Zingerman 27626ccf49f7SEduard Zingerman scev->stack_sz = 0; 27636ccf49f7SEduard Zingerman expr_stack_push(scev, id); 27646ccf49f7SEduard Zingerman while (expr_next(scev, &id, &order)) { 27656ccf49f7SEduard Zingerman if (order & DEPTH_LIMIT) { 27666ccf49f7SEduard Zingerman verifier_bug(env, "scev ANY union exceeds expression depth limit"); 27676ccf49f7SEduard Zingerman return -EFAULT; 27686ccf49f7SEduard Zingerman } 27696ccf49f7SEduard Zingerman if (!(order & PRE) || is_any(scev, id, &l, &r)) 27706ccf49f7SEduard Zingerman continue; 27716ccf49f7SEduard Zingerman if (is_imm(scev, id, &imm)) { 27726ccf49f7SEduard Zingerman bpf_mark_reg_known_scalar(tmp, imm); 27736ccf49f7SEduard Zingerman leaf_reg = tmp; 27746ccf49f7SEduard Zingerman } else if (is_reg(scev, id, &leaf)) { 27756ccf49f7SEduard Zingerman leaf_reg = scev_reg_for_read(env, loop_entry, leaf); 27766ccf49f7SEduard Zingerman if (verifier_bug_if(!leaf_reg, env, "unreadable SCEV ANY leaf %u", leaf)) 27776ccf49f7SEduard Zingerman return -EFAULT; 27786ccf49f7SEduard Zingerman } else { 27796ccf49f7SEduard Zingerman verifier_bug(env, "scev ANY union has an unsupported leaf"); 27806ccf49f7SEduard Zingerman return -EFAULT; 27816ccf49f7SEduard Zingerman } 27826ccf49f7SEduard Zingerman err = bpf_reg_union(env, acc, leaf_reg); 27836ccf49f7SEduard Zingerman if (err) 27846ccf49f7SEduard Zingerman return err; 27856ccf49f7SEduard Zingerman } 27866ccf49f7SEduard Zingerman return 0; 27876ccf49f7SEduard Zingerman } 27886ccf49f7SEduard Zingerman 27896ccf49f7SEduard Zingerman int bpf_widen_scev_regs(struct bpf_verifier_env *env, struct bpf_verifier_state *st, 27906ccf49f7SEduard Zingerman struct bpf_verifier_state *loop_entry, struct bpf_loop_iters *iters) 27916ccf49f7SEduard Zingerman { 27926ccf49f7SEduard Zingerman struct bpf_func_state *cur_func = st->frame[st->curframe]; 27936ccf49f7SEduard Zingerman struct bpf_func_state *entry_func = loop_entry->frame[loop_entry->curframe]; 27946ccf49f7SEduard Zingerman struct bpf_verifier_log *log = &env->log; 27956ccf49f7SEduard Zingerman struct scev *scev = env->scev; 27966ccf49f7SEduard Zingerman struct bpf_reg_state *reg; 27976ccf49f7SEduard Zingerman struct env *header_env; 2798*32e96257SEduard Zingerman struct linear_coefs coefs; 27996ccf49f7SEduard Zingerman struct bounds bounds; 2800*32e96257SEduard Zingerman u32 r, r_expr, a, b; 28016ccf49f7SEduard Zingerman int insn_idx = st->insn_idx; 28026ccf49f7SEduard Zingerman int err; 28036ccf49f7SEduard Zingerman 28046ccf49f7SEduard Zingerman for_each_set_bit(r, iters->precise_regs, REGS_NUM) { 28056ccf49f7SEduard Zingerman if (r < MAX_BPF_REG) 28066ccf49f7SEduard Zingerman bpf_bt_set_frame_reg(&env->bt, st->curframe, r); 28076ccf49f7SEduard Zingerman else 28086ccf49f7SEduard Zingerman bpf_bt_set_frame_slot(&env->bt, st->curframe, r - MAX_BPF_REG); 28096ccf49f7SEduard Zingerman } 28106ccf49f7SEduard Zingerman err = bpf_mark_chain_precision(env, st, -1, NULL); 28116ccf49f7SEduard Zingerman if (err) 28126ccf49f7SEduard Zingerman return err; 28136ccf49f7SEduard Zingerman 28146ccf49f7SEduard Zingerman header_env = find_header_env(scev, insn_idx); 28156ccf49f7SEduard Zingerman for (r = 0; r < REGS_NUM; r++) { 28166ccf49f7SEduard Zingerman if (!scev_reg_alive(env, st, r) || is_unbound_scev_reg(env, cur_func, r)) 28176ccf49f7SEduard Zingerman continue; 28186ccf49f7SEduard Zingerman 28196ccf49f7SEduard Zingerman r_expr = header_env->reg2scev[r]; 28206ccf49f7SEduard Zingerman /* If SCEV for r is (linear <reg> <slope>)*/ 2821*32e96257SEduard Zingerman if (is_simple_linear(scev, r_expr, &coefs) && coefs.base_reg == r) { 28226ccf49f7SEduard Zingerman err = scev_reg_for_write(env, cur_func, r, ®); 28236ccf49f7SEduard Zingerman if (err) 28246ccf49f7SEduard Zingerman return err; 2825*32e96257SEduard Zingerman linear_bounds(reg, iters->max_header_count, &coefs, &bounds); 28266ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) { 28276ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, widening ", insn_idx); 28286ccf49f7SEduard Zingerman log_reg(env, r); 28296ccf49f7SEduard Zingerman bpf_log(log, " to "); 2830*32e96257SEduard Zingerman log_bounds(env, &bounds); 2831*32e96257SEduard Zingerman bpf_log(log, "\n"); 28326ccf49f7SEduard Zingerman } 28336ccf49f7SEduard Zingerman scratch_widened_reg_id(env, reg); 2834*32e96257SEduard Zingerman err = bpf_set_reg_range(env, reg, bounds.r64, bounds.r32, 2835*32e96257SEduard Zingerman bounds.base, bounds.step); 28366ccf49f7SEduard Zingerman if (err) 28376ccf49f7SEduard Zingerman return err; 28386ccf49f7SEduard Zingerman mark_scev_reg_scratched(env, r); 28396ccf49f7SEduard Zingerman } else if (is_any(scev, r_expr, &a, &b)) { 28406ccf49f7SEduard Zingerman err = scev_reg_for_write(env, cur_func, r, ®); 28416ccf49f7SEduard Zingerman if (err) 28426ccf49f7SEduard Zingerman return err; 28436ccf49f7SEduard Zingerman err = union_any_reg(env, entry_func, reg, r_expr); 28446ccf49f7SEduard Zingerman if (err) 28456ccf49f7SEduard Zingerman return err; 28466ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) { 28476ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, widening ", insn_idx); 28486ccf49f7SEduard Zingerman log_reg(env, r); 28496ccf49f7SEduard Zingerman bpf_log(log, " to "); 28506ccf49f7SEduard Zingerman bpf_verbose_snum(env, reg_smin(reg)); 28516ccf49f7SEduard Zingerman bpf_log(log, ".."); 28526ccf49f7SEduard Zingerman bpf_verbose_snum(env, reg_smax(reg)); 28536ccf49f7SEduard Zingerman bpf_log(log, " step %u\n", reg->step); 28546ccf49f7SEduard Zingerman } 28556ccf49f7SEduard Zingerman scratch_widened_reg_id(env, reg); 28566ccf49f7SEduard Zingerman mark_scev_reg_scratched(env, r); 28576ccf49f7SEduard Zingerman } 28586ccf49f7SEduard Zingerman } 28596ccf49f7SEduard Zingerman return 1; 28606ccf49f7SEduard Zingerman } 28616ccf49f7SEduard Zingerman 28626ccf49f7SEduard Zingerman int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur_func_state, u32 insn_idx, 28636ccf49f7SEduard Zingerman struct bpf_verifier_state *entry_state, u32 max_header_count) 28646ccf49f7SEduard Zingerman { 28656ccf49f7SEduard Zingerman struct bpf_func_state *entry_st = entry_state->frame[entry_state->curframe]; 28666ccf49f7SEduard Zingerman struct bpf_verifier_log *log = &env->log; 28676ccf49f7SEduard Zingerman struct bpf_reg_state *reg, *entry_reg; 28686ccf49f7SEduard Zingerman struct scev *scev = env->scev; 2869*32e96257SEduard Zingerman struct linear_coefs coefs; 28706ccf49f7SEduard Zingerman struct env *header_env; 28716ccf49f7SEduard Zingerman struct bounds bounds; 2872*32e96257SEduard Zingerman u32 r; 28736ccf49f7SEduard Zingerman int err; 28746ccf49f7SEduard Zingerman 28756ccf49f7SEduard Zingerman if (entry_state->curframe != cur_func_state->frameno) { 28766ccf49f7SEduard Zingerman verifier_bug(env, "clamping registers for a wrong frame: %d vs %d\n", 28776ccf49f7SEduard Zingerman entry_state->curframe, cur_func_state->frameno); 28786ccf49f7SEduard Zingerman return -EFAULT; 28796ccf49f7SEduard Zingerman } 28806ccf49f7SEduard Zingerman 28816ccf49f7SEduard Zingerman header_env = find_header_env(scev, insn_idx); 28826ccf49f7SEduard Zingerman for (r = 0; r < REGS_NUM; r++) { 28836ccf49f7SEduard Zingerman /* If SCEV for r is (linear <reg> <slope>)*/ 2884*32e96257SEduard Zingerman if (!is_simple_linear(scev, header_env->reg2scev[r], &coefs) || 2885*32e96257SEduard Zingerman coefs.base_reg != r) 28866ccf49f7SEduard Zingerman continue; 28876ccf49f7SEduard Zingerman 28886ccf49f7SEduard Zingerman entry_reg = scev_reg_for_linear(entry_st, r); 28896ccf49f7SEduard Zingerman reg = scev_reg_for_linear(cur_func_state, r); 28906ccf49f7SEduard Zingerman if (!entry_reg || !reg || entry_reg->type == NOT_INIT || reg->type == NOT_INIT || 28916ccf49f7SEduard Zingerman is_unbound_scev_reg(env, entry_st, r)) 28926ccf49f7SEduard Zingerman continue; 28936ccf49f7SEduard Zingerman 2894*32e96257SEduard Zingerman linear_bounds(entry_reg, max_header_count, &coefs, &bounds); 2895*32e96257SEduard Zingerman bounds.r64 = cnum64_intersect(reg->r64, bounds.r64); 2896*32e96257SEduard Zingerman bounds.r32 = cnum32_intersect(reg->r32, bounds.r32); 2897*32e96257SEduard Zingerman if (cnum64_is_empty(bounds.r64)) { 28986ccf49f7SEduard Zingerman verifier_bug(env, "scev clamp produced empty range for r%d", r); 28996ccf49f7SEduard Zingerman return -EFAULT; 29006ccf49f7SEduard Zingerman } 29016ccf49f7SEduard Zingerman if (log->level & BPF_LOG_LEVEL2) { 29026ccf49f7SEduard Zingerman bpf_log(log, "loop header at %d, clamping ", insn_idx); 29036ccf49f7SEduard Zingerman log_reg(env, r); 29046ccf49f7SEduard Zingerman bpf_log(log, " to "); 2905*32e96257SEduard Zingerman log_bounds(env, &bounds); 2906*32e96257SEduard Zingerman bpf_log(log, "\n"); 29076ccf49f7SEduard Zingerman } 29086ccf49f7SEduard Zingerman scratch_widened_reg_id(env, reg); 2909*32e96257SEduard Zingerman err = bpf_set_reg_range(env, reg, bounds.r64, bounds.r32, 2910*32e96257SEduard Zingerman bounds.base, bounds.step); 29116ccf49f7SEduard Zingerman if (err) 29126ccf49f7SEduard Zingerman return err; 29136ccf49f7SEduard Zingerman mark_scev_reg_scratched(env, r); 29146ccf49f7SEduard Zingerman } 29156ccf49f7SEduard Zingerman return 0; 29166ccf49f7SEduard Zingerman } 2917