bpf: allow sleepable uprobe programs to attach
authorDelyan Kratunov <delyank@fb.com>
Tue, 14 Jun 2022 23:10:43 +0000 (23:10 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 17 Jun 2022 02:27:29 +0000 (19:27 -0700)
uprobe and kprobe programs have the same program type, KPROBE, which is
currently not allowed to load sleepable programs.

To avoid adding a new UPROBE type, instead allow sleepable KPROBE
programs to load and defer the is-it-actually-a-uprobe-program check
to attachment time, where there's already validation of the
corresponding perf_event.

A corollary of this patch is that you can now load a sleepable kprobe
program but cannot attach it.

Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Delyan Kratunov <delyank@fb.com>
Link: https://lore.kernel.org/r/fcd44a7cd204f372f6bb03ef794e829adeaef299.1655248076.git.delyank@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c
kernel/events/core.c

index 2d28726..eadc23a 100644 (file)
@@ -14829,8 +14829,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
        }
 
        if (prog->aux->sleepable && prog->type != BPF_PROG_TYPE_TRACING &&
-           prog->type != BPF_PROG_TYPE_LSM) {
-               verbose(env, "Only fentry/fexit/fmod_ret and lsm programs can be sleepable\n");
+           prog->type != BPF_PROG_TYPE_LSM && prog->type != BPF_PROG_TYPE_KPROBE) {
+               verbose(env, "Only fentry/fexit/fmod_ret, lsm, and kprobe/uprobe programs can be sleepable\n");
                return -EINVAL;
        }
 
index 950b25c..deee681 100644 (file)
@@ -10069,26 +10069,30 @@ static inline bool perf_event_is_tracing(struct perf_event *event)
 int perf_event_set_bpf_prog(struct perf_event *event, struct bpf_prog *prog,
                            u64 bpf_cookie)
 {
-       bool is_kprobe, is_tracepoint, is_syscall_tp;
+       bool is_kprobe, is_uprobe, is_tracepoint, is_syscall_tp;
 
        if (!perf_event_is_tracing(event))
                return perf_event_set_bpf_handler(event, prog, bpf_cookie);
 
-       is_kprobe = event->tp_event->flags & TRACE_EVENT_FL_UKPROBE;
+       is_kprobe = event->tp_event->flags & TRACE_EVENT_FL_KPROBE;
+       is_uprobe = event->tp_event->flags & TRACE_EVENT_FL_UPROBE;
        is_tracepoint = event->tp_event->flags & TRACE_EVENT_FL_TRACEPOINT;
        is_syscall_tp = is_syscall_trace_event(event->tp_event);
-       if (!is_kprobe && !is_tracepoint && !is_syscall_tp)
+       if (!is_kprobe && !is_uprobe && !is_tracepoint && !is_syscall_tp)
                /* bpf programs can only be attached to u/kprobe or tracepoint */
                return -EINVAL;
 
-       if ((is_kprobe && prog->type != BPF_PROG_TYPE_KPROBE) ||
+       if (((is_kprobe || is_uprobe) && prog->type != BPF_PROG_TYPE_KPROBE) ||
            (is_tracepoint && prog->type != BPF_PROG_TYPE_TRACEPOINT) ||
            (is_syscall_tp && prog->type != BPF_PROG_TYPE_TRACEPOINT))
                return -EINVAL;
 
+       if (prog->type == BPF_PROG_TYPE_KPROBE && prog->aux->sleepable && !is_uprobe)
+               /* only uprobe programs are allowed to be sleepable */
+               return -EINVAL;
+
        /* Kprobe override only works for kprobes, not uprobes. */
-       if (prog->kprobe_override &&
-           !(event->tp_event->flags & TRACE_EVENT_FL_KPROBE))
+       if (prog->kprobe_override && !is_kprobe)
                return -EINVAL;
 
        if (is_tracepoint || is_syscall_tp) {