mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
Merge branch 'misc-bug-fixes-part-1'
Kumar Kartikeya Dwivedi says: ==================== Misc bug fixes - part 1 A set of miscellaneous fixes for bugs reported by Nicholas. These are easy ones and should not require any major discussion, hence batched together. See commit logs and selftests for details. ==================== Link: https://patch.msgid.link/20260903144433.1716731-1-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
e044668419
|
|
@ -6672,6 +6672,10 @@ struct bpf_raw_tp_null_args {
|
|||
static const struct bpf_raw_tp_null_args raw_tp_null_args[] = {
|
||||
/* sched */
|
||||
{ "sched_pi_setprio", 0x10 },
|
||||
/*
|
||||
* do_wait() passes NULL for wait4(-1) and waitid(P_ALL).
|
||||
*/
|
||||
{ "sched_process_wait", 0x1 },
|
||||
/* ... from sched_numa_pair_template event class */
|
||||
{ "sched_stick_numa", 0x100 },
|
||||
{ "sched_swap_numa", 0x100 },
|
||||
|
|
@ -6732,6 +6736,9 @@ static const struct bpf_raw_tp_null_args raw_tp_null_args[] = {
|
|||
{ "rxrpc_resend", 0x10 },
|
||||
{ "rxrpc_tq", 0x10 },
|
||||
{ "rxrpc_client", 0x1 },
|
||||
/* signal */
|
||||
{ "signal_generate", 0x20 },
|
||||
{ "signal_deliver", 0x20 },
|
||||
/* skb */
|
||||
{"kfree_skb", 0x1000},
|
||||
/* sunrpc */
|
||||
|
|
|
|||
|
|
@ -6568,6 +6568,7 @@ EXPORT_SYMBOL_NS(kern_sys_bpf, "BPF_INTERNAL");
|
|||
static const struct bpf_func_proto bpf_sys_bpf_proto = {
|
||||
.func = bpf_sys_bpf,
|
||||
.gpl_only = false,
|
||||
.might_sleep = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_ANYTHING,
|
||||
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
||||
|
|
@ -6593,6 +6594,7 @@ BPF_CALL_1(bpf_sys_close, u32, fd)
|
|||
static const struct bpf_func_proto bpf_sys_close_proto = {
|
||||
.func = bpf_sys_close,
|
||||
.gpl_only = false,
|
||||
.might_sleep = true,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_ANYTHING,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11228,6 +11228,17 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
|
|||
if (env->cur_state->curframe) {
|
||||
struct bpf_verifier_state *branch;
|
||||
|
||||
/*
|
||||
* A taken tail call is modeled as a return from the current
|
||||
* frame. A callback frame cannot be left that way because
|
||||
* prepare_func_exit() would apply its return contract to the
|
||||
* unknown R0 synthesized below. Stack-depth validation rejects
|
||||
* this construct anyway.
|
||||
*/
|
||||
if (cur_func(env)->in_callback_fn) {
|
||||
verbose(env, "cannot tail call within callback\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mark_reg_scratched(env, BPF_REG_0);
|
||||
branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
|
||||
if (IS_ERR(branch))
|
||||
|
|
@ -13230,6 +13241,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
|
|||
{
|
||||
int flags = PROCESS_RES_LOCK;
|
||||
|
||||
if (in_rbtree_lock_required_cb(env)) {
|
||||
verbose(env, "can't res_spin_{lock,unlock} in rbtree cb\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (reg->type != PTR_TO_MAP_VALUE && reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
|
||||
verbose(env, "%s doesn't point to map value or allocated object\n",
|
||||
reg_arg_name(env, argno));
|
||||
|
|
|
|||
|
|
@ -22,3 +22,56 @@ int test_raw_tp_null_sched_pi_setprio_arg_2(void *ctx) {
|
|||
asm volatile("r1 = *(u64 *)(r1 +8); r1 = *(u64 *)(r1 +0);" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Plain raw tracepoint arguments remain scalar values. */
|
||||
SEC("raw_tp/signal_generate")
|
||||
__success
|
||||
int test_raw_tp_signal_generate_info_scalar(void *ctx)
|
||||
{
|
||||
asm volatile("r1 = *(u64 *)(r1 +8); if r1 != 1 goto +0;" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tp_btf programs may inspect the sentinel as a scalar value. */
|
||||
SEC("tp_btf/signal_generate")
|
||||
__success
|
||||
int test_tp_btf_signal_generate_info_scalar(void *ctx)
|
||||
{
|
||||
asm volatile("r1 = *(u64 *)(r1 +8); if r1 != 1 goto +0;" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SEND_SIG_PRIV is non-NULL, so a NULL check cannot make info safe. */
|
||||
SEC("tp_btf/signal_generate")
|
||||
__failure __msg("R1 invalid mem access 'scalar'")
|
||||
int test_tp_btf_signal_generate_info_no_deref(void *ctx)
|
||||
{
|
||||
asm volatile("r1 = *(u64 *)(r1 +8); if r1 == 0 goto +1; "
|
||||
"r1 = *(u32 *)(r1 +0);" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/signal_deliver")
|
||||
__failure __msg("R1 invalid mem access 'scalar'")
|
||||
int test_tp_btf_signal_deliver_info_no_deref(void *ctx)
|
||||
{
|
||||
asm volatile("r1 = *(u64 *)(r1 +8); r1 = *(u32 *)(r1 +0);" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/sched_process_wait")
|
||||
__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'")
|
||||
int test_raw_tp_null_sched_process_wait_arg_1(void *ctx)
|
||||
{
|
||||
asm volatile("r1 = *(u64 *)(r1 +0); r1 = *(u32 *)(r1 +0);" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/sched_process_wait")
|
||||
__success
|
||||
int test_raw_tp_null_sched_process_wait_arg_1_checked(void *ctx)
|
||||
{
|
||||
asm volatile("r1 = *(u64 *)(r1 +0); if r1 == 0 goto +1; "
|
||||
"r1 = *(u32 *)(r1 +0);" ::: __clobber_all);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ struct node_data {
|
|||
private(A) struct bpf_spin_lock glock;
|
||||
private(A) struct bpf_rb_root groot __contains(node_data, node);
|
||||
private(A) struct bpf_rb_root groot2 __contains(node_data, node);
|
||||
private(B) struct bpf_res_spin_lock res_glock;
|
||||
|
||||
static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
|
||||
{
|
||||
|
|
@ -265,6 +266,12 @@ static bool less__bad_fn_call_first_unlock_after(struct bpf_rb_node *a, const st
|
|||
return node_a->key < node_b->key;
|
||||
}
|
||||
|
||||
static bool less__bad_res_spin_unlock(struct bpf_rb_node *a, const struct bpf_rb_node *b)
|
||||
{
|
||||
bpf_res_spin_unlock(&res_glock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
long add_with_cb(bool (cb)(struct bpf_rb_node *a, const struct bpf_rb_node *b))
|
||||
{
|
||||
|
|
@ -301,4 +308,26 @@ long rbtree_api_add_bad_cb_bad_fn_call_first_unlock_after(void *ctx)
|
|||
return add_with_cb(less__bad_fn_call_first_unlock_after);
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
__failure __msg("can't res_spin_{lock,unlock} in rbtree cb")
|
||||
long rbtree_api_add_bad_cb_res_spin_unlock(void *ctx)
|
||||
{
|
||||
struct node_data *n;
|
||||
|
||||
n = bpf_obj_new(typeof(*n));
|
||||
if (!n)
|
||||
return 1;
|
||||
|
||||
bpf_spin_lock(&glock);
|
||||
if (bpf_res_spin_lock(&res_glock)) {
|
||||
bpf_spin_unlock(&glock);
|
||||
bpf_obj_drop(n);
|
||||
return 1;
|
||||
}
|
||||
bpf_rbtree_add(&groot, &n->node, less__bad_res_spin_unlock);
|
||||
bpf_res_spin_unlock(&res_glock);
|
||||
bpf_spin_unlock(&glock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
|
|
|||
|
|
@ -44,6 +44,13 @@ int callback_loop(int index, void **cb_ctx)
|
|||
return ret ? 1 : 0;
|
||||
}
|
||||
|
||||
static __noinline
|
||||
int callback_tail(int index, void **cb_ctx)
|
||||
{
|
||||
bpf_tail_call_static(*cb_ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __noinline
|
||||
int callback_empty(int index, void *data)
|
||||
{
|
||||
|
|
@ -78,4 +85,13 @@ int tailcall_callback_2(struct __sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* callback with a direct tail call is rejected without a verifier bug */
|
||||
SEC("tc")
|
||||
__failure __msg("cannot tail call within callback")
|
||||
int tailcall_callback_3(struct __sk_buff *skb)
|
||||
{
|
||||
bpf_loop(1, callback_tail, &skb, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
|
|
|
|||
|
|
@ -62,6 +62,70 @@ int timer_sleepable_prog(void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int timer_sys_bpf_cb(void *map, int *key, struct bpf_timer *timer)
|
||||
{
|
||||
__u64 attr = 0;
|
||||
|
||||
bpf_sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__failure __msg("sleepable helper bpf_sys_bpf#{{[0-9]+}} in non-sleepable prog")
|
||||
int timer_sys_bpf_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_sys_bpf_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timer_sys_close_cb(void *map, int *key, struct bpf_timer *timer)
|
||||
{
|
||||
bpf_sys_close(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__failure __msg("sleepable helper bpf_sys_close#{{[0-9]+}} in non-sleepable prog")
|
||||
int timer_sys_close_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_sys_close_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success
|
||||
int syscall_sys_bpf_prog(void *ctx)
|
||||
{
|
||||
__u64 attr = 0;
|
||||
|
||||
bpf_sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success
|
||||
int syscall_sys_close_prog(void *ctx)
|
||||
{
|
||||
bpf_sys_close(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Workqueue tests */
|
||||
|
||||
struct wq_elem {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user