diff options
author | Alexei Starovoitov <ast@plumgrid.com> | 2015-03-25 15:49:20 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-04-02 07:25:49 -0400 |
commit | 2541517c32be2531e0da59dfd7efc1ce844644f5 (patch) | |
tree | a69f215a0bbc2f5db1a5d7aff83a465940e40e01 /include | |
parent | 72cbbc8994242b5b43753738c01bf07bf29cb70d (diff) |
tracing, perf: Implement BPF programs attached to kprobes
BPF programs, attached to kprobes, provide a safe way to execute
user-defined BPF byte-code programs without being able to crash or
hang the kernel in any way. The BPF engine makes sure that such
programs have a finite execution time and that they cannot break
out of their sandbox.
The user interface is to attach to a kprobe via the perf syscall:
struct perf_event_attr attr = {
.type = PERF_TYPE_TRACEPOINT,
.config = event_id,
...
};
event_fd = perf_event_open(&attr,...);
ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
'prog_fd' is a file descriptor associated with BPF program
previously loaded.
'event_id' is an ID of the kprobe created.
Closing 'event_fd':
close(event_fd);
... automatically detaches BPF program from it.
BPF programs can call in-kernel helper functions to:
- lookup/update/delete elements in maps
- probe_read - wraper of probe_kernel_read() used to access any
kernel data structures
BPF programs receive 'struct pt_regs *' as an input ('struct pt_regs' is
architecture dependent) and return 0 to ignore the event and 1 to store
kprobe event into the ring buffer.
Note, kprobes are a fundamentally _not_ a stable kernel ABI,
so BPF programs attached to kprobes must be recompiled for
every kernel version and user must supply correct LINUX_VERSION_CODE
in attr.kern_version during bpf_prog_load() call.
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1427312966-8434-4-git-send-email-ast@plumgrid.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/ftrace_event.h | 11 | ||||
-rw-r--r-- | include/uapi/linux/bpf.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/perf_event.h | 1 |
3 files changed, 15 insertions, 0 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 77325e1a1816..0aa535bc9f05 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -13,6 +13,7 @@ struct trace_array; | |||
13 | struct trace_buffer; | 13 | struct trace_buffer; |
14 | struct tracer; | 14 | struct tracer; |
15 | struct dentry; | 15 | struct dentry; |
16 | struct bpf_prog; | ||
16 | 17 | ||
17 | struct trace_print_flags { | 18 | struct trace_print_flags { |
18 | unsigned long mask; | 19 | unsigned long mask; |
@@ -306,6 +307,7 @@ struct ftrace_event_call { | |||
306 | #ifdef CONFIG_PERF_EVENTS | 307 | #ifdef CONFIG_PERF_EVENTS |
307 | int perf_refcount; | 308 | int perf_refcount; |
308 | struct hlist_head __percpu *perf_events; | 309 | struct hlist_head __percpu *perf_events; |
310 | struct bpf_prog *prog; | ||
309 | 311 | ||
310 | int (*perf_perm)(struct ftrace_event_call *, | 312 | int (*perf_perm)(struct ftrace_event_call *, |
311 | struct perf_event *); | 313 | struct perf_event *); |
@@ -551,6 +553,15 @@ event_trigger_unlock_commit_regs(struct ftrace_event_file *file, | |||
551 | event_triggers_post_call(file, tt); | 553 | event_triggers_post_call(file, tt); |
552 | } | 554 | } |
553 | 555 | ||
556 | #ifdef CONFIG_BPF_SYSCALL | ||
557 | unsigned int trace_call_bpf(struct bpf_prog *prog, void *ctx); | ||
558 | #else | ||
559 | static inline unsigned int trace_call_bpf(struct bpf_prog *prog, void *ctx) | ||
560 | { | ||
561 | return 1; | ||
562 | } | ||
563 | #endif | ||
564 | |||
554 | enum { | 565 | enum { |
555 | FILTER_OTHER = 0, | 566 | FILTER_OTHER = 0, |
556 | FILTER_STATIC_STRING, | 567 | FILTER_STATIC_STRING, |
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 45da7ec7d274..b2948feeb70b 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
@@ -118,6 +118,7 @@ enum bpf_map_type { | |||
118 | enum bpf_prog_type { | 118 | enum bpf_prog_type { |
119 | BPF_PROG_TYPE_UNSPEC, | 119 | BPF_PROG_TYPE_UNSPEC, |
120 | BPF_PROG_TYPE_SOCKET_FILTER, | 120 | BPF_PROG_TYPE_SOCKET_FILTER, |
121 | BPF_PROG_TYPE_KPROBE, | ||
121 | }; | 122 | }; |
122 | 123 | ||
123 | /* flags for BPF_MAP_UPDATE_ELEM command */ | 124 | /* flags for BPF_MAP_UPDATE_ELEM command */ |
@@ -151,6 +152,7 @@ union bpf_attr { | |||
151 | __u32 log_level; /* verbosity level of verifier */ | 152 | __u32 log_level; /* verbosity level of verifier */ |
152 | __u32 log_size; /* size of user buffer */ | 153 | __u32 log_size; /* size of user buffer */ |
153 | __aligned_u64 log_buf; /* user supplied buffer */ | 154 | __aligned_u64 log_buf; /* user supplied buffer */ |
155 | __u32 kern_version; /* checked when prog_type=kprobe */ | ||
154 | }; | 156 | }; |
155 | } __attribute__((aligned(8))); | 157 | } __attribute__((aligned(8))); |
156 | 158 | ||
@@ -162,6 +164,7 @@ enum bpf_func_id { | |||
162 | BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */ | 164 | BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */ |
163 | BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */ | 165 | BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */ |
164 | BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */ | 166 | BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */ |
167 | BPF_FUNC_probe_read, /* int bpf_probe_read(void *dst, int size, void *src) */ | ||
165 | __BPF_FUNC_MAX_ID, | 168 | __BPF_FUNC_MAX_ID, |
166 | }; | 169 | }; |
167 | 170 | ||
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 3bb40ddadbe5..91803e54ee73 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h | |||
@@ -381,6 +381,7 @@ struct perf_event_attr { | |||
381 | #define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) | 381 | #define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) |
382 | #define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) | 382 | #define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) |
383 | #define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) | 383 | #define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) |
384 | #define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) | ||
384 | 385 | ||
385 | enum perf_event_ioc_flags { | 386 | enum perf_event_ioc_flags { |
386 | PERF_IOC_FLAG_GROUP = 1U << 0, | 387 | PERF_IOC_FLAG_GROUP = 1U << 0, |