On Tue, Oct 8, 2024 at 4:49 AM Puranjay Mohan <puranjay@xxxxxxxxxx> wrote: > > Implement bpf_send_signal_task 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/bpf/helpers.c | 1 + > kernel/trace/bpf_trace.c | 52 +++++++++++++++++++++++++++++++++------- > 2 files changed, 45 insertions(+), 8 deletions(-) > > diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c > index 4053f279ed4cc..2fd3feefb9d94 100644 > --- a/kernel/bpf/helpers.c > +++ b/kernel/bpf/helpers.c > @@ -3035,6 +3035,7 @@ BTF_ID_FLAGS(func, bpf_task_get_cgroup1, KF_ACQUIRE | KF_RCU | KF_RET_NULL) > #endif > BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL) > BTF_ID_FLAGS(func, bpf_throw) > +BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS) > BTF_KFUNCS_END(generic_btf_ids) > > static const struct btf_kfunc_id_set generic_kfunc_set = { > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > index a582cd25ca876..d9662e84510d3 100644 > --- a/kernel/trace/bpf_trace.c > +++ b/kernel/trace/bpf_trace.c > @@ -802,6 +802,8 @@ struct send_signal_irq_work { > struct task_struct *task; > u32 sig; > enum pid_type type; > + bool has_siginfo; > + struct kernel_siginfo info; > }; > > static DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work); > @@ -809,27 +811,46 @@ static DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work); > static void do_bpf_send_signal(struct irq_work *entry) > { > struct send_signal_irq_work *work; > + struct kernel_siginfo *siginfo; > > work = container_of(entry, struct send_signal_irq_work, irq_work); > - group_send_sig_info(work->sig, SEND_SIG_PRIV, work->task, work->type); > + siginfo = work->has_siginfo ? &work->info : SEND_SIG_PRIV; > + > + group_send_sig_info(work->sig, siginfo, work->task, work->type); > put_task_struct(work->task); > } > > -static int bpf_send_signal_common(u32 sig, enum pid_type type) > +static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struct *task, u64 value) > { > struct send_signal_irq_work *work = NULL; > + struct kernel_siginfo info; > + struct kernel_siginfo *siginfo; > + > + if (!task) { > + task = current; > + siginfo = SEND_SIG_PRIV; > + } else { > + 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_ptr = (void *)(unsigned long)value; > + 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. > */ > - if (unlikely(current->flags & (PF_KTHREAD | PF_EXITING))) > + 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(current))) > + if (unlikely(is_global_init(task))) > return -EPERM; > > if (irqs_disabled()) { > @@ -847,19 +868,21 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type) > * to the irq_work. The current task may change when queued > * irq works get executed. > */ > - work->task = get_task_struct(current); > + work->task = get_task_struct(task); > + work->has_siginfo = siginfo == &info; > + copy_siginfo(&work->info, &info); we shouldn't copy_siginfo() if !work->has_siginfo, no? other than that, lgtm Acked-by: Andrii Nakryiko <andrii@xxxxxxxxxx> > work->sig = sig; > work->type = type; > irq_work_queue(&work->irq_work); > return 0; > } > > - return group_send_sig_info(sig, SEND_SIG_PRIV, current, type); > + return group_send_sig_info(sig, siginfo, task, type); > } > > BPF_CALL_1(bpf_send_signal, u32, sig) > { > - return bpf_send_signal_common(sig, PIDTYPE_TGID); > + return bpf_send_signal_common(sig, PIDTYPE_TGID, NULL, 0); > } > > static const struct bpf_func_proto bpf_send_signal_proto = { > @@ -871,7 +894,7 @@ static const struct bpf_func_proto bpf_send_signal_proto = { > > BPF_CALL_1(bpf_send_signal_thread, u32, sig) > { > - return bpf_send_signal_common(sig, PIDTYPE_PID); > + return bpf_send_signal_common(sig, PIDTYPE_PID, NULL, 0); > } > > static const struct bpf_func_proto bpf_send_signal_thread_proto = { > @@ -3484,3 +3507,16 @@ 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_task(struct task_struct *task, int sig, enum pid_type type, > + u64 value) > +{ > + if (type != PIDTYPE_PID && type != PIDTYPE_TGID) > + return -EINVAL; > + > + return bpf_send_signal_common(sig, type, task, value); > +} > + > +__bpf_kfunc_end_defs(); > -- > 2.40.1 >