summaryrefslogtreecommitdiff
path: root/kernel/trace/bpf_trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/bpf_trace.c')
-rw-r--r--kernel/trace/bpf_trace.c62
1 files changed, 43 insertions, 19 deletions
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 29260951aa87..2aec56d7f3d3 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -823,6 +823,7 @@ const struct bpf_func_proto bpf_task_pt_regs_proto = {
struct send_signal_irq_work {
struct irq_work irq_work;
+ /* The claim: NULL marks the slot free for the next caller. */
struct task_struct *task;
u32 sig;
enum pid_type type;
@@ -842,6 +843,8 @@ static void do_bpf_send_signal(struct irq_work *entry)
group_send_sig_info(work->sig, siginfo, work->task, work->type);
put_task_struct(work->task);
+ /* Release once the fields are consumed. */
+ smp_store_release(&work->task, NULL);
}
static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struct *task, u64 value)
@@ -864,15 +867,12 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struc
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.
+ /*
+ * Similar to bpf_probe_write_user, task needs to be
+ * in a sound condition.
*/
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(task)))
return -EPERM;
@@ -885,14 +885,14 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struc
return -EINVAL;
work = this_cpu_ptr(&send_signal_work);
- if (irq_work_is_busy(&work->irq_work))
+ if (cmpxchg(&work->task, NULL, task))
return -EBUSY;
/* Add the current task, which is the target of sending signal,
* to the irq_work. The current task may change when queued
* irq works get executed.
*/
- work->task = get_task_struct(task);
+ get_task_struct(task);
work->has_siginfo = siginfo == &info;
if (work->has_siginfo)
copy_siginfo(&work->info, &info);
@@ -974,6 +974,10 @@ BTF_ID(func, vfs_getattr)
BTF_ID(func, filp_close)
BTF_SET_END(btf_allowlist_d_path)
+BTF_SET_START(btf_allowlist_d_path_fentry)
+BTF_ID(func, filp_close_sync)
+BTF_SET_END(btf_allowlist_d_path_fentry)
+
static bool bpf_d_path_allowed(const struct bpf_prog *prog)
{
if (prog->type == BPF_PROG_TYPE_TRACING &&
@@ -983,8 +987,15 @@ static bool bpf_d_path_allowed(const struct bpf_prog *prog)
if (prog->type == BPF_PROG_TYPE_LSM)
return bpf_lsm_is_sleepable_hook(prog->aux->attach_btf_id);
- return btf_id_set_contains(&btf_allowlist_d_path,
- prog->aux->attach_btf_id);
+ if (btf_id_set_contains(&btf_allowlist_d_path,
+ prog->aux->attach_btf_id))
+ return true;
+
+ if (btf_id_set_contains(&btf_allowlist_d_path_fentry,
+ prog->aux->attach_btf_id))
+ return prog->expected_attach_type == BPF_TRACE_FENTRY;
+
+ return false;
}
BTF_ID_LIST_SINGLE(bpf_d_path_btf_ids, struct, path)
@@ -995,7 +1006,7 @@ static const struct bpf_func_proto bpf_d_path_proto = {
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_BTF_ID,
.arg1_btf_id = &bpf_d_path_btf_ids[0],
- .arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
+ .arg2_type = ARG_PTR_TO_MEM | MEM_UNINIT | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
.allowed = bpf_d_path_allowed,
};
@@ -1052,7 +1063,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {
.func = bpf_snprintf_btf,
.gpl_only = false,
.ret_type = RET_INTEGER,
- .arg1_type = ARG_PTR_TO_MEM | MEM_WRITE,
+ .arg1_type = ARG_PTR_TO_MEM | MEM_UNINIT | MEM_WRITE,
.arg2_type = ARG_MEM_SIZE,
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
.arg4_type = ARG_MEM_SIZE,
@@ -1565,7 +1576,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = {
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
- .arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_WRITE,
+ .arg2_type = ARG_PTR_TO_MEM_OR_NULL | MEM_UNINIT | MEM_WRITE,
.arg3_type = ARG_MEM_SIZE_OR_ZERO,
.arg4_type = ARG_ANYTHING,
};
@@ -2206,6 +2217,7 @@ int bpf_probe_unregister(struct bpf_raw_event_map *btp, struct bpf_raw_tp_link *
return tracepoint_probe_unregister(btp->tp, (void *)btp->bpf_func, link);
}
+/* On success the caller releases *buf with kfree_const() */
int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
u32 *fd_type, const char **buf,
u64 *probe_offset, u64 *probe_addr,
@@ -2215,6 +2227,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
struct bpf_prog *prog;
int flags, err = 0;
+ /*
+ * The list of dynamic events is walked, and a probe which has siblings
+ * can be deleted, with its strings, while its event is in use.
+ */
+ guard(mutex)(&event_mutex);
+
prog = event->prog;
if (!prog)
return -ENOENT;
@@ -2255,6 +2273,12 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
#endif
}
+ if (!err && *buf) {
+ *buf = kstrdup_const(*buf, GFP_KERNEL);
+ if (!*buf)
+ err = -ENOMEM;
+ }
+
return err;
}
@@ -2388,7 +2412,7 @@ static int copy_user_syms(struct user_syms *us, unsigned long __user *usyms, u32
goto error;
for (p = buf, i = 0; i < cnt; i++) {
- if (__get_user(usymbol, usyms + i)) {
+ if (get_user(usymbol, usyms + i)) {
err = -EFAULT;
goto error;
}
@@ -3295,8 +3319,8 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
/*
* All uoffsets/uref_ctr_offsets/ucookies arrays have the same value
- * size, we need to check their address range is safe for __get_user
- * calls.
+ * size. Check their address ranges up front, so that a bad pointer
+ * fails before anything is looked up or allocated.
*/
size = sizeof(*uoffsets) * cnt;
if (!access_ok(uoffsets, size) || !access_ok(uref_ctr_offsets, size) ||
@@ -3331,7 +3355,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
goto error_free;
for (i = 0; i < cnt; i++) {
- if (__get_user(uprobes[i].offset, uoffsets + i)) {
+ if (get_user(uprobes[i].offset, uoffsets + i)) {
err = -EFAULT;
goto error_free;
}
@@ -3339,11 +3363,11 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
err = -EINVAL;
goto error_free;
}
- if (uref_ctr_offsets && __get_user(uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) {
+ if (uref_ctr_offsets && get_user(uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) {
err = -EFAULT;
goto error_free;
}
- if (ucookies && __get_user(uprobes[i].cookie, ucookies + i)) {
+ if (ucookies && get_user(uprobes[i].cookie, ucookies + i)) {
err = -EFAULT;
goto error_free;
}