summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-29 08:10:23 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-29 08:10:23 -1000
commit46806af187f448b0d5481f284e7c900a57ee6a6d (patch)
tree4a664c1e3f24c91ad6df8b5c5e3bf2fd10b4ee1d /kernel
parentd011f648a708b231f7ef28c18ff30c815b07fe56 (diff)
parentc8a8a68d3ab4a06c8f5a13a8c00275351c8239b4 (diff)
Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Pull bpf fixes from Alexei Starovoitov: - Remove BPF_F_ARENA_SCALAR flag and .arena.data section in libbpf that were added for rust-bpf in this merge window. We found a cleaner approach that does it on compiler side instead of kernel/libbpf. No released kernel has them (Alexei Starovoitov) - Fix bpf_send_signal_task() returning -EPERM when it is called from a kernel thread (Aditya Sharma) - Various fixes (Alexei Starovoitov): - Use emit_rsb_call() to call bpf_unwind_target() in x86 JIT to fix objtool warning during the build - Fix scalar evolution: clear delta of a widened register, don't widen a pointer to a buffer, don't clamp a register whose type changed in the loop, and reset the range of a clamped packet pointer - Finish the insn in the state that maybe_fork_scalars() splits off, so that pruning doesn't drop it at the head of a counted loop - Preserve the registers that carry stack arguments across arch_bpf_timed_may_goto() on x86-64, arm64 and riscv64 - Don't re-sort subprog_info[] for every new subprogram - Fix flaky map_kptr and rcu_reentry selftests - Use memmove() in bpf_skb_load_bytes(), bpf_skb_load_bytes_relative() and bpf_xdp_load_bytes(), since the destination can be a slice of the same packet (Ayushman Rout) - Fixes and follow-ups for scalar evolution: reject pointer operands in 32-bit recurrences and latches, don't intersect with the current register range on clamp to avoid a false 'verifier bug', avoid false infinite loop reports, and recognize a 32-bit copy of the induction variable (Eduard Zingerman) - Fix out-of-bounds write to btf->types[] for split BTF and propagate btf_add_type() errors in btf_check_all_metas() (Feng Yang) - Fix use-after-free in bpf_timer callback that fires after its inner map was freed (Mani Tofigh) - Fix x86 JIT stopping before jumps converge: size backward jumps by the insns they jump over (Mykyta Yatsenko) - Fix use-after-free of struct_ops trampoline: dissociate struct_ops progs before the grace period of the map (Qiliang Yuan) - Validate stack argument reads against the caller state to fix out-of-bounds read in the verifier, and reject callbacks with stack arguments (Weiming Shi) - Tie borrowed iterator results and pointers loaded from trusted fields to the lifetime of their source, so that iterator next, destroy and reference release invalidate them (Xu Yunxiang) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: (48 commits) bpf: Don't re-sort subprog_info[] for every new subprogram bpf: Fix out-of-bounds btf->types write for split BTF selftests/bpf: Test stack arguments across may_goto bpf: Keep stack arguments in arch_bpf_timed_may_goto() selftests/bpf: Test maybe_fork_scalars() at the head of a counted loop bpf: Finish the insn in the state that maybe_fork_scalars() splits off selftests/bpf: Test the clamp of pointers in scalar evolution bpf: Reset the range of a packet pointer that scalar evolution clamps bpf: Don't clamp a register whose type changed in the loop selftests/bpf: Test a loop that moves a pointer to a buffer bpf: Don't widen a pointer to a buffer in scalar evolution selftests/bpf: Avoid a page fault in rcu_reentry while the handler is armed selftests/bpf: Wait for the last maps of map_kptr to be freed selftests/bpf: Test that a widened register is not linked bpf: Clear delta of a register that scalar evolution widens bpf, x86: Remove r0_on_stack from fetching atomics in arena bpf: Remove BPF_F_ARENA_SCALAR selftests/bpf: Remove tests for arena access through numbers libbpf: Keep format strings of bpf_printk() in .rodata libbpf: Remove .arena.data ...
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/bpf_struct_ops.c29
-rw-r--r--kernel/bpf/btf.c26
-rw-r--r--kernel/bpf/core.c12
-rw-r--r--kernel/bpf/fixups.c39
-rw-r--r--kernel/bpf/helpers.c11
-rw-r--r--kernel/bpf/log.c8
-rw-r--r--kernel/bpf/scev.c65
-rw-r--r--kernel/bpf/states.c36
-rw-r--r--kernel/bpf/syscall.c4
-rw-r--r--kernel/bpf/verifier.c205
-rw-r--r--kernel/trace/bpf_trace.c9
11 files changed, 237 insertions, 207 deletions
diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index 1178acd72296..7c5cd6086e27 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -1030,6 +1030,7 @@ static void bpf_struct_ops_map_free_pre_rcu(struct bpf_map *map)
struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
bpf_struct_ops_map_del_ksyms(st_map);
+ bpf_struct_ops_map_dissoc_progs(st_map);
}
static void bpf_struct_ops_map_free(struct bpf_map *map)
@@ -1045,8 +1046,6 @@ static void bpf_struct_ops_map_free(struct bpf_map *map)
if (btf_is_module(st_map->btf))
module_put(st_map->st_ops_desc->st_ops->owner);
- bpf_struct_ops_map_dissoc_progs(st_map);
-
if (tasks_rcu && IS_ENABLED(CONFIG_TASKS_RCU))
synchronize_rcu_tasks();
@@ -1162,8 +1161,11 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
mutex_init(&st_map->lock);
bpf_map_init_from_attr(map, attr);
- map->free_after_mult_rcu_gp = st_ops_desc->st_ops->free_after_mult_rcu_gp;
- map->free_after_rcu_gp = true;
+ /*
+ * A prog dissociated in map_free_pre_rcu() may still run the struct_ops
+ * from a bpf_wq callback or a sleepable prog, under RCU tasks trace.
+ */
+ map->free_after_mult_rcu_gp = true;
return map;
@@ -1541,10 +1543,10 @@ int bpf_prog_assoc_struct_ops(struct bpf_prog *prog, struct bpf_map *map)
{
struct bpf_map *st_ops_assoc;
- guard(mutex)(&prog->aux->st_ops_assoc_mutex);
+ guard(spinlock_irqsave)(&prog->aux->st_ops_assoc_lock);
st_ops_assoc = rcu_dereference_protected(prog->aux->st_ops_assoc,
- lockdep_is_held(&prog->aux->st_ops_assoc_mutex));
+ lockdep_is_held(&prog->aux->st_ops_assoc_lock));
if (st_ops_assoc && st_ops_assoc == map)
return 0;
@@ -1569,19 +1571,20 @@ int bpf_prog_assoc_struct_ops(struct bpf_prog *prog, struct bpf_map *map)
void bpf_prog_disassoc_struct_ops(struct bpf_prog *prog)
{
+ struct bpf_prog_aux *aux = prog->aux;
struct bpf_map *st_ops_assoc;
- guard(mutex)(&prog->aux->st_ops_assoc_mutex);
+ scoped_guard(spinlock_irqsave, &aux->st_ops_assoc_lock) {
+ st_ops_assoc = rcu_dereference_protected(aux->st_ops_assoc,
+ lockdep_is_held(&aux->st_ops_assoc_lock));
+ if (!st_ops_assoc || st_ops_assoc == BPF_PTR_POISON)
+ return;
- st_ops_assoc = rcu_dereference_protected(prog->aux->st_ops_assoc,
- lockdep_is_held(&prog->aux->st_ops_assoc_mutex));
- if (!st_ops_assoc || st_ops_assoc == BPF_PTR_POISON)
- return;
+ RCU_INIT_POINTER(aux->st_ops_assoc, NULL);
+ }
if (prog->type != BPF_PROG_TYPE_STRUCT_OPS)
bpf_map_put(st_ops_assoc);
-
- RCU_INIT_POINTER(prog->aux->st_ops_assoc, NULL);
}
/*
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 538129ed2418..1be30487a2fa 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -1752,15 +1752,16 @@ static int btf_add_type(struct btf_verifier_env *env, struct btf_type *t)
/* Expand 'types' array */
struct btf_type **new_types;
- u32 expand_by, new_size;
+ u32 expand_by, new_size, max_size;
- if (btf->start_id + btf->types_size == BTF_MAX_TYPE) {
+ if (btf->start_id + btf->types_size >= BTF_MAX_TYPE) {
btf_verifier_log(env, "Exceeded max num of types");
return -E2BIG;
}
+ max_size = BTF_MAX_TYPE - btf->start_id;
expand_by = max_t(u32, btf->types_size >> 2, 16);
- new_size = min_t(u32, BTF_MAX_TYPE,
+ new_size = min_t(u32, max_size,
btf->types_size + expand_by);
new_types = kvzalloc_objs(*new_types, new_size,
@@ -5871,6 +5872,7 @@ static int btf_check_all_metas(struct btf_verifier_env *env)
struct btf *btf = env->btf;
struct btf_header *hdr;
void *cur, *end;
+ int err;
hdr = &btf->hdr;
cur = btf->nohdr_data + hdr->type_off;
@@ -5885,7 +5887,10 @@ static int btf_check_all_metas(struct btf_verifier_env *env)
if (meta_size < 0)
return meta_size;
- btf_add_type(env, t);
+ err = btf_add_type(env, t);
+ if (err)
+ return err;
+
cur += meta_size;
env->log_type_id++;
}
@@ -9716,6 +9721,10 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
if (!flags || (flags & (flags - 1)))
return -EINVAL;
+ if ((func_flags & KF_ITER_RET_INDEPENDENT) &&
+ (!(flags & KF_ITER_NEXT) || (func_flags & KF_ACQUIRE)))
+ return -EINVAL;
+
/* any BPF iter kfunc should have `struct bpf_iter_<type> *` first arg */
nr_args = btf_type_vlen(func);
if (nr_args < 1)
@@ -9756,6 +9765,12 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
t = btf_type_skip_modifiers(btf, func->type, NULL);
if (!t || !btf_type_is_ptr(t))
return -EINVAL;
+ /* The opt-out applies only to non-acquired struct results. */
+ if (func_flags & KF_ITER_RET_INDEPENDENT) {
+ t = btf_type_skip_modifiers(btf, t->type, NULL);
+ if (!t || !__btf_type_is_struct(t))
+ return -EINVAL;
+ }
}
if (flags & KF_ITER_DESTROY) {
@@ -9822,7 +9837,8 @@ static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
if (!func || !btf_type_is_func_proto(func))
return -EINVAL;
- if (func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY)) {
+ if (func_flags & (KF_ITER_NEW | KF_ITER_NEXT | KF_ITER_DESTROY |
+ KF_ITER_RET_INDEPENDENT)) {
err = btf_check_iter_kfuncs(btf, func_name, func, func_flags);
if (err)
return err;
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 3030beb531d9..7cf37690d41f 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -141,7 +141,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
mutex_init(&fp->aux->used_maps_mutex);
mutex_init(&fp->aux->ext_mutex);
mutex_init(&fp->aux->dst_mutex);
- mutex_init(&fp->aux->st_ops_assoc_mutex);
+ spin_lock_init(&fp->aux->st_ops_assoc_lock);
return fp;
}
@@ -291,7 +291,6 @@ void __bpf_prog_free(struct bpf_prog *fp)
#endif
mutex_destroy(&fp->aux->used_maps_mutex);
mutex_destroy(&fp->aux->dst_mutex);
- mutex_destroy(&fp->aux->st_ops_assoc_mutex);
kfree(fp->aux->poke_tab);
kfree(fp->aux);
}
@@ -2640,8 +2639,7 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
/*
* Whether a function has an insn that works with the arena base, which a JIT
* sets up in the prologue when bpf_prog_uses_arena_insns() says so. Decided on
- * the final insns of the function: an access through an arena pointer, or
- * through a number in a program loaded with BPF_F_ARENA_SCALAR, has been
+ * the final insns of the function: an access through an arena pointer has been
* rewritten to a BPF_PROBE_MEM32 form by then, a cast to the user address
* space keeps BPF_ADDR_SPACE_CAST, and a kfunc call with an __arena argument,
* which the JIT rebases, has a function model that says so. A load of an
@@ -3519,12 +3517,6 @@ bool __weak bpf_jit_supports_arena(void)
return false;
}
-/* Whether JIT takes BPF_REG_AX as the address of arena access */
-bool __weak bpf_jit_supports_arena_scalar(void)
-{
- return false;
-}
-
bool __weak bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
{
return false;
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index f062ef7dd943..41bc37e205e0 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -44,31 +44,6 @@ static bool is_addr_space_cast32(struct bpf_prog *prog, const struct bpf_insn *i
return false;
}
-/*
- * The insn accesses arena through a number. JITs add the base of arena
- * to the register as it is, so the access goes through the low 32 bits of
- * the number in BPF_REG_AX. Registers of the program are not changed: the
- * number may be compared or stored later, and on another path the register
- * may be PTR_TO_ARENA.
- *
- * Constant blinding leaves insns that use BPF_REG_AX alone, so the immediate
- * of st through a number is not blinded.
- */
-static int arena_scalar_access(const struct bpf_insn *insn, struct bpf_insn *buf)
-{
- bool load = BPF_CLASS(insn->code) == BPF_LDX || bpf_atomic_is_load_acq(insn);
- struct bpf_insn *patch = buf;
-
- *patch++ = BPF_MOV32_REG(BPF_REG_AX, load ? insn->src_reg : insn->dst_reg);
- *patch = *insn;
- if (load)
- patch->src_reg = BPF_REG_AX;
- else
- patch->dst_reg = BPF_REG_AX;
- patch++;
- return patch - buf;
-}
-
/* Return the regno defined by the insn, or -1. */
static int insn_def_regno(const struct bpf_insn *insn)
{
@@ -1880,20 +1855,6 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
/* Convert BPF_CLASS(insn->code) == BPF_ALU64 to 32-bit ALU */
insn->code = BPF_ALU | BPF_OP(insn->code) | BPF_SRC(insn->code);
- if (env->insn_aux_data[i + delta].arena_scalar) {
- cnt = arena_scalar_access(insn, insn_buf);
-
- new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
-
- delta += cnt - 1;
- prog = new_prog;
- env->prog = prog;
- insn = prog->insnsi + i + delta;
- goto next_insn;
- }
-
/* Make sdiv/smod divide-by-minus-one exceptions impossible. */
if ((insn->code == (BPF_ALU64 | BPF_MOD | BPF_K) ||
insn->code == (BPF_ALU64 | BPF_DIV | BPF_K) ||
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 648abe1ba63a..58e357302850 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1221,7 +1221,7 @@ static void bpf_async_refcount_put(struct bpf_async_cb *cb);
static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
{
struct bpf_hrtimer *t = container_of(hrtimer, struct bpf_hrtimer, timer);
- struct bpf_map *map = t->cb.map;
+ struct bpf_map *map = READ_ONCE(t->cb.map);
void *value = t->cb.value;
bpf_callback_t callback_fn;
void *key;
@@ -1229,7 +1229,7 @@ static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
BTF_TYPE_EMIT(struct bpf_timer);
callback_fn = rcu_dereference_check(t->cb.callback_fn, rcu_read_lock_bh_held());
- if (!callback_fn)
+ if (!callback_fn || !map)
goto out;
/* bpf_timer_cb() runs in hrtimer_run_softirq. It doesn't migrate and
@@ -1254,7 +1254,7 @@ static void bpf_wq_work(struct work_struct *work)
{
struct bpf_work *w = container_of(work, struct bpf_work, work);
struct bpf_async_cb *cb = &w->cb;
- struct bpf_map *map = cb->map;
+ struct bpf_map *map;
bpf_callback_t callback_fn;
void *value = cb->value;
void *key;
@@ -1265,8 +1265,9 @@ static void bpf_wq_work(struct work_struct *work)
/* keeps the program that callback_fn belongs to */
rcu_read_lock_trace();
+ map = READ_ONCE(cb->map);
callback_fn = READ_ONCE(cb->callback_fn);
- if (!callback_fn)
+ if (!callback_fn || !map)
goto out;
key = map_key_from_value(map, value, &idx);
@@ -1733,6 +1734,8 @@ static void bpf_async_cancel_and_free(struct bpf_async_kern *async)
if (!cb)
return;
+ /* Callbacks that run after this see NULL and return. */
+ WRITE_ONCE(cb->map, NULL);
bpf_async_update_prog_callback(cb, NULL, NULL);
/*
* No refcount_inc_not_zero(&cb->refcnt) here. Dropping the last
diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c
index 5432c0fc442b..fa29d9b994e4 100644
--- a/kernel/bpf/log.c
+++ b/kernel/bpf/log.c
@@ -535,6 +535,14 @@ void bpf_verbose_snum(struct bpf_verifier_env *env, s64 num)
verbose(env, "%#llx", num);
}
+void bpf_verbose_snum32(struct bpf_verifier_env *env, s32 num)
+{
+ if (is_snum_decimal(num))
+ verbose(env, "%d", num);
+ else
+ verbose(env, "%#x", (u32)num);
+}
+
int tnum_strn(char *str, size_t size, struct tnum a)
{
/* print as a constant, if tnum is fully known */
diff --git a/kernel/bpf/scev.c b/kernel/bpf/scev.c
index fea77772ca96..7b82fd79f9cc 100644
--- a/kernel/bpf/scev.c
+++ b/kernel/bpf/scev.c
@@ -1502,6 +1502,10 @@ static int simplify(struct scev *scev, u32 id, void *priv)
return t;
}
+ /* (zext32 (zext32 X)) -> (zext32 X) */
+ if (is_zext32(scev, id, &a) && is_zext32(scev, a, &b))
+ return a;
+
return id;
}
@@ -2024,7 +2028,8 @@ static void log_incompatible_scev_values(struct bpf_verifier_env *env, const cha
}
static bool scev_value_compatible(struct bpf_verifier_env *env, struct bpf_func_state *st,
- const struct scev_value *a, const struct scev_value *b)
+ const struct scev_value *a, const struct scev_value *b,
+ const struct linear_latch *latch)
{
const struct bpf_reg_state *ra, *rb;
@@ -2035,7 +2040,7 @@ static bool scev_value_compatible(struct bpf_verifier_env *env, struct bpf_func_
}
ra = scev_reg_for_read(env, st, a->ptr_reg);
rb = scev_reg_for_read(env, st, b->ptr_reg);
- if (ra && rb && bpf_same_memory_origin(ra, rb))
+ if (ra && rb && bpf_same_memory_origin(ra, rb) && !latch->zext32 && !latch->jmp32)
return true;
incompatible:
@@ -2267,7 +2272,7 @@ static bool compute_max_iters(struct bpf_verifier_env *env,
}
return false;
}
- if (!scev_value_compatible(env, st, &initial_val, &bound_val))
+ if (!scev_value_compatible(env, st, &initial_val, &bound_val, latch))
return false;
initial = initial_val.value;
@@ -2306,11 +2311,15 @@ static bool compute_max_iters(struct bpf_verifier_env *env,
if (!compute_backedge_taken_count(op, initial, step, bound, &backedge_taken_count))
return false;
+ /*
+ * max_header_count is u32 and U32_MAX means "infinite",
+ * check to avoid overflow below.
+ */
+ if (backedge_taken_count >= U32_MAX - 1)
+ return false;
+
if (latch->zext32 || latch->jmp32) {
- /*
- * compute_backedge_taken_count() guarantees that 'total_change'
- * does not overflow in 64-bit domain.
- */
+ /* total_change is guaranteed not to overflow at this point */
total_change = initial + step * backedge_taken_count;
if (latch->jmp32 && is_signed_op(op)) {
if ((s64)total_change < S32_MIN || (s64)total_change > S32_MAX)
@@ -2321,13 +2330,6 @@ static bool compute_max_iters(struct bpf_verifier_env *env,
}
}
- /*
- * max_header_count is u32 and U32_MAX means "infinite",
- * check to avoid overflow below.
- */
- if (backedge_taken_count >= U32_MAX - 1)
- return false;
-
/* The header executes once on entry and once for each taken backedge, hence +1. */
iters->max_header_count = backedge_taken_count + 1;
/*
@@ -2377,7 +2379,6 @@ static bool is_widenable_reg_type(const struct bpf_reg_state *reg)
case PTR_TO_PACKET:
case PTR_TO_PACKET_META:
case PTR_TO_MEM:
- case PTR_TO_BUF:
case PTR_TO_BTF_ID:
return true;
default:
@@ -2389,7 +2390,7 @@ static void scratch_widened_reg_id(struct bpf_verifier_env *env, struct bpf_reg_
{
switch (base_type(reg->type)) {
case SCALAR_VALUE:
- reg->id = 0;
+ clear_scalar_id(reg);
break;
case PTR_TO_PACKET:
case PTR_TO_PACKET_META:
@@ -2454,11 +2455,13 @@ static void log_bounds(struct bpf_verifier_env *env, const struct bounds *bounds
bpf_verbose_snum(env, cnum64_smin(bounds->r64));
bpf_log(log, "..");
bpf_verbose_snum(env, cnum64_smax(bounds->r64));
- if (bounds->r32.size < U32_MAX) {
+ if (bounds->r32.size < U32_MAX &&
+ (cnum32_smin(bounds->r32) != cnum64_smin(bounds->r64) ||
+ cnum32_smax(bounds->r32) != cnum64_smax(bounds->r64))) {
bpf_log(log, " (s32 ");
- bpf_verbose_snum(env, cnum32_smin(bounds->r32));
+ bpf_verbose_snum32(env, cnum32_smin(bounds->r32));
bpf_log(log, "..");
- bpf_verbose_snum(env, cnum32_smax(bounds->r32));
+ bpf_verbose_snum32(env, cnum32_smax(bounds->r32));
bpf_log(log, ")");
}
bpf_log(log, " step %u", bounds->step);
@@ -2700,6 +2703,9 @@ int bpf_compute_loop_iters(struct bpf_verifier_env *env, struct bpf_verifier_sta
reg = scev_reg_for_linear(cur_func, r);
/* If SCEV for r is (linear <reg> <slope>) */
if (reg && is_simple_linear(scev, r_scev, &coefs) && is_widenable_reg_type(reg)) {
+ /* 32-bit ALU operations on pointers convert them to scalars */
+ if (coefs.zext32 && reg->type != SCALAR_VALUE)
+ goto cant_widen;
/* Spills at varying offsets lose precision */
if (test_bit(r, loop->store_base_regs)) {
spill_base = true;
@@ -2891,13 +2897,15 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
is_unbound_scev_reg(env, entry_st, r))
continue;
+ /*
+ * A call in the loop can change the type: it invalidates packet pointers or
+ * releases a reference. The bounds are the offsets of the pointer at the entry.
+ * They say nothing about the value that is in the register now.
+ */
+ if (reg->type != entry_reg->type)
+ continue;
+
linear_bounds(entry_reg, max_header_count, &coefs, &bounds);
- bounds.r64 = cnum64_intersect(reg->r64, bounds.r64);
- bounds.r32 = cnum32_intersect(reg->r32, bounds.r32);
- if (cnum64_is_empty(bounds.r64)) {
- verifier_bug(env, "scev clamp produced empty range for r%d", r);
- return -EFAULT;
- }
if (log->level & BPF_LOG_LEVEL2) {
bpf_log(log, "loop header at %d, clamping ", insn_idx);
log_reg(env, r);
@@ -2906,6 +2914,13 @@ int bpf_clamp_scev_regs(struct bpf_verifier_env *env, struct bpf_func_state *cur
bpf_log(log, "\n");
}
scratch_widened_reg_id(env, reg);
+ /*
+ * The range of a packet pointer goes together with its id and with the offsets
+ * that it had in the compare with pkt_end. Both are replaced here. What holds for
+ * the new offsets is the range at the entry.
+ */
+ if (type_is_pkt_pointer(reg->type))
+ reg->range = max(entry_reg->range, 0);
err = bpf_set_reg_range(env, reg, bounds.r64, bounds.r32,
bounds.base, bounds.step);
if (err)
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index d7df6632a5c4..a6ae86f973e3 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -1358,13 +1358,33 @@ static bool need_loop_checkpoint(struct bpf_verifier_env *env, int insn_idx)
return top->loop_id == insn_idx && top->terminates;
}
+/* Searches for an innermost loop entry starting from an innermost frame. */
static struct loop_stack_entry *current_loop(struct bpf_verifier_state *st)
{
- struct bpf_func_state *frame = st->frame[st->curframe];
+ struct bpf_func_state *frame;
+ int fr;
- if (frame->loop_stack_cnt == 0)
- return NULL;
- return &frame->loop_stack[frame->loop_stack_cnt - 1];
+ for (fr = st->curframe; fr >= 0; fr--) {
+ frame = st->frame[fr];
+ if (frame->loop_stack_cnt)
+ return &frame->loop_stack[frame->loop_stack_cnt - 1];
+ }
+ return NULL;
+}
+
+/* True if any of the loops call chain is currently in terminates. */
+static bool in_a_terminating_loop(struct bpf_verifier_state *st)
+{
+ struct bpf_func_state *frame;
+ int l, fr;
+
+ for (fr = st->curframe; fr >= 0; fr--) {
+ frame = st->frame[fr];
+ for (l = frame->loop_stack_cnt - 1; l >= 0; l--)
+ if (frame->loop_stack[l].terminates)
+ return true;
+ }
+ return false;
}
int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
@@ -1528,10 +1548,10 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
*/
old_loop = current_loop(&sl->state);
cur_loop = current_loop(cur);
- if (old_loop && cur_loop &&
- old_loop->terminates && cur_loop->terminates &&
- old_loop->entry_state == cur_loop->entry_state) {
- if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) {
+ if (old_loop && cur_loop && in_a_terminating_loop(cur)) {
+ if (old_loop->terminates && cur_loop->terminates &&
+ old_loop->entry_state == cur_loop->entry_state &&
+ states_equal(env, &sl->state, cur, RANGE_WITHIN)) {
loop = true;
goto hit;
}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 90bc7230afa8..60c4d84b9aba 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2971,13 +2971,9 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
BPF_F_XDP_HAS_FRAGS |
BPF_F_XDP_DEV_BOUND_ONLY |
BPF_F_TEST_REG_INVARIANTS |
- BPF_F_ARENA_SCALAR |
BPF_F_TOKEN_FD))
return -EINVAL;
- if ((attr->prog_flags & BPF_F_ARENA_SCALAR) && !bpf_jit_supports_arena_scalar())
- return -EOPNOTSUPP;
-
bpf_prog_load_fixup_attach_type(attr);
if (attr->prog_flags & BPF_F_TOKEN_FD) {
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 5601d2056218..26a5ee0708a3 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -211,6 +211,9 @@ static int acquire_reference(struct bpf_verifier_env *env, int insn_idx, int par
static int __release_reference_nomark(struct bpf_verifier_state *state, int id);
static int release_reference_nomark(struct bpf_verifier_env *env, int id);
static int release_reference(struct bpf_verifier_env *env, int id);
+static int invalidate_reference(struct bpf_verifier_env *env, int id);
+static u32 reg_lifetime_id(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg);
static void invalidate_non_owning_refs(struct bpf_verifier_env *env);
static void invalidate_rcu_protected_refs(struct bpf_verifier_env *env);
static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env);
@@ -793,8 +796,8 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_
if (err)
return err;
- /* Track parent's id if the parent is a referenced object */
- parent_id = ref_obj->id;
+ /* All non-clone constructors take their backing object in R1. */
+ parent_id = reg_lifetime_id(env, &cur_regs(env)[BPF_REG_1]);
if (dynptr_type_referenced(type)) {
int id;
@@ -1074,7 +1077,7 @@ static int unmark_stack_slots_iter(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, int nr_slots)
{
struct bpf_func_state *state = bpf_func(env, reg);
- int spi, i, j;
+ int spi, i, j, err;
spi = iter_get_spi(env, reg, nr_slots);
if (spi < 0)
@@ -1084,8 +1087,11 @@ static int unmark_stack_slots_iter(struct bpf_verifier_env *env,
struct bpf_stack_state *slot = bpf_stack_slot(state, spi - i);
struct bpf_reg_state *st = &slot->spilled_ptr;
- if (i == 0)
- WARN_ON_ONCE(release_reference(env, st->id));
+ if (i == 0) {
+ err = release_reference(env, st->id);
+ if (err)
+ return err;
+ }
bpf_mark_reg_not_init(env, st);
@@ -1627,6 +1633,12 @@ static bool reg_is_referenced(struct bpf_verifier_env *env, const struct bpf_reg
return find_reference_state(env->cur_state, reg->id);
}
+static u32 reg_lifetime_id(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg)
+{
+ return reg_is_referenced(env, reg) ? reg->id : reg->parent_id;
+}
+
static int release_lock_state(struct bpf_verifier_env *env, int type, int id, void *ptr)
{
struct bpf_verifier_state *state = env->cur_state;
@@ -2605,12 +2617,6 @@ static struct bpf_verifier_state *push_async_cb(struct bpf_verifier_env *env,
return &elem->st;
}
-static int cmp_subprogs(const void *a, const void *b)
-{
- return ((struct bpf_subprog_info *)a)->start -
- ((struct bpf_subprog_info *)b)->start;
-}
-
/* Find subprogram that contains instruction at 'off' */
struct bpf_subprog_info *bpf_find_containing_subprog(struct bpf_verifier_env *env, int off)
{
@@ -2645,26 +2651,29 @@ int bpf_find_subprog(struct bpf_verifier_env *env, int off)
static int add_subprog(struct bpf_verifier_env *env, int off)
{
+ struct bpf_subprog_info *subprog = env->subprog_info;
int insn_cnt = env->prog->len;
- int ret;
+ int i;
if (off >= insn_cnt || off < 0) {
verbose(env, "call to invalid destination\n");
return -EINVAL;
}
- ret = bpf_find_subprog(env, off);
- if (ret >= 0)
- return ret;
+ i = bpf_find_subprog(env, off);
+ if (i >= 0)
+ return i;
if (env->subprog_cnt >= BPF_MAX_SUBPROGS) {
verbose(env, "too many subprograms\n");
return -E2BIG;
}
- /* determine subprog starts. The end is one before the next starts */
- env->subprog_info[env->subprog_cnt].exit_idx = U32_MAX;
- env->subprog_info[env->subprog_cnt++].start = off;
- sort(env->subprog_info, env->subprog_cnt,
- sizeof(env->subprog_info[0]), cmp_subprogs, NULL);
- return env->subprog_cnt - 1;
+ /*
+ * Determine subprog starts. The end is one before the next starts.
+ * The array stays sorted: subprogs that start after 'off' move up.
+ */
+ for (i = env->subprog_cnt++; i > 0 && subprog[i - 1].start > off; i--)
+ subprog[i] = subprog[i - 1];
+ subprog[i] = (struct bpf_subprog_info){ .start = off, .exit_idx = U32_MAX };
+ return i;
}
static int bpf_find_exception_callback_insn_off(struct bpf_verifier_env *env)
@@ -3812,12 +3821,6 @@ static bool __is_pointer_value(bool allow_ptr_leaks,
return is_pointer_regtype(reg->type);
}
-static void clear_scalar_id(struct bpf_reg_state *reg)
-{
- reg->id = 0;
- reg->delta = 0;
-}
-
static void assign_scalar_id_before_mov(struct bpf_verifier_env *env,
struct bpf_reg_state *src_reg)
{
@@ -4654,7 +4657,12 @@ static int check_stack_arg_read(struct bpf_verifier_env *env, struct bpf_func_st
}
caller = vstate->frame[vstate->curframe - 1];
- arg = &caller->stack_arg_regs[spi];
+ arg = bpf_get_spilled_stack_arg(spi, caller);
+ if (!arg) {
+ verbose(env, "invalid read from uninitialized stack arg off %d\n", off);
+ return -EACCES;
+ }
+
cur = vstate->frame[vstate->curframe];
bpf_diag_mod_begin(env, &cur->regs[dst_regno], arg, BPF_DIAG_MOD_WRITE);
cur->regs[dst_regno] = *arg;
@@ -5483,19 +5491,6 @@ static bool is_arena_reg(struct bpf_verifier_env *env, int regno)
return reg->type == PTR_TO_ARENA;
}
-/*
- * There are no address spaces in Rust, addresses of arena are plain numbers.
- * When the program is loaded with BPF_F_ARENA_SCALAR and has an arena a load or
- * a store through a number is an access to arena at the low 32 bits of it,
- * like the access through PTR_TO_ARENA is. The register stays a number.
- */
-static bool is_arena_scalar(struct bpf_verifier_env *env, int regno)
-{
- const struct bpf_reg_state *reg = reg_state(env, regno);
-
- return reg->type == SCALAR_VALUE && env->arena_scalar && env->prog->aux->arena;
-}
-
static bool is_load_acq_unsafe(struct bpf_verifier_env *env, int regno,
struct bpf_insn *insn)
{
@@ -5526,7 +5521,7 @@ static bool atomic_ptr_type_ok(struct bpf_verifier_env *env, int regno,
return false;
if (is_sk_reg(env, regno))
return false;
- if (is_arena_reg(env, regno) || is_arena_scalar(env, regno))
+ if (is_arena_reg(env, regno))
return bpf_jit_supports_insn(insn, true);
if (is_load_acq_unsafe(env, regno, insn))
return false;
@@ -6848,9 +6843,14 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
flag &= ~PTR_MAYBE_NULL;
if (atype == BPF_READ && value_regno >= 0) {
+ u32 parent_id = reg_lifetime_id(env, reg);
+
ret = mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag);
if (ret < 0)
return ret;
+ if ((regs[value_regno].type & PTR_TRUSTED) &&
+ !(regs[value_regno].type & (MEM_RCU | MEM_PERCPU | MEM_USER)))
+ regs[value_regno].parent_id = parent_id;
}
return 0;
@@ -7502,22 +7502,6 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
static int save_aux_ptr_type(struct bpf_verifier_env *env, enum bpf_reg_type type,
bool allow_trust_mismatch);
-/*
- * Returns the register to check the access of the current insn with.
- * For a number in a program with an arena that is 'arena'.
- */
-static struct bpf_reg_state *mem_access_reg(struct bpf_verifier_env *env, int regno,
- struct bpf_reg_state *arena)
-{
- if (!is_arena_scalar(env, regno))
- return cur_regs(env) + regno;
-
- memset(arena, 0, sizeof(*arena));
- arena->type = PTR_TO_ARENA;
- env->insn_aux_data[env->insn_idx].arena_scalar = true;
- return arena;
-}
-
static int check_load_mem(struct bpf_verifier_env *env, struct bpf_insn *insn,
bool strict_alignment_once, bool is_ldsx,
bool allow_trust_mismatch, const char *ctx)
@@ -7525,7 +7509,6 @@ static int check_load_mem(struct bpf_verifier_env *env, struct bpf_insn *insn,
struct bpf_verifier_state *vstate = env->cur_state;
struct bpf_func_state *state = vstate->frame[vstate->curframe];
struct bpf_reg_state *regs = cur_regs(env);
- struct bpf_reg_state arena, *src_reg;
enum bpf_reg_type src_reg_type;
int err;
@@ -7547,16 +7530,16 @@ static int check_load_mem(struct bpf_verifier_env *env, struct bpf_insn *insn,
if (err)
return err;
- src_reg = mem_access_reg(env, insn->src_reg, &arena);
- src_reg_type = src_reg->type;
+ src_reg_type = regs[insn->src_reg].type;
/*
* check_stack_read_fixed_off() may refine the modification's origin to
* the source stack slot.
*/
bpf_diag_mod_begin(env, &regs[insn->dst_reg], NULL, BPF_DIAG_MOD_WRITE);
- err = check_mem_access(env, env->insn_idx, src_reg, argno_from_reg(insn->src_reg),
- insn->off, BPF_SIZE(insn->code), BPF_READ, insn->dst_reg,
+ err = check_mem_access(env, env->insn_idx, regs + insn->src_reg,
+ argno_from_reg(insn->src_reg), insn->off,
+ BPF_SIZE(insn->code), BPF_READ, insn->dst_reg,
strict_alignment_once, is_ldsx);
/*
* Paths through a kernel struct pointer and through other pointers
@@ -7584,7 +7567,6 @@ static int check_store_reg(struct bpf_verifier_env *env, struct bpf_insn *insn,
struct bpf_verifier_state *vstate = env->cur_state;
struct bpf_func_state *state = vstate->frame[vstate->curframe];
struct bpf_reg_state *regs = cur_regs(env);
- struct bpf_reg_state arena, *dst_reg;
enum bpf_reg_type dst_reg_type;
int err;
@@ -7606,12 +7588,12 @@ static int check_store_reg(struct bpf_verifier_env *env, struct bpf_insn *insn,
if (err)
return err;
- dst_reg = mem_access_reg(env, insn->dst_reg, &arena);
- dst_reg_type = dst_reg->type;
+ dst_reg_type = regs[insn->dst_reg].type;
/* Check if (dst_reg + off) is writeable. */
- err = check_mem_access(env, env->insn_idx, dst_reg, argno_from_reg(insn->dst_reg),
- insn->off, BPF_SIZE(insn->code), BPF_WRITE, insn->src_reg,
+ err = check_mem_access(env, env->insn_idx, regs + insn->dst_reg,
+ argno_from_reg(insn->dst_reg), insn->off,
+ BPF_SIZE(insn->code), BPF_WRITE, insn->src_reg,
strict_alignment_once, false);
err = err ?: save_aux_ptr_type(env, dst_reg_type, false);
@@ -7621,7 +7603,7 @@ static int check_store_reg(struct bpf_verifier_env *env, struct bpf_insn *insn,
static int check_atomic_rmw(struct bpf_verifier_env *env,
struct bpf_insn *insn)
{
- struct bpf_reg_state arena, *dst_reg;
+ struct bpf_reg_state *dst_reg;
int load_reg;
int err;
@@ -7666,9 +7648,6 @@ static int check_atomic_rmw(struct bpf_verifier_env *env,
return -EACCES;
}
- /* load_reg may be dst_reg. Look at dst_reg before it's marked as unknown. */
- dst_reg = mem_access_reg(env, insn->dst_reg, &arena);
-
load_reg = bpf_atomic_load_reg(insn);
if (load_reg >= 0) {
/* check and record load of old value */
@@ -7677,6 +7656,8 @@ static int check_atomic_rmw(struct bpf_verifier_env *env,
return err;
}
+ dst_reg = cur_regs(env) + insn->dst_reg;
+
/* Check whether we can read the memory, with second call for fetch
* case to simulate the register fill.
*/
@@ -8636,6 +8617,21 @@ static bool is_iter_destroy_kfunc(struct bpf_call_arg_meta *meta)
return meta->kfunc_flags & KF_ITER_DESTROY;
}
+static bool iter_next_borrows_struct(struct bpf_call_arg_meta *meta)
+{
+ const struct btf_type *t;
+
+ if (!(meta->kfunc_flags & KF_ITER_NEXT) ||
+ (meta->kfunc_flags & (KF_ITER_RET_INDEPENDENT | KF_ACQUIRE)))
+ return false;
+
+ t = btf_type_skip_modifiers(meta->btf, meta->func_proto->type, NULL);
+ if (!t || !btf_type_is_ptr(t))
+ return false;
+ t = btf_type_skip_modifiers(meta->btf, t->type, NULL);
+ return t && __btf_type_is_struct(t);
+}
+
static bool is_kfunc_arg_iter(struct bpf_call_arg_meta *meta, int arg_idx,
const struct btf_param *arg)
{
@@ -8746,6 +8742,13 @@ static int process_iter_arg(struct bpf_verifier_env *env, struct bpf_reg_state *
meta->iter.frameno = reg->frameno;
update_ref_obj(&meta->ref_obj, &bpf_stack_slot(state, spi)->spilled_ptr);
+ /* The iterator stays. What was borrowed from the previous element goes. */
+ if (iter_next_borrows_struct(meta)) {
+ err = invalidate_reference(env, meta->ref_obj.id);
+ if (err)
+ return err;
+ }
+
if (is_iter_destroy_kfunc(meta)) {
err = unmark_stack_slots_iter(env, reg, nr_slots);
if (err)
@@ -11073,8 +11076,8 @@ static int idstack_pop(struct bpf_idmap *idmap)
return idmap->map[--idmap->cnt].old;
}
-/* Release id and objects derived from it iteratively in a DFS manner */
-static int release_reference(struct bpf_verifier_env *env, int id)
+/* Invalidate id and objects derived from it iteratively in a DFS manner */
+static int invalidate_reference(struct bpf_verifier_env *env, int id)
{
u32 mask = (1 << STACK_SPILL) | (1 << STACK_DYNPTR);
struct bpf_verifier_state *vstate = env->cur_state;
@@ -11089,11 +11092,6 @@ static int release_reference(struct bpf_verifier_env *env, int id)
if (err)
return err;
- if (find_reference_state(vstate, id)) {
- err = release_reference_nomark(env, id);
- WARN_ON_ONCE(err);
- }
-
while ((id = idstack_pop(idstack))) {
/*
* Child references are inaccessible after parent is released,
@@ -11145,6 +11143,14 @@ static int release_reference(struct bpf_verifier_env *env, int id)
return 0;
}
+static int release_reference(struct bpf_verifier_env *env, int id)
+{
+ if (find_reference_state(env->cur_state, id))
+ WARN_ON_ONCE(release_reference_nomark(env, id));
+
+ return invalidate_reference(env, id);
+}
+
static void invalidate_non_owning_refs(struct bpf_verifier_env *env)
{
struct bpf_func_state *unused;
@@ -11409,6 +11415,10 @@ static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *ins
err = btf_check_subprog_call(env, subprog);
if (err == -EFAULT)
return err;
+ if (bpf_in_stack_arg_cnt(&env->subprog_info[subprog])) {
+ verbose(env, "callback subprog cannot have stack args\n");
+ return -EINVAL;
+ }
/* set_callee_state is used for direct subprog calls, but we are
* interested in validating only BPF helpers that can call subprogs as
@@ -15822,6 +15832,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
regs[BPF_REG_0].btf = desc_btf;
regs[BPF_REG_0].type = type;
regs[BPF_REG_0].btf_id = ptr_type_id;
+ if (iter_next_borrows_struct(&meta) && !(type & MEM_RCU))
+ regs[BPF_REG_0].parent_id = meta.ref_obj.id;
}
if (is_kfunc_ret_null(&meta)) {
@@ -17274,11 +17286,14 @@ static bool is_safe_to_compute_dst_reg_range(struct bpf_insn *insn,
}
}
+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);
+
static int maybe_fork_scalars(struct bpf_verifier_env *env, struct bpf_insn *insn,
- struct bpf_reg_state *dst_reg)
+ struct bpf_reg_state *dst_reg, const struct bpf_reg_state *src_reg)
{
struct bpf_verifier_state *branch;
- struct bpf_reg_state *regs;
+ struct bpf_reg_state *reg;
bool alu32;
if (reg_smin(dst_reg) == -1 && reg_smax(dst_reg) == 0)
@@ -17288,19 +17303,25 @@ static int maybe_fork_scalars(struct bpf_verifier_env *env, struct bpf_insn *ins
else
return 0;
- branch = push_stack(env, env->insn_idx, env->insn_idx, false);
+ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
if (IS_ERR(branch))
return PTR_ERR(branch);
- regs = branch->frame[branch->curframe]->regs;
+ reg = &branch->frame[branch->curframe]->regs[insn->dst_reg];
if (alu32) {
- __mark_reg32_known(&regs[insn->dst_reg], 0);
+ __mark_reg32_known(reg, 0);
__mark_reg32_known(dst_reg, -1ull);
} else {
- __mark_reg_known(&regs[insn->dst_reg], 0);
+ __mark_reg_known(reg, 0);
__mark_reg_known(dst_reg, -1ull);
}
- return 0;
+ /*
+ * The insn is done with in the branch too, and what gets to the next insn is a state
+ * like any other. At this insn the branch is a part of the state that is looked at:
+ * it must not be compared with it.
+ */
+ clear_scalar_id(reg);
+ return adjust_scalar_min_max_vals(env, insn, reg, *src_reg);
}
/* WARNING: This function does calculations on 64-bit values, but the actual
@@ -17405,7 +17426,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
break;
case BPF_AND:
if (tnum_is_const(src_reg.var_off)) {
- ret = maybe_fork_scalars(env, insn, dst_reg);
+ ret = maybe_fork_scalars(env, insn, dst_reg, &src_reg);
if (ret)
return ret;
}
@@ -17416,7 +17437,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
break;
case BPF_OR:
if (tnum_is_const(src_reg.var_off)) {
- ret = maybe_fork_scalars(env, insn, dst_reg);
+ ret = maybe_fork_scalars(env, insn, dst_reg, &src_reg);
if (ret)
return ret;
}
@@ -20236,17 +20257,16 @@ static int do_check_insn(struct bpf_verifier_env *env, bool *do_print_state)
return check_stack_arg_write(env, state, insn->off, NULL);
}
- struct bpf_reg_state arena, *dst_reg;
enum bpf_reg_type dst_reg_type;
err = check_reg_arg(env, insn->dst_reg, SRC_OP);
if (err)
return err;
- dst_reg = mem_access_reg(env, insn->dst_reg, &arena);
- dst_reg_type = dst_reg->type;
+ dst_reg_type = cur_regs(env)[insn->dst_reg].type;
- err = check_mem_access(env, env->insn_idx, dst_reg, argno_from_reg(insn->dst_reg),
+ err = check_mem_access(env, env->insn_idx, cur_regs(env) + insn->dst_reg,
+ argno_from_reg(insn->dst_reg),
insn->off, BPF_SIZE(insn->code),
BPF_WRITE, -1, false, false);
if (err)
@@ -23882,7 +23902,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
if (is_priv)
env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ;
env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS;
- env->arena_scalar = attr->prog_flags & BPF_F_ARENA_SCALAR;
env->explored_states = kvzalloc_objs(struct list_head,
state_htab_size(env),
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index dfac5e1b8f40..14adfb85fdb2 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -867,15 +867,12 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struc
siginfo = &info;
}
- /* Similar to bpf_probe_write_user, task needs to be
- * in a sound condition and kernel memory access be
- * permitted in order to send signal to the current
- * task.
+ /*
+ * Similar to bpf_probe_write_user, task needs to be
+ * in a sound condition.
*/
if (unlikely(task->flags & (PF_KTHREAD | PF_EXITING)))
return -EPERM;
- if (unlikely(!nmi_uaccess_okay()))
- return -EPERM;
/* Task should not be pid=1 to avoid kernel panic. */
if (unlikely(is_global_init(task)))
return -EPERM;