eBPF Verifer CVE-2021-3493分析与利用

eBPF破绽CVE-2021-3490剖析与应用

破绽剖析

​ verifier为了跟踪每一个存放器的边境值(避免越界读写),会对存放器的每一次运算模仿求解边境值(最大/最小值),由于存放器是64bits,但是实践参与运算可能是32bits,因而实践会对32/64都停止边境校验,由adjust_scalar_min_max_valsadjust_reg_min_max_vals函数完成

/* WARNING: This function does calculations on 64-bit values, but the actual
 * execution may occur on 32-bit values. Therefore, things like bitshifts
 * need extra checks in the 32-bit case.
 */
static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
                      struct bpf_insn *insn,
                      struct bpf_reg_state *dst_reg,
                      struct bpf_reg_state src_reg)
{
    struct bpf_reg_state *regs = cur_regs(env);
    u8 opcode = BPF_OP(insn->code);
    ...
    switch (opcode) {
    case BPF_ADD:
        ret = sanitize_val_alu(env, insn);
        if (ret < 0) {
            verbose(env, "R%d tried to add from different pointers or scalars\n", dst);
            return ret;
        }
        scalar32_min_max_add(dst_reg, &src_reg);
        scalar_min_max_add(dst_reg, &src_reg);
        dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
        break;
    case BPF_SUB:
        ret = sanitize_val_alu(env, insn);
        if (ret < 0) {
            verbose(env, "R%d tried to sub from different pointers or scalars\n", dst);
            return ret;
        }
        scalar32_min_max_sub(dst_reg, &src_reg);
        scalar_min_max_sub(dst_reg, &src_reg);
        dst_reg->var_off = tnum_sub(dst_reg->var_off, src_reg.var_off);
        break;
    case BPF_MUL:
        dst_reg->var_off = tnum_mul(dst_reg->var_off, src_reg.var_off);
        scalar32_min_max_mul(dst_reg, &src_reg);
        scalar_min_max_mul(dst_reg, &src_reg);
        break;
    case BPF_AND:
        dst_reg->var_off = tnum_and(dst_reg->var_off, src_reg.var_off);
        scalar32_min_max_and(dst_reg, &src_reg);
        scalar_min_max_and(dst_reg, &src_reg);
        break;
    case BPF_OR:
        dst_reg->var_off = tnum_or(dst_reg->var_off, src_reg.var_off);
        scalar32_min_max_or(dst_reg, &src_reg);
        scalar_min_max_or(dst_reg, &src_reg);
        break;
    case BPF_LSH:
        if (umax_val >= insn_bitness) {
            /* Shifts greater than 31 or 63 are undefined.
             * This includes shifts by a negative number.
             */
            mark_reg_unknown(env, regs, insn->dst_reg);
            break;
        }
        if (alu32)
            scalar32_min_max_lsh(dst_reg, &src_reg);
        else
            scalar_min_max_lsh(dst_reg, &src_reg);
        break;
    case BPF_RSH:
        if (umax_val >= insn_bitness) {
            /* Shifts greater than 31 or 63 are undefined.
             * This includes shifts by a negative number.
             */
            mark_reg_unknown(env, regs, insn->dst_reg);
            break;
        }
        if (alu32)
            scalar32_min_max_rsh(dst_reg, &src_reg);
        else
            scalar_min_max_rsh(dst_reg, &src_reg);
        break;
    case BPF_ARSH:
        if (umax_val >= insn_bitness) {
            /* Shifts greater than 31 or 63 are undefined.
             * This includes shifts by a negative number.
             */
            mark_reg_unknown(env, regs, insn->dst_reg);
            break;
        }
        if (alu32)
            scalar32_min_max_arsh(dst_reg, &src_reg);
        else
            scalar_min_max_arsh(dst_reg, &src_reg);
        break;
    default:
        mark_reg_unknown(env, regs, insn->dst_reg);
        break;
    }

    /* ALU32 ops are zero extended into 64bit register */
    if (alu32)
        zext_32_to_64(dst_reg);

    __update_reg_bounds(dst_reg);
    __reg_deduce_bounds(dst_reg);
    __reg_bound_offset(dst_reg);
    return 0;
}
------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞15赞赏 分享
评论 共1条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片
    • 头像卡角0