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? > > +{ > > + 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 > >