mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
Merge branch 'misc-bug-fixes-part-2'
Kumar Kartikeya Dwivedi says: ==================== Misc bug fixes - part 2 A set of miscellaneous fixes for bugs reported by Nicholas, plus some new findings by GPT-5.6-Sol and Sashiko. See commit logs for details. ==================== Link: https://patch.msgid.link/20260903214758.2727663-1-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
0237317ffc
|
|
@ -8749,6 +8749,7 @@ BPF_CALL_4(bpf_btf_find_by_name_kind, char *, name, int, name_sz, u32, kind, int
|
|||
const struct bpf_func_proto bpf_btf_find_by_name_kind_proto = {
|
||||
.func = bpf_btf_find_by_name_kind,
|
||||
.gpl_only = false,
|
||||
.might_sleep = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
||||
.arg2_type = ARG_MEM_SIZE,
|
||||
|
|
|
|||
|
|
@ -875,6 +875,7 @@ BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, si
|
|||
const struct bpf_func_proto bpf_get_stack_sleepable_proto = {
|
||||
.func = bpf_get_stack_sleepable,
|
||||
.gpl_only = true,
|
||||
.might_sleep = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_CTX,
|
||||
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
|
||||
|
|
@ -928,6 +929,7 @@ BPF_CALL_4(bpf_get_task_stack_sleepable, struct task_struct *, task, void *, buf
|
|||
const struct bpf_func_proto bpf_get_task_stack_sleepable_proto = {
|
||||
.func = bpf_get_task_stack_sleepable,
|
||||
.gpl_only = false,
|
||||
.might_sleep = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_BTF_ID,
|
||||
.arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
|
||||
|
|
|
|||
|
|
@ -5302,6 +5302,15 @@ static int check_max_stack_depth_subprog(struct bpf_verifier_env *env, int idx,
|
|||
if (!priv_stack_supported)
|
||||
subprog[idx].priv_stack_mode = NO_PRIV_STACK;
|
||||
process_func:
|
||||
if (subprog[idx].has_ld_abs) {
|
||||
for (tmp = idx; tmp >= 0; tmp = dinfo[tmp].caller) {
|
||||
if (subprog[tmp].is_cb) {
|
||||
verbose(env, "cannot use BPF_LD_[ABS|IND] within callback\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* protect against potential stack overflow that might happen when
|
||||
* bpf2bpf calls get combined with tailcalls. Limit the caller's stack
|
||||
* depth for such case down to 256 so that the worst case scenario
|
||||
|
|
@ -10235,9 +10244,10 @@ static void account_current_path(struct bpf_verifier_env *env)
|
|||
frame ? state->frame[frame - 1] : NULL);
|
||||
}
|
||||
|
||||
/* Are we currently verifying the callback for a rbtree helper that must
|
||||
* be called with lock held? If so, no need to complain about unreleased
|
||||
* lock
|
||||
/*
|
||||
* Are we currently verifying the callback for an rbtree kfunc that must
|
||||
* be called with a lock held, or one of that callback's subprogs? If so,
|
||||
* no need to complain about an unreleased lock.
|
||||
*/
|
||||
static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
|
||||
{
|
||||
|
|
@ -10245,17 +10255,19 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
|
|||
struct bpf_insn *insn = env->prog->insnsi;
|
||||
struct bpf_func_state *callee;
|
||||
int kfunc_btf_id;
|
||||
u32 frame;
|
||||
|
||||
if (!state->curframe)
|
||||
return false;
|
||||
for (frame = state->curframe; frame; frame--) {
|
||||
callee = state->frame[frame];
|
||||
if (!callee->in_callback_fn)
|
||||
continue;
|
||||
|
||||
callee = state->frame[state->curframe];
|
||||
kfunc_btf_id = insn[callee->callsite].imm;
|
||||
if (is_rbtree_lock_required_kfunc(kfunc_btf_id))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!callee->in_callback_fn)
|
||||
return false;
|
||||
|
||||
kfunc_btf_id = insn[callee->callsite].imm;
|
||||
return is_rbtree_lock_required_kfunc(kfunc_btf_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool retval_range_within(struct bpf_retval_range range, const struct bpf_reg_state *reg)
|
||||
|
|
@ -17179,6 +17191,7 @@ static bool may_access_skb(enum bpf_prog_type type)
|
|||
*/
|
||||
static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
||||
{
|
||||
struct bpf_verifier_state *state = env->cur_state;
|
||||
struct bpf_reg_state *regs = cur_regs(env);
|
||||
static const int ctx_reg = BPF_REG_6;
|
||||
u8 mode = BPF_MODE(insn->code);
|
||||
|
|
@ -17189,6 +17202,13 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = state->curframe; i; i--) {
|
||||
if (state->frame[i]->in_callback_fn) {
|
||||
verbose(env, "cannot use BPF_LD_[ABS|IND] within callback\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!env->ops->gen_ld_abs) {
|
||||
verifier_bug(env, "gen_ld_abs is null");
|
||||
return -EFAULT;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,58 @@ int preempt_sleepable_helper(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("?uprobe.s")
|
||||
__failure __msg("sleepable helper bpf_get_stack#")
|
||||
int preempt_sleepable_get_stack(struct pt_regs *ctx)
|
||||
{
|
||||
struct bpf_stack_build_id stack;
|
||||
|
||||
bpf_preempt_disable();
|
||||
bpf_get_stack(ctx, &stack, sizeof(stack),
|
||||
BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
|
||||
bpf_preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?uprobe.s")
|
||||
__failure __msg("sleepable helper bpf_get_task_stack#")
|
||||
int preempt_sleepable_get_task_stack(void *ctx)
|
||||
{
|
||||
struct bpf_stack_build_id stack;
|
||||
struct task_struct *task;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
bpf_preempt_disable();
|
||||
bpf_get_task_stack(task, &stack, sizeof(stack),
|
||||
BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
|
||||
bpf_preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?uprobe.s")
|
||||
__success
|
||||
int sleepable_get_stack(struct pt_regs *ctx)
|
||||
{
|
||||
struct bpf_stack_build_id stack;
|
||||
|
||||
bpf_get_stack(ctx, &stack, sizeof(stack),
|
||||
BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?uprobe.s")
|
||||
__success
|
||||
int sleepable_get_task_stack(void *ctx)
|
||||
{
|
||||
struct bpf_stack_build_id stack;
|
||||
struct task_struct *task;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
bpf_get_task_stack(task, &stack, sizeof(stack),
|
||||
BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
|
||||
__failure __msg("kernel func bpf_copy_from_user_str is sleepable within non-preemptible region")
|
||||
int preempt_sleepable_kfunc(void *ctx)
|
||||
|
|
|
|||
|
|
@ -272,6 +272,47 @@ static bool less__bad_res_spin_unlock(struct bpf_rb_node *a, const struct bpf_rb
|
|||
return false;
|
||||
}
|
||||
|
||||
static __noinline void rbtree_cb_unlock_relock(void)
|
||||
{
|
||||
bpf_spin_unlock(&glock);
|
||||
bpf_spin_lock(&glock);
|
||||
}
|
||||
|
||||
static __noinline void rbtree_cb_nested_unlock(void)
|
||||
{
|
||||
rbtree_cb_unlock_relock();
|
||||
asm volatile ("");
|
||||
}
|
||||
|
||||
static bool less__bad_subprog_unlock(struct bpf_rb_node *a, const struct bpf_rb_node *b)
|
||||
{
|
||||
struct node_data *node_a;
|
||||
struct node_data *node_b;
|
||||
|
||||
node_a = container_of(a, struct node_data, node);
|
||||
node_b = container_of(b, struct node_data, node);
|
||||
rbtree_cb_nested_unlock();
|
||||
|
||||
return node_a->key < node_b->key;
|
||||
}
|
||||
|
||||
static __noinline void rbtree_cb_noop(void)
|
||||
{
|
||||
asm volatile ("");
|
||||
}
|
||||
|
||||
static bool less__subprog_allowed(struct bpf_rb_node *a, const struct bpf_rb_node *b)
|
||||
{
|
||||
struct node_data *node_a;
|
||||
struct node_data *node_b;
|
||||
|
||||
node_a = container_of(a, struct node_data, node);
|
||||
node_b = container_of(b, struct node_data, node);
|
||||
rbtree_cb_noop();
|
||||
|
||||
return node_a->key < node_b->key;
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
long add_with_cb(bool (cb)(struct bpf_rb_node *a, const struct bpf_rb_node *b))
|
||||
{
|
||||
|
|
@ -330,4 +371,18 @@ long rbtree_api_add_bad_cb_res_spin_unlock(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("can't spin_{lock,unlock} in rbtree cb")
|
||||
long rbtree_api_add_bad_cb_subprog_unlock(void *ctx)
|
||||
{
|
||||
return add_with_cb(less__bad_subprog_unlock);
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
__success
|
||||
long rbtree_api_add_cb_subprog_allowed(void *ctx)
|
||||
{
|
||||
return add_with_cb(less__subprog_allowed);
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
|
|
|||
|
|
@ -108,6 +108,30 @@ int timer_sys_close_prog(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int timer_btf_find_cb(void *map, int *key, struct bpf_timer *timer)
|
||||
{
|
||||
char name[] = "task_struct";
|
||||
|
||||
bpf_btf_find_by_name_kind(name, sizeof(name), BTF_KIND_STRUCT, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__failure __msg("sleepable helper bpf_btf_find_by_name_kind#{{[0-9]+}} in non-sleepable prog")
|
||||
int timer_btf_find_prog(void *ctx)
|
||||
{
|
||||
struct timer_elem *val;
|
||||
int key = 0;
|
||||
|
||||
val = bpf_map_lookup_elem(&timer_map, &key);
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
bpf_timer_init(&val->t, &timer_map, 0);
|
||||
bpf_timer_set_callback(&val->t, timer_btf_find_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success
|
||||
int syscall_sys_bpf_prog(void *ctx)
|
||||
|
|
@ -126,6 +150,16 @@ int syscall_sys_close_prog(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success
|
||||
int syscall_btf_find_prog(void *ctx)
|
||||
{
|
||||
char name[] = "task_struct";
|
||||
|
||||
bpf_btf_find_by_name_kind(name, sizeof(name), BTF_KIND_STRUCT, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Workqueue tests */
|
||||
|
||||
struct wq_elem {
|
||||
|
|
|
|||
|
|
@ -194,6 +194,102 @@ __naked void ld_ind_subprog_both_paths_safe(void)
|
|||
::: __clobber_all);
|
||||
}
|
||||
|
||||
__naked __noinline __used
|
||||
static int ld_abs_callback(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r6 = *(u64 *)(r2 + 0);"
|
||||
".8byte %[ld_abs];"
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
:
|
||||
: __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0))
|
||||
: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("ld_abs: reject in callback")
|
||||
__failure __msg("cannot use BPF_LD_[ABS|IND] within callback")
|
||||
int ld_abs_callback_reject(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_loop(1, ld_abs_callback, &skb, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__naked __noinline __used
|
||||
static int ld_ind_callback_subprog(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r6 = r1;"
|
||||
"r7 = 0;"
|
||||
".8byte %[ld_ind];"
|
||||
"r0 = 0;"
|
||||
"exit;"
|
||||
:
|
||||
: __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0))
|
||||
: __clobber_all);
|
||||
}
|
||||
|
||||
__naked __noinline __used
|
||||
static int ld_ind_callback(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r1 = *(u64 *)(r2 + 0);"
|
||||
"call ld_ind_callback_subprog;"
|
||||
"exit;"
|
||||
::: __clobber_all);
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("ld_ind: reject in callback subprog")
|
||||
__failure __msg("cannot use BPF_LD_[ABS|IND] within callback")
|
||||
int ld_ind_callback_subprog_reject(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_loop(1, ld_ind_callback, &skb, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __noinline int ld_ind_global_static(struct __sk_buff *skb)
|
||||
{
|
||||
asm volatile (
|
||||
"r6 = %[skb];"
|
||||
"r7 = 0;"
|
||||
".8byte %[ld_ind];"
|
||||
:
|
||||
: [skb] "r"(skb),
|
||||
__imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0))
|
||||
: __clobber_common, "r6", "r7");
|
||||
return skb->mark;
|
||||
}
|
||||
|
||||
__noinline int ld_ind_global(struct __sk_buff *skb)
|
||||
{
|
||||
return ld_ind_global_static(skb);
|
||||
}
|
||||
|
||||
static int ld_ind_global_callback(__u32 index, struct __sk_buff **ctx)
|
||||
{
|
||||
ld_ind_global(*ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("ld_ind: reject in callback global subprog")
|
||||
__failure __msg("cannot use BPF_LD_[ABS|IND] within callback")
|
||||
int ld_ind_global_callback_reject(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_loop(1, ld_ind_global_callback, &skb, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("socket")
|
||||
__description("ld_ind: allow in non-callback global subprog")
|
||||
__success
|
||||
int ld_ind_global_subprog_ok(struct __sk_buff *skb)
|
||||
{
|
||||
return ld_ind_global(skb);
|
||||
}
|
||||
|
||||
/*
|
||||
* ld_{abs,ind} in subprogs require scalar (int) return type in BTF.
|
||||
* A test with void return must be rejected.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user