mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01: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_pid, KF_ACQUIRE | KF_RET_NULL)
|
||||||
BTF_ID_FLAGS(func, bpf_task_from_vpid, 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_throw)
|
||||||
|
BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS)
|
||||||
BTF_KFUNCS_END(generic_btf_ids)
|
BTF_KFUNCS_END(generic_btf_ids)
|
||||||
|
|
||||||
static const struct btf_kfunc_id_set generic_kfunc_set = {
|
static const struct btf_kfunc_id_set generic_kfunc_set = {
|
||||||
|
|
|
||||||
|
|
@ -802,6 +802,8 @@ struct send_signal_irq_work {
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
u32 sig;
|
u32 sig;
|
||||||
enum pid_type type;
|
enum pid_type type;
|
||||||
|
bool has_siginfo;
|
||||||
|
struct kernel_siginfo info;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work);
|
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)
|
static void do_bpf_send_signal(struct irq_work *entry)
|
||||||
{
|
{
|
||||||
struct send_signal_irq_work *work;
|
struct send_signal_irq_work *work;
|
||||||
|
struct kernel_siginfo *siginfo;
|
||||||
|
|
||||||
work = container_of(entry, struct send_signal_irq_work, irq_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);
|
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);
|
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 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
|
/* Similar to bpf_probe_write_user, task needs to be
|
||||||
* in a sound condition and kernel memory access be
|
* in a sound condition and kernel memory access be
|
||||||
* permitted in order to send signal to the current
|
* permitted in order to send signal to the current
|
||||||
* task.
|
* task.
|
||||||
*/
|
*/
|
||||||
if (unlikely(current->flags & (PF_KTHREAD | PF_EXITING)))
|
if (unlikely(task->flags & (PF_KTHREAD | PF_EXITING)))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (unlikely(!nmi_uaccess_okay()))
|
if (unlikely(!nmi_uaccess_okay()))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
/* Task should not be pid=1 to avoid kernel panic. */
|
/* Task should not be pid=1 to avoid kernel panic. */
|
||||||
if (unlikely(is_global_init(current)))
|
if (unlikely(is_global_init(task)))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (irqs_disabled()) {
|
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
|
* to the irq_work. The current task may change when queued
|
||||||
* irq works get executed.
|
* 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->sig = sig;
|
||||||
work->type = type;
|
work->type = type;
|
||||||
irq_work_queue(&work->irq_work);
|
irq_work_queue(&work->irq_work);
|
||||||
return 0;
|
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)
|
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 = {
|
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)
|
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 = {
|
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);
|
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