提交 b03c9f9f 编写于 作者: E Edward Cree 提交者: David S. Miller

bpf/verifier: track signed and unsigned min/max values

Allows us to, sometimes, combine information from a signed check of one
 bound and an unsigned check of the other.
We now track the full range of possible values, rather than restricting
 ourselves to [0, 1<<30) and considering anything beyond that as
 unknown.  While this is probably not necessary, it makes the code more
 straightforward and symmetrical between signed and unsigned bounds.
Signed-off-by: NEdward Cree <ecree@solarflare.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 f1174f77
...@@ -11,11 +11,15 @@ ...@@ -11,11 +11,15 @@
#include <linux/filter.h> /* for MAX_BPF_STACK */ #include <linux/filter.h> /* for MAX_BPF_STACK */
#include <linux/tnum.h> #include <linux/tnum.h>
/* Just some arbitrary values so we can safely do math without overflowing and /* Maximum variable offset umax_value permitted when resolving memory accesses.
* are obviously wrong for any sort of memory access. * In practice this is far bigger than any realistic pointer offset; this limit
* ensures that umax_value + (int)off + (int)size cannot overflow a u64.
*/ */
#define BPF_REGISTER_MAX_RANGE (1024 * 1024 * 1024) #define BPF_MAX_VAR_OFF (1ULL << 31)
#define BPF_REGISTER_MIN_RANGE -1 /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO]. This ensures
* that converting umax_value to int cannot overflow.
*/
#define BPF_MAX_VAR_SIZ INT_MAX
struct bpf_reg_state { struct bpf_reg_state {
enum bpf_reg_type type; enum bpf_reg_type type;
...@@ -36,7 +40,7 @@ struct bpf_reg_state { ...@@ -36,7 +40,7 @@ struct bpf_reg_state {
* came from, when one is tested for != NULL. * came from, when one is tested for != NULL.
*/ */
u32 id; u32 id;
/* These three fields must be last. See states_equal() */ /* These five fields must be last. See states_equal() */
/* For scalar types (SCALAR_VALUE), this represents our knowledge of /* For scalar types (SCALAR_VALUE), this represents our knowledge of
* the actual value. * the actual value.
* For pointer types, this represents the variable part of the offset * For pointer types, this represents the variable part of the offset
...@@ -49,9 +53,10 @@ struct bpf_reg_state { ...@@ -49,9 +53,10 @@ struct bpf_reg_state {
* These refer to the same value as var_off, not necessarily the actual * These refer to the same value as var_off, not necessarily the actual
* contents of the register. * contents of the register.
*/ */
s64 min_value; s64 smin_value; /* minimum possible (s64)value */
u64 max_value; s64 smax_value; /* maximum possible (s64)value */
bool value_from_signed; u64 umin_value; /* minimum possible (u64)value */
u64 umax_value; /* maximum possible (u64)value */
}; };
enum bpf_stack_slot_type { enum bpf_stack_slot_type {
......
...@@ -17,6 +17,8 @@ struct tnum { ...@@ -17,6 +17,8 @@ struct tnum {
struct tnum tnum_const(u64 value); struct tnum tnum_const(u64 value);
/* A completely unknown value */ /* A completely unknown value */
extern const struct tnum tnum_unknown; extern const struct tnum tnum_unknown;
/* A value that's unknown except that @min <= value <= @max */
struct tnum tnum_range(u64 min, u64 max);
/* Arithmetic and logical ops */ /* Arithmetic and logical ops */
/* Shift a tnum left (by a fixed shift) */ /* Shift a tnum left (by a fixed shift) */
......
...@@ -17,6 +17,22 @@ struct tnum tnum_const(u64 value) ...@@ -17,6 +17,22 @@ struct tnum tnum_const(u64 value)
return TNUM(value, 0); return TNUM(value, 0);
} }
struct tnum tnum_range(u64 min, u64 max)
{
u64 chi = min ^ max, delta;
u8 bits = fls64(chi);
/* special case, needed because 1ULL << 64 is undefined */
if (bits > 63)
return tnum_unknown;
/* e.g. if chi = 4, bits = 3, delta = (1<<3) - 1 = 7.
* if chi = 0, bits = 0, delta = (1<<0) - 1 = 0, so we return
* constant min (since min == max).
*/
delta = (1ULL << bits) - 1;
return TNUM(min & ~delta, delta);
}
struct tnum tnum_lshift(struct tnum a, u8 shift) struct tnum tnum_lshift(struct tnum a, u8 shift)
{ {
return TNUM(a.value << shift, a.mask << shift); return TNUM(a.value << shift, a.mask << shift);
......
...@@ -234,12 +234,20 @@ static void print_verifier_state(struct bpf_verifier_state *state) ...@@ -234,12 +234,20 @@ static void print_verifier_state(struct bpf_verifier_state *state)
verbose(",ks=%d,vs=%d", verbose(",ks=%d,vs=%d",
reg->map_ptr->key_size, reg->map_ptr->key_size,
reg->map_ptr->value_size); reg->map_ptr->value_size);
if (reg->min_value != BPF_REGISTER_MIN_RANGE) if (reg->smin_value != reg->umin_value &&
verbose(",min_value=%lld", reg->smin_value != S64_MIN)
(long long)reg->min_value); verbose(",smin_value=%lld",
if (reg->max_value != BPF_REGISTER_MAX_RANGE) (long long)reg->smin_value);
verbose(",max_value=%llu", if (reg->smax_value != reg->umax_value &&
(unsigned long long)reg->max_value); reg->smax_value != S64_MAX)
verbose(",smax_value=%lld",
(long long)reg->smax_value);
if (reg->umin_value != 0)
verbose(",umin_value=%llu",
(unsigned long long)reg->umin_value);
if (reg->umax_value != U64_MAX)
verbose(",umax_value=%llu",
(unsigned long long)reg->umax_value);
if (!tnum_is_unknown(reg->var_off)) { if (!tnum_is_unknown(reg->var_off)) {
char tn_buf[48]; char tn_buf[48];
...@@ -466,14 +474,25 @@ static const int caller_saved[CALLER_SAVED_REGS] = { ...@@ -466,14 +474,25 @@ static const int caller_saved[CALLER_SAVED_REGS] = {
static void __mark_reg_not_init(struct bpf_reg_state *reg); static void __mark_reg_not_init(struct bpf_reg_state *reg);
/* Mark the unknown part of a register (variable offset or scalar value) as
* known to have the value @imm.
*/
static void __mark_reg_known(struct bpf_reg_state *reg, u64 imm)
{
reg->id = 0;
reg->var_off = tnum_const(imm);
reg->smin_value = (s64)imm;
reg->smax_value = (s64)imm;
reg->umin_value = imm;
reg->umax_value = imm;
}
/* Mark the 'variable offset' part of a register as zero. This should be /* Mark the 'variable offset' part of a register as zero. This should be
* used only on registers holding a pointer type. * used only on registers holding a pointer type.
*/ */
static void __mark_reg_known_zero(struct bpf_reg_state *reg) static void __mark_reg_known_zero(struct bpf_reg_state *reg)
{ {
reg->var_off = tnum_const(0); __mark_reg_known(reg, 0);
reg->min_value = 0;
reg->max_value = 0;
} }
static void mark_reg_known_zero(struct bpf_reg_state *regs, u32 regno) static void mark_reg_known_zero(struct bpf_reg_state *regs, u32 regno)
...@@ -488,6 +507,72 @@ static void mark_reg_known_zero(struct bpf_reg_state *regs, u32 regno) ...@@ -488,6 +507,72 @@ static void mark_reg_known_zero(struct bpf_reg_state *regs, u32 regno)
__mark_reg_known_zero(regs + regno); __mark_reg_known_zero(regs + regno);
} }
/* Attempts to improve min/max values based on var_off information */
static void __update_reg_bounds(struct bpf_reg_state *reg)
{
/* min signed is max(sign bit) | min(other bits) */
reg->smin_value = max_t(s64, reg->smin_value,
reg->var_off.value | (reg->var_off.mask & S64_MIN));
/* max signed is min(sign bit) | max(other bits) */
reg->smax_value = min_t(s64, reg->smax_value,
reg->var_off.value | (reg->var_off.mask & S64_MAX));
reg->umin_value = max(reg->umin_value, reg->var_off.value);
reg->umax_value = min(reg->umax_value,
reg->var_off.value | reg->var_off.mask);
}
/* Uses signed min/max values to inform unsigned, and vice-versa */
static void __reg_deduce_bounds(struct bpf_reg_state *reg)
{
/* Learn sign from signed bounds.
* If we cannot cross the sign boundary, then signed and unsigned bounds
* are the same, so combine. This works even in the negative case, e.g.
* -3 s<= x s<= -1 implies 0xf...fd u<= x u<= 0xf...ff.
*/
if (reg->smin_value >= 0 || reg->smax_value < 0) {
reg->smin_value = reg->umin_value = max_t(u64, reg->smin_value,
reg->umin_value);
reg->smax_value = reg->umax_value = min_t(u64, reg->smax_value,
reg->umax_value);
return;
}
/* Learn sign from unsigned bounds. Signed bounds cross the sign
* boundary, so we must be careful.
*/
if ((s64)reg->umax_value >= 0) {
/* Positive. We can't learn anything from the smin, but smax
* is positive, hence safe.
*/
reg->smin_value = reg->umin_value;
reg->smax_value = reg->umax_value = min_t(u64, reg->smax_value,
reg->umax_value);
} else if ((s64)reg->umin_value < 0) {
/* Negative. We can't learn anything from the smax, but smin
* is negative, hence safe.
*/
reg->smin_value = reg->umin_value = max_t(u64, reg->smin_value,
reg->umin_value);
reg->smax_value = reg->umax_value;
}
}
/* Attempts to improve var_off based on unsigned min/max information */
static void __reg_bound_offset(struct bpf_reg_state *reg)
{
reg->var_off = tnum_intersect(reg->var_off,
tnum_range(reg->umin_value,
reg->umax_value));
}
/* Reset the min/max bounds of a register */
static void __mark_reg_unbounded(struct bpf_reg_state *reg)
{
reg->smin_value = S64_MIN;
reg->smax_value = S64_MAX;
reg->umin_value = 0;
reg->umax_value = U64_MAX;
}
/* Mark a register as having a completely unknown (scalar) value. */ /* Mark a register as having a completely unknown (scalar) value. */
static void __mark_reg_unknown(struct bpf_reg_state *reg) static void __mark_reg_unknown(struct bpf_reg_state *reg)
{ {
...@@ -495,8 +580,7 @@ static void __mark_reg_unknown(struct bpf_reg_state *reg) ...@@ -495,8 +580,7 @@ static void __mark_reg_unknown(struct bpf_reg_state *reg)
reg->id = 0; reg->id = 0;
reg->off = 0; reg->off = 0;
reg->var_off = tnum_unknown; reg->var_off = tnum_unknown;
reg->min_value = BPF_REGISTER_MIN_RANGE; __mark_reg_unbounded(reg);
reg->max_value = BPF_REGISTER_MAX_RANGE;
} }
static void mark_reg_unknown(struct bpf_reg_state *regs, u32 regno) static void mark_reg_unknown(struct bpf_reg_state *regs, u32 regno)
...@@ -545,13 +629,6 @@ static void init_reg_state(struct bpf_reg_state *regs) ...@@ -545,13 +629,6 @@ static void init_reg_state(struct bpf_reg_state *regs)
mark_reg_known_zero(regs, BPF_REG_1); mark_reg_known_zero(regs, BPF_REG_1);
} }
static void reset_reg_range_values(struct bpf_reg_state *regs, u32 regno)
{
regs[regno].min_value = BPF_REGISTER_MIN_RANGE;
regs[regno].max_value = BPF_REGISTER_MAX_RANGE;
regs[regno].value_from_signed = false;
}
enum reg_arg_type { enum reg_arg_type {
SRC_OP, /* register is used as source operand */ SRC_OP, /* register is used as source operand */
DST_OP, /* register is used as destination operand */ DST_OP, /* register is used as destination operand */
...@@ -716,26 +793,27 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, ...@@ -716,26 +793,27 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
* index'es we need to make sure that whatever we use * index'es we need to make sure that whatever we use
* will have a set floor within our range. * will have a set floor within our range.
*/ */
if (reg->min_value < 0) { if (reg->smin_value < 0) {
verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
regno); regno);
return -EACCES; return -EACCES;
} }
err = __check_map_access(env, regno, reg->min_value + off, size); err = __check_map_access(env, regno, reg->smin_value + off, size);
if (err) { if (err) {
verbose("R%d min value is outside of the array range\n", regno); verbose("R%d min value is outside of the array range\n", regno);
return err; return err;
} }
/* If we haven't set a max value then we need to bail /* If we haven't set a max value then we need to bail since we can't be
* since we can't be sure we won't do bad things. * sure we won't do bad things.
* If reg->umax_value + off could overflow, treat that as unbounded too.
*/ */
if (reg->max_value == BPF_REGISTER_MAX_RANGE) { if (reg->umax_value >= BPF_MAX_VAR_OFF) {
verbose("R%d unbounded memory access, make sure to bounds check any array access into a map\n", verbose("R%d unbounded memory access, make sure to bounds check any array access into a map\n",
regno); regno);
return -EACCES; return -EACCES;
} }
err = __check_map_access(env, regno, reg->max_value + off, size); err = __check_map_access(env, regno, reg->umax_value + off, size);
if (err) if (err)
verbose("R%d max value is outside of the array range\n", regno); verbose("R%d max value is outside of the array range\n", regno);
return err; return err;
...@@ -797,7 +875,7 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off, ...@@ -797,7 +875,7 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
/* We don't allow negative numbers, because we aren't tracking enough /* We don't allow negative numbers, because we aren't tracking enough
* detail to prove they're safe. * detail to prove they're safe.
*/ */
if (reg->min_value < 0) { if (reg->smin_value < 0) {
verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n", verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
regno); regno);
return -EACCES; return -EACCES;
...@@ -1070,12 +1148,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn ...@@ -1070,12 +1148,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
/* b/h/w load zero-extends, mark upper bits as known 0 */ /* b/h/w load zero-extends, mark upper bits as known 0 */
state->regs[value_regno].var_off = tnum_cast( state->regs[value_regno].var_off = tnum_cast(
state->regs[value_regno].var_off, size); state->regs[value_regno].var_off, size);
/* sign bit is known zero, so we can bound the value */ __update_reg_bounds(&state->regs[value_regno]);
state->regs[value_regno].min_value = 0;
state->regs[value_regno].max_value = min_t(u64,
state->regs[value_regno].var_off.value |
state->regs[value_regno].var_off.mask,
BPF_REGISTER_MAX_RANGE);
} }
return err; return err;
} }
...@@ -1333,13 +1406,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, ...@@ -1333,13 +1406,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
*/ */
meta = NULL; meta = NULL;
if (reg->min_value < 0) { if (reg->smin_value < 0) {
verbose("R%d min value is negative, either use unsigned or 'var &= const'\n", verbose("R%d min value is negative, either use unsigned or 'var &= const'\n",
regno); regno);
return -EACCES; return -EACCES;
} }
if (reg->min_value == 0) { if (reg->umin_value == 0) {
err = check_helper_mem_access(env, regno - 1, 0, err = check_helper_mem_access(env, regno - 1, 0,
zero_size_allowed, zero_size_allowed,
meta); meta);
...@@ -1347,13 +1420,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, ...@@ -1347,13 +1420,13 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
return err; return err;
} }
if (reg->max_value == BPF_REGISTER_MAX_RANGE) { if (reg->umax_value >= BPF_MAX_VAR_SIZ) {
verbose("R%d unbounded memory access, use 'var &= const' or 'if (var < const)'\n", verbose("R%d unbounded memory access, use 'var &= const' or 'if (var < const)'\n",
regno); regno);
return -EACCES; return -EACCES;
} }
err = check_helper_mem_access(env, regno - 1, err = check_helper_mem_access(env, regno - 1,
reg->max_value, reg->umax_value,
zero_size_allowed, meta); zero_size_allowed, meta);
} }
...@@ -1600,33 +1673,35 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx) ...@@ -1600,33 +1673,35 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx)
return 0; return 0;
} }
static void check_reg_overflow(struct bpf_reg_state *reg)
{
if (reg->max_value > BPF_REGISTER_MAX_RANGE)
reg->max_value = BPF_REGISTER_MAX_RANGE;
if (reg->min_value < BPF_REGISTER_MIN_RANGE ||
reg->min_value > BPF_REGISTER_MAX_RANGE)
reg->min_value = BPF_REGISTER_MIN_RANGE;
}
static void coerce_reg_to_32(struct bpf_reg_state *reg) static void coerce_reg_to_32(struct bpf_reg_state *reg)
{ {
/* 32-bit values can't be negative as an s64 */
if (reg->min_value < 0)
reg->min_value = 0;
/* clear high 32 bits */ /* clear high 32 bits */
reg->var_off = tnum_cast(reg->var_off, 4); reg->var_off = tnum_cast(reg->var_off, 4);
/* Did value become known? Then update bounds */ /* Update bounds */
if (tnum_is_const(reg->var_off)) { __update_reg_bounds(reg);
if ((s64)reg->var_off.value > BPF_REGISTER_MIN_RANGE) }
reg->min_value = reg->var_off.value;
if (reg->var_off.value < BPF_REGISTER_MAX_RANGE) static bool signed_add_overflows(s64 a, s64 b)
reg->max_value = reg->var_off.value; {
} /* Do the add in u64, where overflow is well-defined */
s64 res = (s64)((u64)a + (u64)b);
if (b < 0)
return res > a;
return res < a;
}
static bool signed_sub_overflows(s64 a, s64 b)
{
/* Do the sub in u64, where overflow is well-defined */
s64 res = (s64)((u64)a - (u64)b);
if (b < 0)
return res < a;
return res > a;
} }
/* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
* Caller must check_reg_overflow all argument regs beforehand.
* Caller should also handle BPF_MOV case separately. * Caller should also handle BPF_MOV case separately.
* If we return -EACCES, caller may want to try again treating pointer as a * If we return -EACCES, caller may want to try again treating pointer as a
* scalar. So we only emit a diagnostic if !env->allow_ptr_leaks. * scalar. So we only emit a diagnostic if !env->allow_ptr_leaks.
...@@ -1638,16 +1713,23 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ...@@ -1638,16 +1713,23 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
{ {
struct bpf_reg_state *regs = env->cur_state.regs, *dst_reg; struct bpf_reg_state *regs = env->cur_state.regs, *dst_reg;
bool known = tnum_is_const(off_reg->var_off); bool known = tnum_is_const(off_reg->var_off);
s64 min_val = off_reg->min_value; s64 smin_val = off_reg->smin_value, smax_val = off_reg->smax_value,
u64 max_val = off_reg->max_value; smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
u8 opcode = BPF_OP(insn->code); u8 opcode = BPF_OP(insn->code);
u32 dst = insn->dst_reg; u32 dst = insn->dst_reg;
dst_reg = &regs[dst]; dst_reg = &regs[dst];
if (WARN_ON_ONCE(known && (min_val != max_val))) { if (WARN_ON_ONCE(known && (smin_val != smax_val))) {
print_verifier_state(&env->cur_state);
verbose("verifier internal error: known but bad sbounds\n");
return -EINVAL;
}
if (WARN_ON_ONCE(known && (umin_val != umax_val))) {
print_verifier_state(&env->cur_state); print_verifier_state(&env->cur_state);
verbose("verifier internal error\n"); verbose("verifier internal error: known but bad ubounds\n");
return -EINVAL; return -EINVAL;
} }
...@@ -1689,22 +1771,18 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ...@@ -1689,22 +1771,18 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
/* We can take a fixed offset as long as it doesn't overflow /* We can take a fixed offset as long as it doesn't overflow
* the s32 'off' field * the s32 'off' field
*/ */
if (known && (ptr_reg->off + min_val == if (known && (ptr_reg->off + smin_val ==
(s64)(s32)(ptr_reg->off + min_val))) { (s64)(s32)(ptr_reg->off + smin_val))) {
/* pointer += K. Accumulate it into fixed offset */ /* pointer += K. Accumulate it into fixed offset */
dst_reg->min_value = ptr_reg->min_value; dst_reg->smin_value = smin_ptr;
dst_reg->max_value = ptr_reg->max_value; dst_reg->smax_value = smax_ptr;
dst_reg->umin_value = umin_ptr;
dst_reg->umax_value = umax_ptr;
dst_reg->var_off = ptr_reg->var_off; dst_reg->var_off = ptr_reg->var_off;
dst_reg->off = ptr_reg->off + min_val; dst_reg->off = ptr_reg->off + smin_val;
dst_reg->range = ptr_reg->range; dst_reg->range = ptr_reg->range;
break; break;
} }
if (max_val == BPF_REGISTER_MAX_RANGE) {
if (!env->allow_ptr_leaks)
verbose("R%d tried to add unbounded value to pointer\n",
dst);
return -EACCES;
}
/* A new variable offset is created. Note that off_reg->off /* A new variable offset is created. Note that off_reg->off
* == 0, since it's a scalar. * == 0, since it's a scalar.
* dst_reg gets the pointer type and since some positive * dst_reg gets the pointer type and since some positive
...@@ -1714,12 +1792,22 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ...@@ -1714,12 +1792,22 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
* added into the variable offset, and we copy the fixed offset * added into the variable offset, and we copy the fixed offset
* from ptr_reg. * from ptr_reg.
*/ */
if (min_val <= BPF_REGISTER_MIN_RANGE) if (signed_add_overflows(smin_ptr, smin_val) ||
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; signed_add_overflows(smax_ptr, smax_val)) {
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) dst_reg->smin_value = S64_MIN;
dst_reg->min_value += min_val; dst_reg->smax_value = S64_MAX;
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE) } else {
dst_reg->max_value += max_val; dst_reg->smin_value = smin_ptr + smin_val;
dst_reg->smax_value = smax_ptr + smax_val;
}
if (umin_ptr + umin_val < umin_ptr ||
umax_ptr + umax_val < umax_ptr) {
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else {
dst_reg->umin_value = umin_ptr + umin_val;
dst_reg->umax_value = umax_ptr + umax_val;
}
dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off); dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
dst_reg->off = ptr_reg->off; dst_reg->off = ptr_reg->off;
if (ptr_reg->type == PTR_TO_PACKET) { if (ptr_reg->type == PTR_TO_PACKET) {
...@@ -1746,43 +1834,46 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ...@@ -1746,43 +1834,46 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
dst); dst);
return -EACCES; return -EACCES;
} }
if (known && (ptr_reg->off - min_val == if (known && (ptr_reg->off - smin_val ==
(s64)(s32)(ptr_reg->off - min_val))) { (s64)(s32)(ptr_reg->off - smin_val))) {
/* pointer -= K. Subtract it from fixed offset */ /* pointer -= K. Subtract it from fixed offset */
dst_reg->min_value = ptr_reg->min_value; dst_reg->smin_value = smin_ptr;
dst_reg->max_value = ptr_reg->max_value; dst_reg->smax_value = smax_ptr;
dst_reg->umin_value = umin_ptr;
dst_reg->umax_value = umax_ptr;
dst_reg->var_off = ptr_reg->var_off; dst_reg->var_off = ptr_reg->var_off;
dst_reg->id = ptr_reg->id; dst_reg->id = ptr_reg->id;
dst_reg->off = ptr_reg->off - min_val; dst_reg->off = ptr_reg->off - smin_val;
dst_reg->range = ptr_reg->range; dst_reg->range = ptr_reg->range;
break; break;
} }
/* Subtracting a negative value will just confuse everything.
* This can happen if off_reg is an immediate.
*/
if ((s64)max_val < 0) {
if (!env->allow_ptr_leaks)
verbose("R%d tried to subtract negative max_val %lld from pointer\n",
dst, (s64)max_val);
return -EACCES;
}
/* A new variable offset is created. If the subtrahend is known /* A new variable offset is created. If the subtrahend is known
* nonnegative, then any reg->range we had before is still good. * nonnegative, then any reg->range we had before is still good.
*/ */
if (max_val >= BPF_REGISTER_MAX_RANGE) if (signed_sub_overflows(smin_ptr, smax_val) ||
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; signed_sub_overflows(smax_ptr, smin_val)) {
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) /* Overflow possible, we know nothing */
dst_reg->min_value -= max_val; dst_reg->smin_value = S64_MIN;
if (min_val <= BPF_REGISTER_MIN_RANGE) dst_reg->smax_value = S64_MAX;
dst_reg->max_value = BPF_REGISTER_MAX_RANGE; } else {
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE) dst_reg->smin_value = smin_ptr - smax_val;
dst_reg->max_value -= min_val; dst_reg->smax_value = smax_ptr - smin_val;
}
if (umin_ptr < umax_val) {
/* Overflow possible, we know nothing */
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else {
/* Cannot overflow (as long as bounds are consistent) */
dst_reg->umin_value = umin_ptr - umax_val;
dst_reg->umax_value = umax_ptr - umin_val;
}
dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off); dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
dst_reg->off = ptr_reg->off; dst_reg->off = ptr_reg->off;
if (ptr_reg->type == PTR_TO_PACKET) { if (ptr_reg->type == PTR_TO_PACKET) {
dst_reg->id = ++env->id_gen; dst_reg->id = ++env->id_gen;
/* something was added to pkt_ptr, set range to zero */ /* something was added to pkt_ptr, set range to zero */
if (min_val < 0) if (smin_val < 0)
dst_reg->range = 0; dst_reg->range = 0;
} }
break; break;
...@@ -1805,7 +1896,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ...@@ -1805,7 +1896,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
return -EACCES; return -EACCES;
} }
check_reg_overflow(dst_reg); __update_reg_bounds(dst_reg);
__reg_deduce_bounds(dst_reg);
__reg_bound_offset(dst_reg);
return 0; return 0;
} }
...@@ -1815,157 +1908,217 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, ...@@ -1815,157 +1908,217 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
struct bpf_reg_state src_reg) struct bpf_reg_state src_reg)
{ {
struct bpf_reg_state *regs = env->cur_state.regs; struct bpf_reg_state *regs = env->cur_state.regs;
s64 min_val = BPF_REGISTER_MIN_RANGE;
u64 max_val = BPF_REGISTER_MAX_RANGE;
u8 opcode = BPF_OP(insn->code); u8 opcode = BPF_OP(insn->code);
bool src_known, dst_known; bool src_known, dst_known;
s64 smin_val, smax_val;
u64 umin_val, umax_val;
if (BPF_CLASS(insn->code) != BPF_ALU64) { if (BPF_CLASS(insn->code) != BPF_ALU64) {
/* 32-bit ALU ops are (32,32)->64 */ /* 32-bit ALU ops are (32,32)->64 */
coerce_reg_to_32(dst_reg); coerce_reg_to_32(dst_reg);
coerce_reg_to_32(&src_reg); coerce_reg_to_32(&src_reg);
} }
min_val = src_reg.min_value; smin_val = src_reg.smin_value;
max_val = src_reg.max_value; smax_val = src_reg.smax_value;
umin_val = src_reg.umin_value;
umax_val = src_reg.umax_value;
src_known = tnum_is_const(src_reg.var_off); src_known = tnum_is_const(src_reg.var_off);
dst_known = tnum_is_const(dst_reg->var_off); dst_known = tnum_is_const(dst_reg->var_off);
switch (opcode) { switch (opcode) {
case BPF_ADD: case BPF_ADD:
if (min_val == BPF_REGISTER_MIN_RANGE) if (signed_add_overflows(dst_reg->smin_value, smin_val) ||
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; signed_add_overflows(dst_reg->smax_value, smax_val)) {
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) dst_reg->smin_value = S64_MIN;
dst_reg->min_value += min_val; dst_reg->smax_value = S64_MAX;
/* if max_val is MAX_RANGE, this will saturate dst->max */ } else {
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE) dst_reg->smin_value += smin_val;
dst_reg->max_value += max_val; dst_reg->smax_value += smax_val;
}
if (dst_reg->umin_value + umin_val < umin_val ||
dst_reg->umax_value + umax_val < umax_val) {
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else {
dst_reg->umin_value += umin_val;
dst_reg->umax_value += umax_val;
}
dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off); dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
break; break;
case BPF_SUB: case BPF_SUB:
if (max_val == BPF_REGISTER_MAX_RANGE) if (signed_sub_overflows(dst_reg->smin_value, smax_val) ||
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; signed_sub_overflows(dst_reg->smax_value, smin_val)) {
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) /* Overflow possible, we know nothing */
dst_reg->min_value -= max_val; dst_reg->smin_value = S64_MIN;
if (min_val == BPF_REGISTER_MIN_RANGE) dst_reg->smax_value = S64_MAX;
dst_reg->max_value = BPF_REGISTER_MAX_RANGE; } else {
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE) dst_reg->smin_value -= smax_val;
dst_reg->max_value -= min_val; dst_reg->smax_value -= smin_val;
}
if (dst_reg->umin_value < umax_val) {
/* Overflow possible, we know nothing */
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else {
/* Cannot overflow (as long as bounds are consistent) */
dst_reg->umin_value -= umax_val;
dst_reg->umax_value -= umin_val;
}
dst_reg->var_off = tnum_sub(dst_reg->var_off, src_reg.var_off); dst_reg->var_off = tnum_sub(dst_reg->var_off, src_reg.var_off);
break; break;
case BPF_MUL: case BPF_MUL:
if (min_val < 0 || dst_reg->min_value < 0) { dst_reg->var_off = tnum_mul(dst_reg->var_off, src_reg.var_off);
if (smin_val < 0 || dst_reg->smin_value < 0) {
/* Ain't nobody got time to multiply that sign */ /* Ain't nobody got time to multiply that sign */
__mark_reg_unknown(dst_reg); __mark_reg_unbounded(dst_reg);
__update_reg_bounds(dst_reg);
break; break;
} }
dst_reg->min_value *= min_val; /* Both values are positive, so we can work with unsigned and
/* if max_val is MAX_RANGE, this will saturate dst->max. * copy the result to signed (unless it exceeds S64_MAX).
* We know MAX_RANGE ** 2 won't overflow a u64, because
* MAX_RANGE itself fits in a u32.
*/ */
BUILD_BUG_ON(BPF_REGISTER_MAX_RANGE > (u32)-1); if (umax_val > U32_MAX || dst_reg->umax_value > U32_MAX) {
if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE) /* Potential overflow, we know nothing */
dst_reg->max_value *= max_val; __mark_reg_unbounded(dst_reg);
dst_reg->var_off = tnum_mul(dst_reg->var_off, src_reg.var_off); /* (except what we can learn from the var_off) */
__update_reg_bounds(dst_reg);
break;
}
dst_reg->umin_value *= umin_val;
dst_reg->umax_value *= umax_val;
if (dst_reg->umax_value > S64_MAX) {
/* Overflow possible, we know nothing */
dst_reg->smin_value = S64_MIN;
dst_reg->smax_value = S64_MAX;
} else {
dst_reg->smin_value = dst_reg->umin_value;
dst_reg->smax_value = dst_reg->umax_value;
}
break; break;
case BPF_AND: case BPF_AND:
if (src_known && dst_known) { if (src_known && dst_known) {
u64 value = dst_reg->var_off.value & src_reg.var_off.value; __mark_reg_known(dst_reg, dst_reg->var_off.value &
src_reg.var_off.value);
dst_reg->var_off = tnum_const(value);
dst_reg->min_value = dst_reg->max_value = min_t(u64,
value, BPF_REGISTER_MAX_RANGE);
break; break;
} }
/* Lose min_value when AND'ing negative numbers, ain't nobody /* We get our minimum from the var_off, since that's inherently
* got time for that. Otherwise we get our minimum from the * bitwise. Our maximum is the minimum of the operands' maxima.
* var_off, since that's inherently bitwise.
* Our maximum is the minimum of the operands' maxima.
*/ */
dst_reg->var_off = tnum_and(dst_reg->var_off, src_reg.var_off); dst_reg->var_off = tnum_and(dst_reg->var_off, src_reg.var_off);
if (min_val < 0 && dst_reg->min_value < 0) dst_reg->umin_value = dst_reg->var_off.value;
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; dst_reg->umax_value = min(dst_reg->umax_value, umax_val);
else if (dst_reg->smin_value < 0 || smin_val < 0) {
dst_reg->min_value = dst_reg->var_off.value; /* Lose signed bounds when ANDing negative numbers,
dst_reg->max_value = min(dst_reg->max_value, max_val); * ain't nobody got time for that.
*/
dst_reg->smin_value = S64_MIN;
dst_reg->smax_value = S64_MAX;
} else {
/* ANDing two positives gives a positive, so safe to
* cast result into s64.
*/
dst_reg->smin_value = dst_reg->umin_value;
dst_reg->smax_value = dst_reg->umax_value;
}
/* We may learn something more from the var_off */
__update_reg_bounds(dst_reg);
break; break;
case BPF_OR: case BPF_OR:
if (src_known && dst_known) { if (src_known && dst_known) {
u64 value = dst_reg->var_off.value | src_reg.var_off.value; __mark_reg_known(dst_reg, dst_reg->var_off.value |
src_reg.var_off.value);
dst_reg->var_off = tnum_const(value);
dst_reg->min_value = dst_reg->max_value = min_t(u64,
value, BPF_REGISTER_MAX_RANGE);
break; break;
} }
/* Lose ranges when OR'ing negative numbers, ain't nobody got /* We get our maximum from the var_off, and our minimum is the
* time for that. Otherwise we get our maximum from the var_off, * maximum of the operands' minima
* and our minimum is the maximum of the operands' minima.
*/ */
dst_reg->var_off = tnum_or(dst_reg->var_off, src_reg.var_off); dst_reg->var_off = tnum_or(dst_reg->var_off, src_reg.var_off);
if (min_val < 0 || dst_reg->min_value < 0) { dst_reg->umin_value = max(dst_reg->umin_value, umin_val);
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; dst_reg->umax_value = dst_reg->var_off.value |
dst_reg->max_value = BPF_REGISTER_MAX_RANGE; dst_reg->var_off.mask;
if (dst_reg->smin_value < 0 || smin_val < 0) {
/* Lose signed bounds when ORing negative numbers,
* ain't nobody got time for that.
*/
dst_reg->smin_value = S64_MIN;
dst_reg->smax_value = S64_MAX;
} else { } else {
dst_reg->min_value = max(dst_reg->min_value, min_val); /* ORing two positives gives a positive, so safe to
dst_reg->max_value = dst_reg->var_off.value | dst_reg->var_off.mask; * cast result into s64.
*/
dst_reg->smin_value = dst_reg->umin_value;
dst_reg->smax_value = dst_reg->umax_value;
} }
/* We may learn something more from the var_off */
__update_reg_bounds(dst_reg);
break; break;
case BPF_LSH: case BPF_LSH:
if (min_val < 0) { if (umax_val > 63) {
/* LSH by a negative number is undefined */ /* Shifts greater than 63 are undefined. This includes
* shifts by a negative number.
*/
mark_reg_unknown(regs, insn->dst_reg); mark_reg_unknown(regs, insn->dst_reg);
break; break;
} }
/* Gotta have special overflow logic here, if we're shifting /* We lose all sign bit information (except what we can pick
* more than MAX_RANGE then just assume we have an invalid * up from var_off)
* range.
*/ */
if (min_val > ilog2(BPF_REGISTER_MAX_RANGE)) { dst_reg->smin_value = S64_MIN;
dst_reg->min_value = BPF_REGISTER_MIN_RANGE; dst_reg->smax_value = S64_MAX;
dst_reg->var_off = tnum_unknown; /* If we might shift our top bit out, then we know nothing */
if (dst_reg->umax_value > 1ULL << (63 - umax_val)) {
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else { } else {
if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) dst_reg->umin_value <<= umin_val;
dst_reg->min_value <<= min_val; dst_reg->umax_value <<= umax_val;
}
if (src_known) if (src_known)
dst_reg->var_off = tnum_lshift(dst_reg->var_off, min_val); dst_reg->var_off = tnum_lshift(dst_reg->var_off, umin_val);
else else
dst_reg->var_off = tnum_lshift(tnum_unknown, min_val); dst_reg->var_off = tnum_lshift(tnum_unknown, umin_val);
} /* We may learn something more from the var_off */
if (max_val > ilog2(BPF_REGISTER_MAX_RANGE)) __update_reg_bounds(dst_reg);
dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
else if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
dst_reg->max_value <<= max_val;
break; break;
case BPF_RSH: case BPF_RSH:
if (min_val < 0) { if (umax_val > 63) {
/* RSH by a negative number is undefined */ /* Shifts greater than 63 are undefined. This includes
* shifts by a negative number.
*/
mark_reg_unknown(regs, insn->dst_reg); mark_reg_unknown(regs, insn->dst_reg);
break; break;
} }
/* BPF_RSH is an unsigned shift, so make the appropriate casts */ /* BPF_RSH is an unsigned shift, so make the appropriate casts */
if (dst_reg->min_value < 0) { if (dst_reg->smin_value < 0) {
if (min_val) if (umin_val) {
/* Sign bit will be cleared */ /* Sign bit will be cleared */
dst_reg->min_value = 0; dst_reg->smin_value = 0;
} else { } else {
dst_reg->min_value = /* Lost sign bit information */
(u64)(dst_reg->min_value) >> min_val; dst_reg->smin_value = S64_MIN;
dst_reg->smax_value = S64_MAX;
}
} else {
dst_reg->smin_value =
(u64)(dst_reg->smin_value) >> umax_val;
} }
if (src_known) if (src_known)
dst_reg->var_off = tnum_rshift(dst_reg->var_off, min_val); dst_reg->var_off = tnum_rshift(dst_reg->var_off,
umin_val);
else else
dst_reg->var_off = tnum_rshift(tnum_unknown, min_val); dst_reg->var_off = tnum_rshift(tnum_unknown, umin_val);
if (dst_reg->max_value == BPF_REGISTER_MAX_RANGE) dst_reg->umin_value >>= umax_val;
dst_reg->max_value = ~0; dst_reg->umax_value >>= umin_val;
dst_reg->max_value >>= max_val; /* We may learn something more from the var_off */
__update_reg_bounds(dst_reg);
break; break;
default: default:
mark_reg_unknown(regs, insn->dst_reg); mark_reg_unknown(regs, insn->dst_reg);
break; break;
} }
check_reg_overflow(dst_reg); __reg_deduce_bounds(dst_reg);
__reg_bound_offset(dst_reg);
return 0; return 0;
} }
...@@ -1981,14 +2134,11 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, ...@@ -1981,14 +2134,11 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
int rc; int rc;
dst_reg = &regs[insn->dst_reg]; dst_reg = &regs[insn->dst_reg];
check_reg_overflow(dst_reg);
src_reg = NULL; src_reg = NULL;
if (dst_reg->type != SCALAR_VALUE) if (dst_reg->type != SCALAR_VALUE)
ptr_reg = dst_reg; ptr_reg = dst_reg;
if (BPF_SRC(insn->code) == BPF_X) { if (BPF_SRC(insn->code) == BPF_X) {
src_reg = &regs[insn->src_reg]; src_reg = &regs[insn->src_reg];
check_reg_overflow(src_reg);
if (src_reg->type != SCALAR_VALUE) { if (src_reg->type != SCALAR_VALUE) {
if (dst_reg->type != SCALAR_VALUE) { if (dst_reg->type != SCALAR_VALUE) {
/* Combining two pointers by any ALU op yields /* Combining two pointers by any ALU op yields
...@@ -2035,11 +2185,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, ...@@ -2035,11 +2185,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
* need to be able to read from this state. * need to be able to read from this state.
*/ */
off_reg.type = SCALAR_VALUE; off_reg.type = SCALAR_VALUE;
off_reg.var_off = tnum_const(insn->imm); __mark_reg_known(&off_reg, insn->imm);
off_reg.min_value = insn->imm;
off_reg.max_value = insn->imm;
src_reg = &off_reg; src_reg = &off_reg;
check_reg_overflow(src_reg);
if (ptr_reg) { /* pointer += K */ if (ptr_reg) { /* pointer += K */
rc = adjust_ptr_min_max_vals(env, insn, rc = adjust_ptr_min_max_vals(env, insn,
ptr_reg, src_reg); ptr_reg, src_reg);
...@@ -2144,22 +2291,17 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -2144,22 +2291,17 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
return -EACCES; return -EACCES;
} }
mark_reg_unknown(regs, insn->dst_reg); mark_reg_unknown(regs, insn->dst_reg);
/* high 32 bits are known zero. But this is /* high 32 bits are known zero. */
* still out of range for max_value, so leave
* that.
*/
regs[insn->dst_reg].var_off = tnum_cast( regs[insn->dst_reg].var_off = tnum_cast(
regs[insn->dst_reg].var_off, 4); regs[insn->dst_reg].var_off, 4);
__update_reg_bounds(&regs[insn->dst_reg]);
} }
} else { } else {
/* case: R = imm /* case: R = imm
* remember the value we stored into this reg * remember the value we stored into this reg
*/ */
regs[insn->dst_reg].type = SCALAR_VALUE; regs[insn->dst_reg].type = SCALAR_VALUE;
regs[insn->dst_reg].var_off = tnum_const(insn->imm); __mark_reg_known(regs + insn->dst_reg, insn->imm);
regs[insn->dst_reg].max_value = insn->imm;
regs[insn->dst_reg].min_value = insn->imm;
regs[insn->dst_reg].id = 0;
} }
} else if (opcode > BPF_END) { } else if (opcode > BPF_END) {
...@@ -2226,8 +2368,8 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, ...@@ -2226,8 +2368,8 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state,
/* This doesn't give us any range */ /* This doesn't give us any range */
return; return;
if (dst_reg->max_value > MAX_PACKET_OFF || if (dst_reg->umax_value > MAX_PACKET_OFF ||
dst_reg->max_value + dst_reg->off > MAX_PACKET_OFF) dst_reg->umax_value + dst_reg->off > MAX_PACKET_OFF)
/* Risk of overflow. For instance, ptr + (1<<63) may be less /* Risk of overflow. For instance, ptr + (1<<63) may be less
* than pkt_end, but that's because it's also less than pkt. * than pkt_end, but that's because it's also less than pkt.
*/ */
...@@ -2291,8 +2433,6 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, ...@@ -2291,8 +2433,6 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
struct bpf_reg_state *false_reg, u64 val, struct bpf_reg_state *false_reg, u64 val,
u8 opcode) u8 opcode)
{ {
bool value_from_signed = true;
/* If the dst_reg is a pointer, we can't learn anything about its /* If the dst_reg is a pointer, we can't learn anything about its
* variable offset from the compare (unless src_reg were a pointer into * variable offset from the compare (unless src_reg were a pointer into
* the same object, but we don't bother with that. * the same object, but we don't bother with that.
...@@ -2307,62 +2447,45 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg, ...@@ -2307,62 +2447,45 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
/* If this is false then we know nothing Jon Snow, but if it is /* If this is false then we know nothing Jon Snow, but if it is
* true then we know for sure. * true then we know for sure.
*/ */
true_reg->max_value = true_reg->min_value = val; __mark_reg_known(true_reg, val);
true_reg->var_off = tnum_const(val);
break; break;
case BPF_JNE: case BPF_JNE:
/* If this is true we know nothing Jon Snow, but if it is false /* If this is true we know nothing Jon Snow, but if it is false
* we know the value for sure; * we know the value for sure;
*/ */
false_reg->max_value = false_reg->min_value = val; __mark_reg_known(false_reg, val);
false_reg->var_off = tnum_const(val);
break; break;
case BPF_JGT: case BPF_JGT:
value_from_signed = false; false_reg->umax_value = min(false_reg->umax_value, val);
/* fallthrough */ true_reg->umin_value = max(true_reg->umin_value, val + 1);
break;
case BPF_JSGT: case BPF_JSGT:
if (true_reg->value_from_signed != value_from_signed) false_reg->smax_value = min_t(s64, false_reg->smax_value, val);
reset_reg_range_values(true_reg, 0); true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1);
if (false_reg->value_from_signed != value_from_signed)
reset_reg_range_values(false_reg, 0);
if (opcode == BPF_JGT) {
/* Unsigned comparison, the minimum value is 0. */
false_reg->min_value = 0;
}
/* If this is false then we know the maximum val is val,
* otherwise we know the min val is val+1.
*/
false_reg->max_value = val;
false_reg->value_from_signed = value_from_signed;
true_reg->min_value = val + 1;
true_reg->value_from_signed = value_from_signed;
break; break;
case BPF_JGE: case BPF_JGE:
value_from_signed = false; false_reg->umax_value = min(false_reg->umax_value, val - 1);
/* fallthrough */ true_reg->umin_value = max(true_reg->umin_value, val);
break;
case BPF_JSGE: case BPF_JSGE:
if (true_reg->value_from_signed != value_from_signed) false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1);
reset_reg_range_values(true_reg, 0); true_reg->smin_value = max_t(s64, true_reg->smin_value, val);
if (false_reg->value_from_signed != value_from_signed)
reset_reg_range_values(false_reg, 0);
if (opcode == BPF_JGE) {
/* Unsigned comparison, the minimum value is 0. */
false_reg->min_value = 0;
}
/* If this is false then we know the maximum value is val - 1,
* otherwise we know the mimimum value is val.
*/
false_reg->max_value = val - 1;
false_reg->value_from_signed = value_from_signed;
true_reg->min_value = val;
true_reg->value_from_signed = value_from_signed;
break; break;
default: default:
break; break;
} }
check_reg_overflow(false_reg); __reg_deduce_bounds(false_reg);
check_reg_overflow(true_reg); __reg_deduce_bounds(true_reg);
/* We might have learned some bits from the bounds. */
__reg_bound_offset(false_reg);
__reg_bound_offset(true_reg);
/* Intersecting with the old var_off might have improved our bounds
* slightly. e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
* then new var_off is (0; 0x7f...fc) which improves our umax.
*/
__update_reg_bounds(false_reg);
__update_reg_bounds(true_reg);
} }
/* Same as above, but for the case that dst_reg holds a constant and src_reg is /* Same as above, but for the case that dst_reg holds a constant and src_reg is
...@@ -2372,8 +2495,6 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, ...@@ -2372,8 +2495,6 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
struct bpf_reg_state *false_reg, u64 val, struct bpf_reg_state *false_reg, u64 val,
u8 opcode) u8 opcode)
{ {
bool value_from_signed = true;
if (__is_pointer_value(false, false_reg)) if (__is_pointer_value(false, false_reg))
return; return;
...@@ -2382,77 +2503,76 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, ...@@ -2382,77 +2503,76 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
/* If this is false then we know nothing Jon Snow, but if it is /* If this is false then we know nothing Jon Snow, but if it is
* true then we know for sure. * true then we know for sure.
*/ */
true_reg->max_value = true_reg->min_value = val; __mark_reg_known(true_reg, val);
true_reg->var_off = tnum_const(val);
break; break;
case BPF_JNE: case BPF_JNE:
/* If this is true we know nothing Jon Snow, but if it is false /* If this is true we know nothing Jon Snow, but if it is false
* we know the value for sure; * we know the value for sure;
*/ */
false_reg->max_value = false_reg->min_value = val; __mark_reg_known(false_reg, val);
false_reg->var_off = tnum_const(val);
break; break;
case BPF_JGT: case BPF_JGT:
value_from_signed = false; true_reg->umax_value = min(true_reg->umax_value, val - 1);
/* fallthrough */ false_reg->umin_value = max(false_reg->umin_value, val);
break;
case BPF_JSGT: case BPF_JSGT:
if (true_reg->value_from_signed != value_from_signed) true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1);
reset_reg_range_values(true_reg, 0); false_reg->smin_value = max_t(s64, false_reg->smin_value, val);
if (false_reg->value_from_signed != value_from_signed)
reset_reg_range_values(false_reg, 0);
if (opcode == BPF_JGT) {
/* Unsigned comparison, the minimum value is 0. */
true_reg->min_value = 0;
}
/*
* If this is false, then the val is <= the register, if it is
* true the register <= to the val.
*/
false_reg->min_value = val;
false_reg->value_from_signed = value_from_signed;
true_reg->max_value = val - 1;
true_reg->value_from_signed = value_from_signed;
break; break;
case BPF_JGE: case BPF_JGE:
value_from_signed = false; true_reg->umax_value = min(true_reg->umax_value, val);
/* fallthrough */ false_reg->umin_value = max(false_reg->umin_value, val + 1);
break;
case BPF_JSGE: case BPF_JSGE:
if (true_reg->value_from_signed != value_from_signed) true_reg->smax_value = min_t(s64, true_reg->smax_value, val);
reset_reg_range_values(true_reg, 0); false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1);
if (false_reg->value_from_signed != value_from_signed)
reset_reg_range_values(false_reg, 0);
if (opcode == BPF_JGE) {
/* Unsigned comparison, the minimum value is 0. */
true_reg->min_value = 0;
}
/* If this is false then constant < register, if it is true then
* the register < constant.
*/
false_reg->min_value = val + 1;
false_reg->value_from_signed = value_from_signed;
true_reg->max_value = val;
true_reg->value_from_signed = value_from_signed;
break; break;
default: default:
break; break;
} }
check_reg_overflow(false_reg); __reg_deduce_bounds(false_reg);
check_reg_overflow(true_reg); __reg_deduce_bounds(true_reg);
/* We might have learned some bits from the bounds. */
__reg_bound_offset(false_reg);
__reg_bound_offset(true_reg);
/* Intersecting with the old var_off might have improved our bounds
* slightly. e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
* then new var_off is (0; 0x7f...fc) which improves our umax.
*/
__update_reg_bounds(false_reg);
__update_reg_bounds(true_reg);
} }
/* Regs are known to be equal, so intersect their min/max/var_off */ /* Regs are known to be equal, so intersect their min/max/var_off */
static void __reg_combine_min_max(struct bpf_reg_state *src_reg, static void __reg_combine_min_max(struct bpf_reg_state *src_reg,
struct bpf_reg_state *dst_reg) struct bpf_reg_state *dst_reg)
{ {
src_reg->min_value = dst_reg->min_value = max(src_reg->min_value, src_reg->umin_value = dst_reg->umin_value = max(src_reg->umin_value,
dst_reg->min_value); dst_reg->umin_value);
src_reg->max_value = dst_reg->max_value = min(src_reg->max_value, src_reg->umax_value = dst_reg->umax_value = min(src_reg->umax_value,
dst_reg->max_value); dst_reg->umax_value);
src_reg->smin_value = dst_reg->smin_value = max(src_reg->smin_value,
dst_reg->smin_value);
src_reg->smax_value = dst_reg->smax_value = min(src_reg->smax_value,
dst_reg->smax_value);
src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off, src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off,
dst_reg->var_off); dst_reg->var_off);
check_reg_overflow(src_reg); /* We might have learned new bounds from the var_off. */
check_reg_overflow(dst_reg); __update_reg_bounds(src_reg);
__update_reg_bounds(dst_reg);
/* We might have learned something about the sign bit. */
__reg_deduce_bounds(src_reg);
__reg_deduce_bounds(dst_reg);
/* We might have learned some bits from the bounds. */
__reg_bound_offset(src_reg);
__reg_bound_offset(dst_reg);
/* Intersecting with the old var_off might have improved our bounds
* slightly. e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
* then new var_off is (0; 0x7f...fc) which improves our umax.
*/
__update_reg_bounds(src_reg);
__update_reg_bounds(dst_reg);
} }
static void reg_combine_min_max(struct bpf_reg_state *true_src, static void reg_combine_min_max(struct bpf_reg_state *true_src,
...@@ -2467,6 +2587,7 @@ static void reg_combine_min_max(struct bpf_reg_state *true_src, ...@@ -2467,6 +2587,7 @@ static void reg_combine_min_max(struct bpf_reg_state *true_src,
break; break;
case BPF_JNE: case BPF_JNE:
__reg_combine_min_max(false_src, false_dst); __reg_combine_min_max(false_src, false_dst);
break;
} }
} }
...@@ -2480,11 +2601,11 @@ static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id, ...@@ -2480,11 +2601,11 @@ static void mark_map_reg(struct bpf_reg_state *regs, u32 regno, u32 id,
* have been known-zero, because we don't allow pointer * have been known-zero, because we don't allow pointer
* arithmetic on pointers that might be NULL. * arithmetic on pointers that might be NULL.
*/ */
if (WARN_ON_ONCE(reg->min_value || reg->max_value || if (WARN_ON_ONCE(reg->smin_value || reg->smax_value ||
reg->var_off.value || reg->var_off.mask || !tnum_equals_const(reg->var_off, 0) ||
reg->off)) { reg->off)) {
reg->min_value = reg->max_value = reg->off = 0; __mark_reg_known_zero(reg);
reg->var_off = tnum_const(0); reg->off = 0;
} }
if (is_null) { if (is_null) {
reg->type = SCALAR_VALUE; reg->type = SCALAR_VALUE;
...@@ -2676,11 +2797,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -2676,11 +2797,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm; u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
regs[insn->dst_reg].type = SCALAR_VALUE; regs[insn->dst_reg].type = SCALAR_VALUE;
regs[insn->dst_reg].min_value = imm; __mark_reg_known(&regs[insn->dst_reg], imm);
regs[insn->dst_reg].max_value = imm;
check_reg_overflow(&regs[insn->dst_reg]);
regs[insn->dst_reg].var_off = tnum_const(imm);
regs[insn->dst_reg].id = 0;
return 0; return 0;
} }
...@@ -2968,8 +3085,10 @@ static int check_cfg(struct bpf_verifier_env *env) ...@@ -2968,8 +3085,10 @@ static int check_cfg(struct bpf_verifier_env *env)
static bool range_within(struct bpf_reg_state *old, static bool range_within(struct bpf_reg_state *old,
struct bpf_reg_state *cur) struct bpf_reg_state *cur)
{ {
return old->min_value <= cur->min_value && return old->umin_value <= cur->umin_value &&
old->max_value >= cur->max_value; old->umax_value >= cur->umax_value &&
old->smin_value <= cur->smin_value &&
old->smax_value >= cur->smax_value;
} }
/* Maximum number of register states that can exist at once */ /* Maximum number of register states that can exist at once */
...@@ -3032,8 +3151,10 @@ static bool regsafe(struct bpf_reg_state *rold, ...@@ -3032,8 +3151,10 @@ static bool regsafe(struct bpf_reg_state *rold,
* equal, because we can't know anything about the * equal, because we can't know anything about the
* scalar value of the pointer in the new value. * scalar value of the pointer in the new value.
*/ */
return rold->min_value == BPF_REGISTER_MIN_RANGE && return rold->umin_value == 0 &&
rold->max_value == BPF_REGISTER_MAX_RANGE && rold->umax_value == U64_MAX &&
rold->smin_value == S64_MIN &&
rold->smax_value == S64_MAX &&
tnum_is_unknown(rold->var_off); tnum_is_unknown(rold->var_off);
} }
case PTR_TO_MAP_VALUE: case PTR_TO_MAP_VALUE:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册