Commit 8482941f authored by Yonghong Song's avatar Yonghong Song Committed by Alexei Starovoitov

bpf: Add bpf_send_signal_thread() helper

Commit 8b401f9e ("bpf: implement bpf_send_signal() helper")
added helper bpf_send_signal() which permits bpf program to
send a signal to the current process. The signal may be
delivered to any threads in the process.

We found a use case where sending the signal to the current
thread is more preferable.
  - A bpf program will collect the stack trace and then
    send signal to the user application.
  - The user application will add some thread specific
    information to the just collected stack trace for
    later analysis.

If bpf_send_signal() is used, user application will need
to check whether the thread receiving the signal matches
the thread collecting the stack by checking thread id.
If not, it will need to send signal to another thread
through pthread_kill().

This patch proposed a new helper bpf_send_signal_thread(),
which sends the signal to the thread corresponding to
the current kernel task. This way, user space is guaranteed that
bpf_program execution context and user space signal handling
context are the same thread.
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200115035002.602336-1-yhs@fb.com
parent d3a56931
...@@ -2714,7 +2714,8 @@ union bpf_attr { ...@@ -2714,7 +2714,8 @@ union bpf_attr {
* *
* int bpf_send_signal(u32 sig) * int bpf_send_signal(u32 sig)
* Description * Description
* Send signal *sig* to the current task. * Send signal *sig* to the process of the current task.
* The signal may be delivered to any of this process's threads.
* Return * Return
* 0 on success or successfully queued. * 0 on success or successfully queued.
* *
...@@ -2850,6 +2851,19 @@ union bpf_attr { ...@@ -2850,6 +2851,19 @@ union bpf_attr {
* Return * Return
* 0 on success, or a negative error in case of failure. * 0 on success, or a negative error in case of failure.
* *
* int bpf_send_signal_thread(u32 sig)
* Description
* Send signal *sig* to the thread corresponding to the current task.
* Return
* 0 on success or successfully queued.
*
* **-EBUSY** if work queue under nmi is full.
*
* **-EINVAL** if *sig* is invalid.
*
* **-EPERM** if no permission to send the *sig*.
*
* **-EAGAIN** if bpf program can try again.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -2968,7 +2982,8 @@ union bpf_attr { ...@@ -2968,7 +2982,8 @@ union bpf_attr {
FN(probe_read_kernel), \ FN(probe_read_kernel), \
FN(probe_read_user_str), \ FN(probe_read_user_str), \
FN(probe_read_kernel_str), \ FN(probe_read_kernel_str), \
FN(tcp_send_ack), FN(tcp_send_ack), \
FN(send_signal_thread),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
......
...@@ -703,6 +703,7 @@ struct send_signal_irq_work { ...@@ -703,6 +703,7 @@ struct send_signal_irq_work {
struct irq_work irq_work; struct irq_work irq_work;
struct task_struct *task; struct task_struct *task;
u32 sig; u32 sig;
enum pid_type type;
}; };
static DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work); static DEFINE_PER_CPU(struct send_signal_irq_work, send_signal_work);
...@@ -712,10 +713,10 @@ static void do_bpf_send_signal(struct irq_work *entry) ...@@ -712,10 +713,10 @@ static void do_bpf_send_signal(struct irq_work *entry)
struct send_signal_irq_work *work; struct send_signal_irq_work *work;
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, PIDTYPE_TGID); group_send_sig_info(work->sig, SEND_SIG_PRIV, work->task, work->type);
} }
BPF_CALL_1(bpf_send_signal, u32, sig) static int bpf_send_signal_common(u32 sig, enum pid_type type)
{ {
struct send_signal_irq_work *work = NULL; struct send_signal_irq_work *work = NULL;
...@@ -748,11 +749,17 @@ BPF_CALL_1(bpf_send_signal, u32, sig) ...@@ -748,11 +749,17 @@ BPF_CALL_1(bpf_send_signal, u32, sig)
*/ */
work->task = current; work->task = current;
work->sig = sig; work->sig = sig;
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, PIDTYPE_TGID); return group_send_sig_info(sig, SEND_SIG_PRIV, current, type);
}
BPF_CALL_1(bpf_send_signal, u32, sig)
{
return bpf_send_signal_common(sig, PIDTYPE_TGID);
} }
static const struct bpf_func_proto bpf_send_signal_proto = { static const struct bpf_func_proto bpf_send_signal_proto = {
...@@ -762,6 +769,18 @@ static const struct bpf_func_proto bpf_send_signal_proto = { ...@@ -762,6 +769,18 @@ static const struct bpf_func_proto bpf_send_signal_proto = {
.arg1_type = ARG_ANYTHING, .arg1_type = ARG_ANYTHING,
}; };
BPF_CALL_1(bpf_send_signal_thread, u32, sig)
{
return bpf_send_signal_common(sig, PIDTYPE_PID);
}
static const struct bpf_func_proto bpf_send_signal_thread_proto = {
.func = bpf_send_signal_thread,
.gpl_only = false,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
};
static const struct bpf_func_proto * static const struct bpf_func_proto *
tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{ {
...@@ -822,6 +841,8 @@ tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) ...@@ -822,6 +841,8 @@ tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
#endif #endif
case BPF_FUNC_send_signal: case BPF_FUNC_send_signal:
return &bpf_send_signal_proto; return &bpf_send_signal_proto;
case BPF_FUNC_send_signal_thread:
return &bpf_send_signal_thread_proto;
default: default:
return NULL; return NULL;
} }
......
...@@ -2714,7 +2714,8 @@ union bpf_attr { ...@@ -2714,7 +2714,8 @@ union bpf_attr {
* *
* int bpf_send_signal(u32 sig) * int bpf_send_signal(u32 sig)
* Description * Description
* Send signal *sig* to the current task. * Send signal *sig* to the process of the current task.
* The signal may be delivered to any of this process's threads.
* Return * Return
* 0 on success or successfully queued. * 0 on success or successfully queued.
* *
...@@ -2850,6 +2851,19 @@ union bpf_attr { ...@@ -2850,6 +2851,19 @@ union bpf_attr {
* Return * Return
* 0 on success, or a negative error in case of failure. * 0 on success, or a negative error in case of failure.
* *
* int bpf_send_signal_thread(u32 sig)
* Description
* Send signal *sig* to the thread corresponding to the current task.
* Return
* 0 on success or successfully queued.
*
* **-EBUSY** if work queue under nmi is full.
*
* **-EINVAL** if *sig* is invalid.
*
* **-EPERM** if no permission to send the *sig*.
*
* **-EAGAIN** if bpf program can try again.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
...@@ -2968,7 +2982,8 @@ union bpf_attr { ...@@ -2968,7 +2982,8 @@ union bpf_attr {
FN(probe_read_kernel), \ FN(probe_read_kernel), \
FN(probe_read_user_str), \ FN(probe_read_user_str), \
FN(probe_read_kernel_str), \ FN(probe_read_kernel_str), \
FN(tcp_send_ack), FN(tcp_send_ack), \
FN(send_signal_thread),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment