Commit 6280cf71 authored by Puranjay Mohan's avatar Puranjay Mohan Committed by Andrii Nakryiko
Browse files

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: default avatarPuranjay Mohan <puranjay@kernel.org>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20241016084136.10305-2-puranjay@kernel.org
parent 8ca77b8f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 = {
+45 −8
Original line number Diff line number Diff line
@@ -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();