Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> writes: > On Mon, Sep 30, 2024 at 2:48 PM Andrii Nakryiko > <andrii.nakryiko@xxxxxxxxx> wrote: >> >> On Thu, Sep 26, 2024 at 4:53 AM Puranjay Mohan <puranjay@xxxxxxxxxx> wrote: >> > >> > Implement bpf_send_signal_remote kfunc that is similar to >> > bpf_send_signal_thread and bpf_send_signal helpers but can be used to >> > send signals to other threads and processes. It also supports sending a >> > cookie with the signal similar to sigqueue(). >> > >> > If the receiving process establishes a handler for the signal using the >> > SA_SIGINFO flag to sigaction(), then it can obtain this cookie via the >> > si_value field of the siginfo_t structure passed as the second argument >> > to the handler. >> > >> > Signed-off-by: Puranjay Mohan <puranjay@xxxxxxxxxx> >> > --- >> > kernel/trace/bpf_trace.c | 78 +++++++++++++++++++++++++++++++++++++++- >> > 1 file changed, 77 insertions(+), 1 deletion(-) >> > >> > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c >> > index a582cd25ca876..51b27db1321fc 100644 >> > --- a/kernel/trace/bpf_trace.c >> > +++ b/kernel/trace/bpf_trace.c >> > @@ -802,6 +802,9 @@ struct send_signal_irq_work { >> > struct task_struct *task; >> > u32 sig; >> > enum pid_type type; >> > + bool is_siginfo; >> > + kernel_siginfo_t info; >> > + int value; >> > }; >> > >> > static DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work); >> > @@ -811,7 +814,11 @@ static void do_bpf_send_signal(struct irq_work *entry) >> > struct send_signal_irq_work *work; >> > >> > work = container_of(entry, struct send_signal_irq_work, irq_work); >> > - group_send_sig_info(work->sig, SEND_SIG_PRIV, work->task, work->type); >> > + if (work->is_siginfo) >> > + group_send_sig_info(work->sig, &work->info, work->task, work->type); >> > + else >> > + group_send_sig_info(work->sig, SEND_SIG_PRIV, work->task, work->type); >> > + >> > put_task_struct(work->task); >> > } >> > >> > @@ -848,6 +855,7 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type) >> > * irq works get executed. >> > */ >> > work->task = get_task_struct(current); >> > + work->is_siginfo = false; >> > work->sig = sig; >> > work->type = type; >> > irq_work_queue(&work->irq_work); >> > @@ -3484,3 +3492,71 @@ static int __init bpf_kprobe_multi_kfuncs_init(void) >> > } >> > >> > late_initcall(bpf_kprobe_multi_kfuncs_init); >> > + >> > +__bpf_kfunc_start_defs(); >> > + >> > +__bpf_kfunc int bpf_send_signal_remote(struct task_struct *task, int sig, enum pid_type type, >> > + int value) > > Bikeshedding here a bit, but would bpf_send_signal_task() be a better > name for something that accepts task_struct? I agree, will use that name in the next version. >> > +{ >> > + struct send_signal_irq_work *work = NULL; >> > + kernel_siginfo_t info; >> > + >> > + if (type != PIDTYPE_PID && type != PIDTYPE_TGID) >> > + return -EINVAL; >> > + 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; >> > + >> > + clear_siginfo(&info); >> > + info.si_signo = sig; >> > + info.si_errno = 0; >> > + info.si_code = SI_KERNEL; >> > + info.si_pid = 0; >> > + info.si_uid = 0; >> > + info.si_value.sival_int = value; >> >> It seems like it could be either int sival_int or `void *sival_ptr`, >> i.e., it's actually a 64-bit value on 64-bit architectures. >> >> Can we allow passing a full u64 here and assign it to sival_ptr (with a cast)? > > Seems like Alexei already suggested that on patch #2, I support the request. > >> >> > + >> > + if (irqs_disabled()) { >> > + /* Do an early check on signal validity. Otherwise, >> > + * the error is lost in deferred irq_work. >> > + */ >> > + if (unlikely(!valid_signal(sig))) >> > + return -EINVAL; >> > + >> > + work = this_cpu_ptr(&send_signal_work); >> > + if (irq_work_is_busy(&work->irq_work)) >> > + return -EBUSY; >> > + >> > + work->task = get_task_struct(task); >> > + work->is_siginfo = true; >> > + work->info = info; >> > + work->sig = sig; >> > + work->type = type; >> > + work->value = value; >> > + irq_work_queue(&work->irq_work); >> > + return 0; >> > + } >> > + >> > + return group_send_sig_info(sig, &info, task, type); >> > +} >> > + >> > +__bpf_kfunc_end_defs(); >> > + >> > +BTF_KFUNCS_START(send_signal_kfunc_ids) >> > +BTF_ID_FLAGS(func, bpf_send_signal_remote, KF_TRUSTED_ARGS) >> > +BTF_KFUNCS_END(send_signal_kfunc_ids) >> > + >> > +static const struct btf_kfunc_id_set bpf_send_signal_kfunc_set = { >> > + .owner = THIS_MODULE, >> > + .set = &send_signal_kfunc_ids, >> > +}; >> > + >> > +static int __init bpf_send_signal_kfuncs_init(void) >> > +{ >> > + return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_send_signal_kfunc_set); >> >> let's allow it for other program types (at least kprobes, tracepoints, >> raw_tp, etc, etc)? Is there any problem just allowing it for any >> program type? >> >> >> > +} >> > + >> > +late_initcall(bpf_send_signal_kfuncs_init); >> > -- >> > 2.40.1 >> >
Attachment:
signature.asc
Description: PGP signature