mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 04:06:26 +00:00
bpf: Implement bpf_send_signal_task() kfunc
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@kernel.org> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20241016084136.10305-2-puranjay@kernel.org
This commit is contained in:
parent
8ca77b8f62
commit
6280cf718d
@ -3055,6 +3055,7 @@ BTF_ID_FLAGS(func, bpf_task_get_cgroup1, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
|
||||
BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL)
|
||||
BTF_ID_FLAGS(func, bpf_task_from_vpid, 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 = {
|
||||
|
@ -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,22 @@ 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;
|
||||
if (work->has_siginfo)
|
||||
copy_siginfo(&work->info, &info);
|
||||
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 +895,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 +3508,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();
|
||||
|
Loading…
Reference in New Issue
Block a user