Commit 0967f539 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'range-tracking-for-bpf_neg'

Song Liu says:

====================
Add range tracking for BPF_NEG. Please see commit log of 1/2 for more
details.
---

Changes v3 => v4:
1. Fix selftest verifier_value_ptr_arith.c. (Eduard)

v3: https://lore.kernel.org/bpf/20250624233328.313573-1-song@kernel.org/

Changes v2 => v3:
1. Minor changes in the selftests. (Eduard)

v2: https://lore.kernel.org/bpf/20250624220038.656646-1-song@kernel.org/

Changes v1 => v2:
1. Split new selftests to a separate patch. (Eduard)
2. Reset reg id on BPF_NEG. (Eduard)
3. Use env->fake_reg instead of a bpf_reg_state on the stack. (Eduard)
4. Add __msg for passing selftests.

v1: https://lore.kernel.org/bpf/20250624172320.2923031-1-song@kernel.org/
====================

Link: https://patch.msgid.link/20250625164025.3310203-1-song@kernel.org


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents d69bafe6 2945434e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ struct tnum tnum_arshift(struct tnum a, u8 min_shift, u8 insn_bitness);
struct tnum tnum_add(struct tnum a, struct tnum b);
/* Subtract two tnums, return @a - @b */
struct tnum tnum_sub(struct tnum a, struct tnum b);
/* Neg of a tnum, return  0 - @a */
struct tnum tnum_neg(struct tnum a);
/* Bitwise-AND, return @a & @b */
struct tnum tnum_and(struct tnum a, struct tnum b);
/* Bitwise-OR, return @a | @b */
+5 −0
Original line number Diff line number Diff line
@@ -83,6 +83,11 @@ struct tnum tnum_sub(struct tnum a, struct tnum b)
	return TNUM(dv & ~mu, mu);
}

struct tnum tnum_neg(struct tnum a)
{
	return tnum_sub(TNUM(0, 0), a);
}

struct tnum tnum_and(struct tnum a, struct tnum b)
{
	u64 alpha, beta, v;
+16 −1
Original line number Diff line number Diff line
@@ -15182,6 +15182,7 @@ static bool is_safe_to_compute_dst_reg_range(struct bpf_insn *insn,
	switch (BPF_OP(insn->code)) {
	case BPF_ADD:
	case BPF_SUB:
	case BPF_NEG:
	case BPF_AND:
	case BPF_XOR:
	case BPF_OR:
@@ -15250,6 +15251,13 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
		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_NEG:
		env->fake_reg[0] = *dst_reg;
		__mark_reg_known(dst_reg, 0);
		scalar32_min_max_sub(dst_reg, &env->fake_reg[0]);
		scalar_min_max_sub(dst_reg, &env->fake_reg[0]);
		dst_reg->var_off = tnum_neg(env->fake_reg[0].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);
@@ -15473,7 +15481,14 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
		}
		/* check dest operand */
		if (opcode == BPF_NEG) {
			err = check_reg_arg(env, insn->dst_reg, DST_OP_NO_MARK);
			err = err ?: adjust_scalar_min_max_vals(env, insn,
							 &regs[insn->dst_reg],
							 regs[insn->dst_reg]);
		} else {
			err = check_reg_arg(env, insn->dst_reg, DST_OP);
		}
		if (err)
			return err;
+7 −4
Original line number Diff line number Diff line
@@ -159,13 +159,16 @@ __failure_unpriv
__naked void deducing_bounds_from_const_10(void)
{
	asm volatile ("					\
	r6 = r1;					\
	r0 = 0;						\
	if r0 s<= 0 goto l0_%=;				\
l0_%=:	/* Marks reg as unknown. */			\
	r0 = -r0;					\
	r0 -= r1;					\
l0_%=: /* Marks r0 as unknown. */			\
	call %[bpf_get_prandom_u32];			\
	r0 -= r6;					\
	exit;						\
"	::: __clobber_all);
"	:
	: __imm(bpf_get_prandom_u32)
	: __clobber_all);
}

char _license[] SEC("license") = "GPL";
+70 −0
Original line number Diff line number Diff line
@@ -231,4 +231,74 @@ __naked void bpf_cond_op_not_r10(void)
	::: __clobber_all);
}

SEC("lsm.s/socket_connect")
__success __log_level(2)
__msg("0: (b7) r0 = 1                        ; R0_w=1")
__msg("1: (84) w0 = -w0                      ; R0_w=0xffffffff")
__msg("mark_precise: frame0: last_idx 2 first_idx 0 subseq_idx -1")
__msg("mark_precise: frame0: regs=r0 stack= before 1: (84) w0 = -w0")
__msg("mark_precise: frame0: regs=r0 stack= before 0: (b7) r0 = 1")
__naked int bpf_neg_2(void)
{
	/*
	 * lsm.s/socket_connect requires a return value within [-4095, 0].
	 * Returning -1 is allowed
	 */
	asm volatile (
	"r0 = 1;"
	"w0 = -w0;"
	"exit;"
	::: __clobber_all);
}

SEC("lsm.s/socket_connect")
__failure __msg("At program exit the register R0 has")
__naked int bpf_neg_3(void)
{
	/*
	 * lsm.s/socket_connect requires a return value within [-4095, 0].
	 * Returning -10000 is not allowed.
	 */
	asm volatile (
	"r0 = 10000;"
	"w0 = -w0;"
	"exit;"
	::: __clobber_all);
}

SEC("lsm.s/socket_connect")
__success __log_level(2)
__msg("0: (b7) r0 = 1                        ; R0_w=1")
__msg("1: (87) r0 = -r0                      ; R0_w=-1")
__msg("mark_precise: frame0: last_idx 2 first_idx 0 subseq_idx -1")
__msg("mark_precise: frame0: regs=r0 stack= before 1: (87) r0 = -r0")
__msg("mark_precise: frame0: regs=r0 stack= before 0: (b7) r0 = 1")
__naked int bpf_neg_4(void)
{
	/*
	 * lsm.s/socket_connect requires a return value within [-4095, 0].
	 * Returning -1 is allowed
	 */
	asm volatile (
	"r0 = 1;"
	"r0 = -r0;"
	"exit;"
	::: __clobber_all);
}

SEC("lsm.s/socket_connect")
__failure __msg("At program exit the register R0 has")
__naked int bpf_neg_5(void)
{
	/*
	 * lsm.s/socket_connect requires a return value within [-4095, 0].
	 * Returning -10000 is not allowed.
	 */
	asm volatile (
	"r0 = 10000;"
	"r0 = -r0;"
	"exit;"
	::: __clobber_all);
}

char _license[] SEC("license") = "GPL";
Loading