* [PATCH net-next RFC] selftests: test timestamps in psock_tpacket
From: Willem de Bruijn @ 2017-11-30 1:52 UTC (permalink / raw)
To: netdev; +Cc: arnd, Willem de Bruijn
In-Reply-To: <CAF=yD-Lp_ByK7LODFof5XLsp2kNmHS9P+HAB7yyfSoE0FfW1ng@mail.gmail.com>
From: Willem de Bruijn <willemb@google.com>
Packet rings can return timestamps. Optionally test this path.
Verify that the returned values are sane.
Also test new timestamp modes skip and ns64.
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
tools/testing/selftests/net/psock_tpacket.c | 125 +++++++++++++++++++++++++++-
1 file changed, 124 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c
index 7f6cd9fdacf3..5af11016a5de 100644
--- a/tools/testing/selftests/net/psock_tpacket.c
+++ b/tools/testing/selftests/net/psock_tpacket.c
@@ -36,6 +36,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -57,6 +58,7 @@
#include <net/if.h>
#include <inttypes.h>
#include <poll.h>
+#include <sys/time.h>
#include "psock_lib.h"
@@ -75,6 +77,19 @@
#define NUM_PACKETS 100
#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
+const uint64_t tstamp_bound_ns64 = 1000UL * 1000 * 1000;
+
+enum cfg_tstamp_type {
+ tstype_none,
+ tstype_default,
+ tstype_skip,
+ tstype_ns64
+};
+
+static enum cfg_tstamp_type cfg_tstamp;
+
+static uint64_t tstamp_start_ns64;
+
struct ring {
struct iovec *rd;
uint8_t *mm_space;
@@ -150,6 +165,43 @@ static void test_payload(void *pay, size_t len)
}
}
+static void test_tstamp(uint32_t sec, uint32_t nsec)
+{
+ uint64_t tstamp_ns64;
+
+ if (!cfg_tstamp)
+ return;
+
+ if (cfg_tstamp == tstype_skip) {
+ if (sec || nsec) {
+ fprintf(stderr, "%s: unexpected tstamp %u:%u\n",
+ __func__, sec, nsec);
+ exit(1);
+ }
+ return;
+ }
+
+ if (cfg_tstamp == tstype_ns64)
+ tstamp_ns64 = (((uint64_t) sec) << 32) | nsec;
+ else
+ tstamp_ns64 = (sec * 1000UL * 1000 * 1000) + nsec;
+
+ if (tstamp_ns64 < tstamp_start_ns64) {
+ fprintf(stderr, "tstamp: %lu lowerbound=%lu under=%lu\n",
+ tstamp_ns64, tstamp_start_ns64,
+ tstamp_start_ns64 - tstamp_ns64);
+ exit(1);
+ }
+ if (tstamp_ns64 > tstamp_start_ns64 + tstamp_bound_ns64) {
+ fprintf(stderr, "tstamp: %lu upperbound=%lu over=%lu\n",
+ tstamp_ns64,
+ tstamp_start_ns64 + tstamp_bound_ns64,
+ tstamp_ns64 - (tstamp_start_ns64 +
+ tstamp_bound_ns64));
+ exit(1);
+ }
+}
+
static void create_payload(void *pay, size_t *len)
{
int i;
@@ -256,12 +308,18 @@ static void walk_v1_v2_rx(int sock, struct ring *ring)
case TPACKET_V1:
test_payload((uint8_t *) ppd.raw + ppd.v1->tp_h.tp_mac,
ppd.v1->tp_h.tp_snaplen);
+ test_tstamp(ppd.v1->tp_h.tp_sec,
+ cfg_tstamp == tstype_ns64 ?
+ ppd.v1->tp_h.tp_usec :
+ ppd.v1->tp_h.tp_usec * 1000);
total_bytes += ppd.v1->tp_h.tp_snaplen;
break;
case TPACKET_V2:
test_payload((uint8_t *) ppd.raw + ppd.v2->tp_h.tp_mac,
ppd.v2->tp_h.tp_snaplen);
+ test_tstamp(ppd.v2->tp_h.tp_sec,
+ ppd.v2->tp_h.tp_nsec);
total_bytes += ppd.v2->tp_h.tp_snaplen;
break;
}
@@ -572,6 +630,7 @@ static void __v3_walk_block(struct block_desc *pbd, const int block_num)
bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac);
test_payload((uint8_t *) ppd + ppd->tp_mac, ppd->tp_snaplen);
+ test_tstamp(ppd->tp_sec, ppd->tp_nsec);
status_bar_update();
total_packets++;
@@ -766,6 +825,38 @@ static void unmap_ring(int sock, struct ring *ring)
free(ring->rd);
}
+static void setup_tstamp(int sock)
+{
+ struct timeval tv;
+ int one = 1;
+
+ gettimeofday(&tv, NULL);
+ tstamp_start_ns64 = (tv.tv_sec * 1000UL * 1000 * 1000) +
+ (tv.tv_usec * 1000UL);
+
+/* TODO: remove before submit: temporary */
+#ifndef PACKET_SKIPTIMESTAMP
+#define PACKET_SKIPTIMESTAMP 23
+#endif
+#ifndef PACKET_TIMESTAMP_NS64
+#define PACKET_TIMESTAMP_NS64 24
+#endif
+
+ if (cfg_tstamp == tstype_skip) {
+ if (setsockopt(sock, SOL_PACKET, PACKET_SKIPTIMESTAMP,
+ &one, sizeof(one))) {
+ perror("setsockopt skiptimestamp");
+ exit(1);
+ }
+ } else if (cfg_tstamp == tstype_ns64) {
+ if (setsockopt(sock, SOL_PACKET, PACKET_TIMESTAMP_NS64,
+ &one, sizeof(one))) {
+ perror("setsockopt timestamp ns64");
+ exit(1);
+ }
+ }
+}
+
static int test_kernel_bit_width(void)
{
char in[512], *ptr;
@@ -829,6 +920,8 @@ static int test_tpacket(int version, int type)
}
sock = pfsocket(version);
+ if (cfg_tstamp)
+ setup_tstamp(sock);
memset(&ring, 0, sizeof(ring));
setup_ring(sock, &ring, version, type);
mmap_ring(sock, &ring);
@@ -841,10 +934,40 @@ static int test_tpacket(int version, int type)
return 0;
}
-int main(void)
+static void usage(const char *filepath)
+{
+ fprintf(stderr, "Usage: %s [-t <default|skip|ns64>]\n", filepath);
+ exit(1);
+}
+
+static void parse_opts(int argc, char **argv)
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "t:")) != -1) {
+ switch (c) {
+ case 't':
+ if (!strcmp(optarg, "default"))
+ cfg_tstamp = tstype_default;
+ else if (!strcmp(optarg, "skip"))
+ cfg_tstamp = tstype_skip;
+ else if (!strcmp(optarg, "ns64"))
+ cfg_tstamp = tstype_ns64;
+ else
+ usage(argv[0]);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+}
+
+int main(int argc, char **argv)
{
int ret = 0;
+ parse_opts(argc, argv);
+
ret |= test_tpacket(TPACKET_V1, PACKET_RX_RING);
ret |= test_tpacket(TPACKET_V1, PACKET_TX_RING);
--
2.15.0.531.g2ccb3012c9-goog
^ permalink raw reply related
* [PATCH v2 6/6] bpf: add new test test_many_kprobe
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
The test compares old text based kprobe API with PERF_TYPE_KPROBE.
Here is a sample output of this test:
Creating 1000 kprobes with text-based API takes 6.979683 seconds
Cleaning 1000 kprobes with text-based API takes 84.897687 seconds
Creating 1000 kprobes with PERF_TYPE_KPROBE (function name) takes 5.077558 seconds
Cleaning 1000 kprobes with PERF_TYPE_KPROBE (function name) takes 81.241354 seconds
Creating 1000 kprobes with PERF_TYPE_KPROBE (function addr) takes 5.218255 seconds
Cleaning 1000 kprobes with PERF_TYPE_KPROBE (function addr) takes 80.010731 seconds
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
---
samples/bpf/Makefile | 3 +
samples/bpf/bpf_load.c | 5 +-
samples/bpf/bpf_load.h | 4 +
samples/bpf/test_many_kprobe_user.c | 182 ++++++++++++++++++++++++++++++++++++
4 files changed, 191 insertions(+), 3 deletions(-)
create mode 100644 samples/bpf/test_many_kprobe_user.c
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 9b4a66e..ec92f35 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -42,6 +42,7 @@ hostprogs-y += xdp_redirect
hostprogs-y += xdp_redirect_map
hostprogs-y += xdp_monitor
hostprogs-y += syscall_tp
+hostprogs-y += test_many_kprobe
# Libbpf dependencies
LIBBPF := ../../tools/lib/bpf/bpf.o
@@ -87,6 +88,7 @@ xdp_redirect-objs := bpf_load.o $(LIBBPF) xdp_redirect_user.o
xdp_redirect_map-objs := bpf_load.o $(LIBBPF) xdp_redirect_map_user.o
xdp_monitor-objs := bpf_load.o $(LIBBPF) xdp_monitor_user.o
syscall_tp-objs := bpf_load.o $(LIBBPF) syscall_tp_user.o
+test_many_kprobe-objs := bpf_load.o $(LIBBPF) test_many_kprobe_user.o
# Tell kbuild to always build the programs
always := $(hostprogs-y)
@@ -172,6 +174,7 @@ HOSTLOADLIBES_xdp_redirect += -lelf
HOSTLOADLIBES_xdp_redirect_map += -lelf
HOSTLOADLIBES_xdp_monitor += -lelf
HOSTLOADLIBES_syscall_tp += -lelf
+HOSTLOADLIBES_test_many_kprobe += -lelf
# Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
# make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 872510e..caba9bc 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -635,9 +635,8 @@ void read_trace_pipe(void)
}
}
-#define MAX_SYMS 300000
-static struct ksym syms[MAX_SYMS];
-static int sym_cnt;
+struct ksym syms[MAX_SYMS];
+int sym_cnt;
static int ksym_cmp(const void *p1, const void *p2)
{
diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h
index e7a8a21..16bc263 100644
--- a/samples/bpf/bpf_load.h
+++ b/samples/bpf/bpf_load.h
@@ -67,6 +67,10 @@ static inline __u64 ptr_to_u64(const void *ptr)
return (__u64) (unsigned long) ptr;
}
+#define MAX_SYMS 300000
+extern struct ksym syms[MAX_SYMS];
+extern int sym_cnt;
+
int load_kallsyms(void);
struct ksym *ksym_search(long key);
int set_link_xdp_fd(int ifindex, int fd, __u32 flags);
diff --git a/samples/bpf/test_many_kprobe_user.c b/samples/bpf/test_many_kprobe_user.c
new file mode 100644
index 0000000..1f3ee07
--- /dev/null
+++ b/samples/bpf/test_many_kprobe_user.c
@@ -0,0 +1,182 @@
+/* Copyright (c) 2017 Facebook
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <linux/version.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <time.h>
+#include "libbpf.h"
+#include "bpf_load.h"
+#include "perf-sys.h"
+
+#define MAX_KPROBES 1000
+
+#define DEBUGFS "/sys/kernel/debug/tracing/"
+
+int kprobes[MAX_KPROBES] = {0};
+int kprobe_count;
+int perf_event_fds[MAX_KPROBES];
+const char license[] = "GPL";
+
+static __u64 time_get_ns(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000000000ull + ts.tv_nsec;
+}
+
+static int kprobe_api(char *func, void *addr, bool use_new_api)
+{
+ int efd;
+ struct perf_event_attr attr = {};
+ char buf[256];
+ int err, id;
+
+ attr.sample_type = PERF_SAMPLE_RAW;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
+
+ if (use_new_api) {
+ attr.type = PERF_TYPE_KPROBE;
+ if (func) {
+ attr.kprobe_func = ptr_to_u64(func);
+ attr.probe_offset = 0;
+ } else {
+ attr.kprobe_func = 0;
+ attr.kprobe_addr = ptr_to_u64(addr);
+ }
+ } else {
+ attr.type = PERF_TYPE_TRACEPOINT;
+ snprintf(buf, sizeof(buf),
+ "echo 'p:%s %s' >> /sys/kernel/debug/tracing/kprobe_events",
+ func, func);
+ err = system(buf);
+ if (err < 0) {
+ printf("failed to create kprobe '%s' error '%s'\n",
+ func, strerror(errno));
+ return -1;
+ }
+
+ strcpy(buf, DEBUGFS);
+ strcat(buf, "events/kprobes/");
+ strcat(buf, func);
+ strcat(buf, "/id");
+ efd = open(buf, O_RDONLY, 0);
+ if (efd < 0) {
+ printf("failed to open event %s\n", func);
+ return -1;
+ }
+
+ err = read(efd, buf, sizeof(buf));
+ if (err < 0 || err >= sizeof(buf)) {
+ printf("read from '%s' failed '%s'\n", func,
+ strerror(errno));
+ return -1;
+ }
+
+ close(efd);
+ buf[err] = 0;
+ id = atoi(buf);
+ attr.config = id;
+ }
+
+ attr.size = sizeof(attr);
+ efd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/,
+ -1/*group_fd*/, 0);
+
+ return efd;
+}
+
+static int select_kprobes(void)
+{
+ int fd;
+ int i;
+
+ load_kallsyms();
+
+ kprobe_count = 0;
+ for (i = 0; i < sym_cnt; i++) {
+ if (strstr(syms[i].name, "."))
+ continue;
+ fd = kprobe_api(syms[i].name, NULL, true);
+ if (fd < 0)
+ continue;
+ close(fd);
+ kprobes[kprobe_count] = i;
+ if (++kprobe_count >= MAX_KPROBES)
+ break;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ __u64 start_time;
+
+ select_kprobes();
+
+ /* clean all trace_kprobe */
+ i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
+
+ /* test text based API */
+ start_time = time_get_ns();
+ for (i = 0; i < kprobe_count; i++)
+ perf_event_fds[i] = kprobe_api(syms[kprobes[i]].name,
+ NULL, false);
+ printf("Creating %d kprobes with text-based API takes %f seconds\n",
+ kprobe_count, (time_get_ns() - start_time) / 1000000000.0);
+
+ start_time = time_get_ns();
+ for (i = 0; i < kprobe_count; i++)
+ if (perf_event_fds[i] > 0)
+ close(perf_event_fds[i]);
+ i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
+ printf("Cleaning %d kprobes with text-based API takes %f seconds\n",
+ kprobe_count, (time_get_ns() - start_time) / 1000000000.0);
+
+ /* test PERF_TYPE_KPROBE API, with function names */
+ start_time = time_get_ns();
+ for (i = 0; i < kprobe_count; i++)
+ perf_event_fds[i] = kprobe_api(syms[kprobes[i]].name,
+ NULL, true);
+ printf("Creating %d kprobes with PERF_TYPE_KPROBE (function name) takes %f seconds\n",
+ kprobe_count, (time_get_ns() - start_time) / 1000000000.0);
+
+ start_time = time_get_ns();
+ for (i = 0; i < kprobe_count; i++)
+ if (perf_event_fds[i] > 0)
+ close(perf_event_fds[i]);
+ printf("Cleaning %d kprobes with PERF_TYPE_KPROBE (function name) takes %f seconds\n",
+ kprobe_count, (time_get_ns() - start_time) / 1000000000.0);
+
+ /* test PERF_TYPE_KPROBE API, with function address */
+ start_time = time_get_ns();
+ for (i = 0; i < kprobe_count; i++)
+ perf_event_fds[i] = kprobe_api(
+ NULL, (void *)(syms[kprobes[i]].addr), true);
+ printf("Creating %d kprobes with PERF_TYPE_KPROBE (function addr) takes %f seconds\n",
+ kprobe_count, (time_get_ns() - start_time) / 1000000000.0);
+
+ start_time = time_get_ns();
+ for (i = 0; i < kprobe_count; i++)
+ if (perf_event_fds[i] > 0)
+ close(perf_event_fds[i]);
+ printf("Cleaning %d kprobes with PERF_TYPE_KPROBE (function addr) takes %f seconds\n",
+ kprobe_count, (time_get_ns() - start_time) / 1000000000.0);
+ return 0;
+}
--
2.9.5
^ permalink raw reply related
* [PATCH v2 3/6] perf: implement support of PERF_TYPE_KPROBE
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
A new pmu, perf_kprobe, is created for PERF_TYPE_KPROBE. Based on
input from perf_event_open(), perf_kprobe creates a kprobe (or
kretprobe) for the perf_event. This kprobe is private to this
perf_event, and thus not added to global lists, and not
available in tracefs.
Two functions, create_local_trace_kprobe() and
destroy_local_trace_kprobe() are added to created and destroy these
local trace_kprobe.
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Yonghong Song <yhs@fb.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
---
include/linux/trace_events.h | 2 +
kernel/events/core.c | 41 +++++++++++++++++--
kernel/trace/trace_event_perf.c | 53 ++++++++++++++++++++++++
kernel/trace/trace_kprobe.c | 91 +++++++++++++++++++++++++++++++++++++----
kernel/trace/trace_probe.h | 7 ++++
5 files changed, 183 insertions(+), 11 deletions(-)
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 2bcb4dc..51f748c9 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -494,6 +494,8 @@ extern int perf_trace_init(struct perf_event *event);
extern void perf_trace_destroy(struct perf_event *event);
extern int perf_trace_add(struct perf_event *event, int flags);
extern void perf_trace_del(struct perf_event *event, int flags);
+extern int perf_kprobe_init(struct perf_event *event);
+extern void perf_kprobe_destroy(struct perf_event *event);
extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str);
extern void ftrace_profile_free_filter(struct perf_event *event);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 494eca1..daa6e0a 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7970,6 +7970,28 @@ static int perf_tp_event_init(struct perf_event *event)
return 0;
}
+static int perf_kprobe_event_init(struct perf_event *event)
+{
+ int err;
+
+ if (event->attr.type != PERF_TYPE_KPROBE)
+ return -ENOENT;
+
+ /*
+ * no branch sampling for probe events
+ */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ err = perf_kprobe_init(event);
+ if (err)
+ return err;
+
+ event->destroy = perf_kprobe_destroy;
+
+ return 0;
+}
+
static struct pmu perf_tracepoint = {
.task_ctx_nr = perf_sw_context,
@@ -7981,9 +8003,20 @@ static struct pmu perf_tracepoint = {
.read = perf_swevent_read,
};
+static struct pmu perf_kprobe = {
+ .task_ctx_nr = perf_sw_context,
+ .event_init = perf_kprobe_event_init,
+ .add = perf_trace_add,
+ .del = perf_trace_del,
+ .start = perf_swevent_start,
+ .stop = perf_swevent_stop,
+ .read = perf_swevent_read,
+};
+
static inline void perf_tp_register(void)
{
perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);
+ perf_pmu_register(&perf_kprobe, "kprobe", PERF_TYPE_KPROBE);
}
static void perf_event_free_filter(struct perf_event *event)
@@ -8065,7 +8098,8 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
bool is_kprobe, is_tracepoint, is_syscall_tp;
struct bpf_prog *prog;
- if (event->attr.type != PERF_TYPE_TRACEPOINT)
+ if (event->attr.type != PERF_TYPE_TRACEPOINT &&
+ event->attr.type != PERF_TYPE_KPROBE)
return perf_event_set_bpf_handler(event, prog_fd);
if (event->tp_event->prog)
@@ -8537,8 +8571,9 @@ static int perf_event_set_filter(struct perf_event *event, void __user *arg)
char *filter_str;
int ret = -EINVAL;
- if ((event->attr.type != PERF_TYPE_TRACEPOINT ||
- !IS_ENABLED(CONFIG_EVENT_TRACING)) &&
+ if (((event->attr.type != PERF_TYPE_TRACEPOINT &&
+ event->attr.type != PERF_TYPE_KPROBE) ||
+ !IS_ENABLED(CONFIG_EVENT_TRACING)) &&
!has_addr_filter(event))
return -EINVAL;
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 13ba2d3..7cf0d99 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/kprobes.h>
#include "trace.h"
+#include "trace_probe.h"
static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
@@ -229,6 +230,48 @@ int perf_trace_init(struct perf_event *p_event)
return ret;
}
+int perf_kprobe_init(struct perf_event *p_event)
+{
+ int ret;
+ char *func = NULL;
+ struct trace_event_call *tp_event;
+
+#ifdef CONFIG_KPROBE_EVENTS
+ if (p_event->attr.kprobe_func) {
+ func = kzalloc(MAX_PROBE_FUNC_NAME_LEN, GFP_KERNEL);
+ if (!func)
+ return -ENOMEM;
+ ret = strncpy_from_user(
+ func, u64_to_user_ptr(p_event->attr.kprobe_func),
+ MAX_PROBE_FUNC_NAME_LEN);
+ if (ret < 0)
+ goto out;
+
+ if (func[0] == '\0') {
+ kfree(func);
+ func = NULL;
+ }
+ }
+
+ tp_event = create_local_trace_kprobe(
+ func, (void *)(unsigned long)(p_event->attr.kprobe_addr),
+ p_event->attr.probe_offset, p_event->attr.config != 0);
+ if (IS_ERR(tp_event)) {
+ ret = PTR_ERR(tp_event);
+ goto out;
+ }
+
+ ret = perf_trace_event_init(tp_event, p_event);
+ if (ret)
+ destroy_local_trace_kprobe(tp_event);
+out:
+ kfree(func);
+ return ret;
+#else
+ return -EOPNOTSUPP;
+#endif /* CONFIG_KPROBE_EVENTS */
+}
+
void perf_trace_destroy(struct perf_event *p_event)
{
mutex_lock(&event_mutex);
@@ -237,6 +280,16 @@ void perf_trace_destroy(struct perf_event *p_event)
mutex_unlock(&event_mutex);
}
+void perf_kprobe_destroy(struct perf_event *p_event)
+{
+ perf_trace_event_close(p_event);
+ perf_trace_event_unreg(p_event);
+
+#ifdef CONFIG_KPROBE_EVENTS
+ destroy_local_trace_kprobe(p_event->tp_event);
+#endif
+}
+
int perf_trace_add(struct perf_event *p_event, int flags)
{
struct trace_event_call *tp_event = p_event->tp_event;
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 8a907e1..16b334a 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -438,6 +438,14 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file)
disable_kprobe(&tk->rp.kp);
wait = 1;
}
+
+ /*
+ * if tk is not added to any list, it must be a local trace_kprobe
+ * created with perf_event_open. We don't need to wait for these
+ * trace_kprobes
+ */
+ if (list_empty(&tk->list))
+ wait = 0;
out:
if (wait) {
/*
@@ -1315,12 +1323,9 @@ static struct trace_event_functions kprobe_funcs = {
.trace = print_kprobe_event
};
-static int register_kprobe_event(struct trace_kprobe *tk)
+static inline void init_trace_event_call(struct trace_kprobe *tk,
+ struct trace_event_call *call)
{
- struct trace_event_call *call = &tk->tp.call;
- int ret;
-
- /* Initialize trace_event_call */
INIT_LIST_HEAD(&call->class->fields);
if (trace_kprobe_is_return(tk)) {
call->event.funcs = &kretprobe_funcs;
@@ -1329,6 +1334,19 @@ static int register_kprobe_event(struct trace_kprobe *tk)
call->event.funcs = &kprobe_funcs;
call->class->define_fields = kprobe_event_define_fields;
}
+
+ call->flags = TRACE_EVENT_FL_KPROBE;
+ call->class->reg = kprobe_register;
+ call->data = tk;
+}
+
+static int register_kprobe_event(struct trace_kprobe *tk)
+{
+ struct trace_event_call *call = &tk->tp.call;
+ int ret = 0;
+
+ init_trace_event_call(tk, call);
+
if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0)
return -ENOMEM;
ret = register_trace_event(&call->event);
@@ -1336,9 +1354,6 @@ static int register_kprobe_event(struct trace_kprobe *tk)
kfree(call->print_fmt);
return -ENODEV;
}
- call->flags = TRACE_EVENT_FL_KPROBE;
- call->class->reg = kprobe_register;
- call->data = tk;
ret = trace_add_event_call(call);
if (ret) {
pr_info("Failed to register kprobe event: %s\n",
@@ -1360,6 +1375,66 @@ static int unregister_kprobe_event(struct trace_kprobe *tk)
return ret;
}
+#ifdef CONFIG_PERF_EVENTS
+/* create a trace_kprobe, but don't add it to global lists */
+struct trace_event_call *
+create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
+ bool is_return)
+{
+ struct trace_kprobe *tk;
+ int ret;
+ char *event;
+
+ /*
+ * local trace_kprobes are not added to probe_list, so they are never
+ * searched in find_trace_kprobe(). Therefore, there is no concern of
+ * duplicated name here.
+ */
+ event = func ? func : "DUMMY_EVENT";
+
+ tk = alloc_trace_kprobe(KPROBE_EVENT_SYSTEM, event, (void *)addr, func,
+ offs, 0 /* maxactive */, 0 /* nargs */,
+ is_return);
+
+ if (IS_ERR(tk)) {
+ pr_info("Failed to allocate trace_probe.(%d)\n",
+ (int)PTR_ERR(tk));
+ return ERR_CAST(tk);
+ }
+
+ init_trace_event_call(tk, &tk->tp.call);
+
+ if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = __register_trace_kprobe(tk);
+ if (ret < 0)
+ goto error;
+
+ return &tk->tp.call;
+error:
+ free_trace_kprobe(tk);
+ return ERR_PTR(ret);
+}
+
+void destroy_local_trace_kprobe(struct trace_event_call *event_call)
+{
+ struct trace_kprobe *tk;
+
+ tk = container_of(event_call, struct trace_kprobe, tp.call);
+
+ if (trace_probe_is_enabled(&tk->tp)) {
+ WARN_ON(1);
+ return;
+ }
+
+ __unregister_trace_kprobe(tk);
+ free_trace_kprobe(tk);
+}
+#endif /* CONFIG_PERF_EVENTS */
+
/* Make a tracefs interface for controlling probe points */
static __init int init_kprobe_trace(void)
{
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 903273c..910ae1b 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -411,3 +411,10 @@ store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs,
}
extern int set_print_fmt(struct trace_probe *tp, bool is_return);
+
+#ifdef CONFIG_PERF_EVENTS
+extern struct trace_event_call *
+create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
+ bool is_return);
+extern void destroy_local_trace_kprobe(struct trace_event_call *event_call);
+#endif
--
2.9.5
^ permalink raw reply related
* [PATCH v2 5/6] bpf: add option for bpf_load.c to use PERF_TYPE_KPROBE
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
Function load_and_attach() is updated to be able to create kprobes
with either old text based API, or the new PERF_TYPE_KPROBE API.
A global flag use_perf_type_probe is added to select between the
two APIs.
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
---
samples/bpf/bpf_load.c | 54 +++++++++++++++++++++++++++++++-------------------
samples/bpf/bpf_load.h | 8 ++++++++
2 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 2325d7a..872510e 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -8,7 +8,6 @@
#include <errno.h>
#include <unistd.h>
#include <string.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <linux/bpf.h>
#include <linux/filter.h>
@@ -42,6 +41,7 @@ int prog_array_fd = -1;
struct bpf_map_data map_data[MAX_MAPS];
int map_data_count = 0;
+bool use_perf_type_probe = true;
static int populate_prog_array(const char *event, int prog_fd)
{
@@ -70,7 +70,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
size_t insns_cnt = size / sizeof(struct bpf_insn);
enum bpf_prog_type prog_type;
char buf[256];
- int fd, efd, err, id;
+ int fd, efd, err, id = -1;
struct perf_event_attr attr = {};
attr.type = PERF_TYPE_TRACEPOINT;
@@ -128,7 +128,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
return populate_prog_array(event, fd);
}
- if (is_kprobe || is_kretprobe) {
+ if (!use_perf_type_probe && (is_kprobe || is_kretprobe)) {
if (is_kprobe)
event += 7;
else
@@ -169,27 +169,41 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
strcat(buf, "/id");
}
- efd = open(buf, O_RDONLY, 0);
- if (efd < 0) {
- printf("failed to open event %s\n", event);
- return -1;
- }
-
- err = read(efd, buf, sizeof(buf));
- if (err < 0 || err >= sizeof(buf)) {
- printf("read from '%s' failed '%s'\n", event, strerror(errno));
- return -1;
+ if (use_perf_type_probe && (is_kprobe || is_kretprobe)) {
+ attr.type = PERF_TYPE_KPROBE;
+ attr.kprobe_func = ptr_to_u64(
+ event + strlen(is_kprobe ? "kprobe/" : "kretprobe/"));
+ attr.probe_offset = 0;
+ attr.config = !!is_kretprobe;
+ } else {
+ efd = open(buf, O_RDONLY, 0);
+ if (efd < 0) {
+ printf("failed to open event %s\n", event);
+ return -1;
+ }
+ err = read(efd, buf, sizeof(buf));
+ if (err < 0 || err >= sizeof(buf)) {
+ printf("read from '%s' failed '%s'\n", event,
+ strerror(errno));
+ return -1;
+ }
+ close(efd);
+ buf[err] = 0;
+ id = atoi(buf);
+ attr.config = id;
}
- close(efd);
-
- buf[err] = 0;
- id = atoi(buf);
- attr.config = id;
-
efd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0);
if (efd < 0) {
- printf("event %d fd %d err %s\n", id, efd, strerror(errno));
+ if (use_perf_type_probe && (is_kprobe || is_kretprobe))
+ printf("k%sprobe %s fd %d err %s\n",
+ is_kprobe ? "" : "ret",
+ event + strlen(is_kprobe ? "kprobe/"
+ : "kretprobe/"),
+ efd, strerror(errno));
+ else
+ printf("event %d fd %d err %s\n", id, efd,
+ strerror(errno));
return -1;
}
event_fd[prog_cnt - 1] = efd;
diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h
index 7d57a42..e7a8a21 100644
--- a/samples/bpf/bpf_load.h
+++ b/samples/bpf/bpf_load.h
@@ -2,6 +2,7 @@
#ifndef __BPF_LOAD_H
#define __BPF_LOAD_H
+#include <stdbool.h>
#include "libbpf.h"
#define MAX_MAPS 32
@@ -38,6 +39,8 @@ extern int map_fd[MAX_MAPS];
extern struct bpf_map_data map_data[MAX_MAPS];
extern int map_data_count;
+extern bool use_perf_type_probe;
+
/* parses elf file compiled by llvm .c->.o
* . parses 'maps' section and creates maps via BPF syscall
* . parses 'license' section and passes it to syscall
@@ -59,6 +62,11 @@ struct ksym {
char *name;
};
+static inline __u64 ptr_to_u64(const void *ptr)
+{
+ return (__u64) (unsigned long) ptr;
+}
+
int load_kallsyms(void);
struct ksym *ksym_search(long key);
int set_link_xdp_fd(int ifindex, int fd, __u32 flags);
--
2.9.5
^ permalink raw reply related
* [PATCH v2 4/6] perf: implement support of PERF_TYPE_UPROBE
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
This patch adds perf_uprobe support with similar pattern as previous
patch (for kprobe).
Two functions, create_local_trace_uprobe() and
destroy_local_trace_uprobe(), are created so a uprobe can be created
and attached to the file descriptor created by perf_event_open().
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Yonghong Song <yhs@fb.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
---
include/linux/trace_events.h | 2 +
kernel/events/core.c | 39 +++++++++++++++++-
kernel/trace/trace_event_perf.c | 58 ++++++++++++++++++++++++++
kernel/trace/trace_probe.h | 4 ++
kernel/trace/trace_uprobe.c | 90 ++++++++++++++++++++++++++++++++++++-----
5 files changed, 181 insertions(+), 12 deletions(-)
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 51f748c9..9272fa6 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -496,6 +496,8 @@ extern int perf_trace_add(struct perf_event *event, int flags);
extern void perf_trace_del(struct perf_event *event, int flags);
extern int perf_kprobe_init(struct perf_event *event);
extern void perf_kprobe_destroy(struct perf_event *event);
+extern int perf_uprobe_init(struct perf_event *event);
+extern void perf_uprobe_destroy(struct perf_event *event);
extern int ftrace_profile_set_filter(struct perf_event *event, int event_id,
char *filter_str);
extern void ftrace_profile_free_filter(struct perf_event *event);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index daa6e0a..b566a53 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7992,6 +7992,28 @@ static int perf_kprobe_event_init(struct perf_event *event)
return 0;
}
+static int perf_uprobe_event_init(struct perf_event *event)
+{
+ int err;
+
+ if (event->attr.type != PERF_TYPE_UPROBE)
+ return -ENOENT;
+
+ /*
+ * no branch sampling for probe events
+ */
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ err = perf_uprobe_init(event);
+ if (err)
+ return err;
+
+ event->destroy = perf_uprobe_destroy;
+
+ return 0;
+}
+
static struct pmu perf_tracepoint = {
.task_ctx_nr = perf_sw_context,
@@ -8013,10 +8035,21 @@ static struct pmu perf_kprobe = {
.read = perf_swevent_read,
};
+static struct pmu perf_uprobe = {
+ .task_ctx_nr = perf_sw_context,
+ .event_init = perf_uprobe_event_init,
+ .add = perf_trace_add,
+ .del = perf_trace_del,
+ .start = perf_swevent_start,
+ .stop = perf_swevent_stop,
+ .read = perf_swevent_read,
+};
+
static inline void perf_tp_register(void)
{
perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT);
perf_pmu_register(&perf_kprobe, "kprobe", PERF_TYPE_KPROBE);
+ perf_pmu_register(&perf_uprobe, "uprobe", PERF_TYPE_UPROBE);
}
static void perf_event_free_filter(struct perf_event *event)
@@ -8099,7 +8132,8 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
struct bpf_prog *prog;
if (event->attr.type != PERF_TYPE_TRACEPOINT &&
- event->attr.type != PERF_TYPE_KPROBE)
+ event->attr.type != PERF_TYPE_KPROBE &&
+ event->attr.type != PERF_TYPE_UPROBE)
return perf_event_set_bpf_handler(event, prog_fd);
if (event->tp_event->prog)
@@ -8572,7 +8606,8 @@ static int perf_event_set_filter(struct perf_event *event, void __user *arg)
int ret = -EINVAL;
if (((event->attr.type != PERF_TYPE_TRACEPOINT &&
- event->attr.type != PERF_TYPE_KPROBE) ||
+ event->attr.type != PERF_TYPE_KPROBE &&
+ event->attr.type != PERF_TYPE_UPROBE) ||
!IS_ENABLED(CONFIG_EVENT_TRACING)) &&
!has_addr_filter(event))
return -EINVAL;
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index 7cf0d99..1b97ea2 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -272,6 +272,52 @@ int perf_kprobe_init(struct perf_event *p_event)
#endif /* CONFIG_KPROBE_EVENTS */
}
+int perf_uprobe_init(struct perf_event *p_event)
+{
+ int ret;
+ char *path = NULL;
+ struct trace_event_call *tp_event;
+
+#ifdef CONFIG_UPROBE_EVENTS
+ if (!p_event->attr.uprobe_path)
+ return -EINVAL;
+ path = kzalloc(PATH_MAX, GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+ ret = strncpy_from_user(
+ path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX);
+ if (ret < 0)
+ goto out;
+ if (path[0] == '\0') {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tp_event = create_local_trace_uprobe(
+ path, p_event->attr.probe_offset, p_event->attr.config != 0);
+ if (IS_ERR(tp_event)) {
+ ret = PTR_ERR(tp_event);
+ goto out;
+ }
+
+ /*
+ * local trace_uprobe need to hold event_mutex to call
+ * uprobe_buffer_enable() and uprobe_buffer_disable().
+ * event_mutex is not required for local trace_kprobes.
+ */
+ mutex_lock(&event_mutex);
+ ret = perf_trace_event_init(tp_event, p_event);
+ if (ret)
+ destroy_local_trace_uprobe(tp_event);
+ mutex_unlock(&event_mutex);
+out:
+ kfree(path);
+ return ret;
+#else
+ return -EOPNOTSUPP;
+#endif /* CONFIG_UPROBE_EVENTS */
+}
+
void perf_trace_destroy(struct perf_event *p_event)
{
mutex_lock(&event_mutex);
@@ -290,6 +336,18 @@ void perf_kprobe_destroy(struct perf_event *p_event)
#endif
}
+void perf_uprobe_destroy(struct perf_event *p_event)
+{
+ mutex_lock(&event_mutex);
+ perf_trace_event_close(p_event);
+ perf_trace_event_unreg(p_event);
+ mutex_unlock(&event_mutex);
+
+#ifdef CONFIG_UPROBE_EVENTS
+ destroy_local_trace_uprobe(p_event->tp_event);
+#endif
+}
+
int perf_trace_add(struct perf_event *p_event, int flags)
{
struct trace_event_call *tp_event = p_event->tp_event;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 910ae1b..86b5925 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -417,4 +417,8 @@ extern struct trace_event_call *
create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
bool is_return);
extern void destroy_local_trace_kprobe(struct trace_event_call *event_call);
+
+extern struct trace_event_call *
+create_local_trace_uprobe(char *name, unsigned long offs, bool is_return);
+extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
#endif
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 4525e02..4d805d2 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -31,8 +31,8 @@
#define UPROBE_EVENT_SYSTEM "uprobes"
struct uprobe_trace_entry_head {
- struct trace_entry ent;
- unsigned long vaddr[];
+ struct trace_entry ent;
+ unsigned long vaddr[];
};
#define SIZEOF_TRACE_ENTRY(is_return) \
@@ -1293,16 +1293,25 @@ static struct trace_event_functions uprobe_funcs = {
.trace = print_uprobe_event
};
-static int register_uprobe_event(struct trace_uprobe *tu)
+static inline void init_trace_event_call(struct trace_uprobe *tu,
+ struct trace_event_call *call)
{
- struct trace_event_call *call = &tu->tp.call;
- int ret;
-
- /* Initialize trace_event_call */
INIT_LIST_HEAD(&call->class->fields);
call->event.funcs = &uprobe_funcs;
call->class->define_fields = uprobe_event_define_fields;
+ call->flags = TRACE_EVENT_FL_UPROBE;
+ call->class->reg = trace_uprobe_register;
+ call->data = tu;
+}
+
+static int register_uprobe_event(struct trace_uprobe *tu)
+{
+ struct trace_event_call *call = &tu->tp.call;
+ int ret = 0;
+
+ init_trace_event_call(tu, call);
+
if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
return -ENOMEM;
@@ -1312,9 +1321,6 @@ static int register_uprobe_event(struct trace_uprobe *tu)
return -ENODEV;
}
- call->flags = TRACE_EVENT_FL_UPROBE;
- call->class->reg = trace_uprobe_register;
- call->data = tu;
ret = trace_add_event_call(call);
if (ret) {
@@ -1340,6 +1346,70 @@ static int unregister_uprobe_event(struct trace_uprobe *tu)
return 0;
}
+#ifdef CONFIG_PERF_EVENTS
+struct trace_event_call *
+create_local_trace_uprobe(char *name, unsigned long offs, bool is_return)
+{
+ struct trace_uprobe *tu;
+ struct inode *inode;
+ struct path path;
+ int ret;
+
+ ret = kern_path(name, LOOKUP_FOLLOW, &path);
+ if (ret)
+ return ERR_PTR(ret);
+
+ inode = igrab(d_inode(path.dentry));
+ path_put(&path);
+
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ iput(inode);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * local trace_kprobes are not added to probe_list, so they are never
+ * searched in find_trace_kprobe(). Therefore, there is no concern of
+ * duplicated name "DUMMY_EVENT" here.
+ */
+ tu = alloc_trace_uprobe(UPROBE_EVENT_SYSTEM, "DUMMY_EVENT", 0,
+ is_return);
+
+ if (IS_ERR(tu)) {
+ pr_info("Failed to allocate trace_uprobe.(%d)\n",
+ (int)PTR_ERR(tu));
+ return ERR_CAST(tu);
+ }
+
+ tu->offset = offs;
+ tu->inode = inode;
+ tu->filename = kstrdup(name, GFP_KERNEL);
+ init_trace_event_call(tu, &tu->tp.call);
+
+ if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ return &tu->tp.call;
+error:
+ free_trace_uprobe(tu);
+ return ERR_PTR(ret);
+}
+
+void destroy_local_trace_uprobe(struct trace_event_call *event_call)
+{
+ struct trace_uprobe *tu;
+
+ tu = container_of(event_call, struct trace_uprobe, tp.call);
+
+ kfree(tu->tp.call.print_fmt);
+ tu->tp.call.print_fmt = NULL;
+
+ free_trace_uprobe(tu);
+}
+#endif /* CONFIG_PERF_EVENTS */
+
/* Make a trace interface for controling probe points */
static __init int init_uprobe_trace(void)
{
--
2.9.5
^ permalink raw reply related
* [PATCH v2 2/6] perf: copy new perf_event.h to tools/include/uapi
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
perf_event.h is updated in previous patch, this patch applies same
changes to the tools/ version. This is part is put in a separate
patch in case the two files are back ported separately.
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Yonghong Song <yhs@fb.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
tools/include/uapi/linux/perf_event.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index b9a4953..c361442 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -33,6 +33,8 @@ enum perf_type_id {
PERF_TYPE_HW_CACHE = 3,
PERF_TYPE_RAW = 4,
PERF_TYPE_BREAKPOINT = 5,
+ PERF_TYPE_KPROBE = 6,
+ PERF_TYPE_UPROBE = 7,
PERF_TYPE_MAX, /* non-ABI */
};
@@ -299,6 +301,8 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */
#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
+#define MAX_PROBE_FUNC_NAME_LEN 64
+
/*
* Hardware event_id to monitor via a performance monitoring event:
*
@@ -380,10 +384,14 @@ struct perf_event_attr {
__u32 bp_type;
union {
__u64 bp_addr;
+ __u64 kprobe_func; /* for PERF_TYPE_KPROBE */
+ __u64 uprobe_path; /* for PERF_TYPE_UPROBE */
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
+ __u64 kprobe_addr; /* for PERF_TYPE_KPROBE, with kprobe_func == NULL */
+ __u64 probe_offset; /* for PERF_TYPE_[K,U]PROBE */
__u64 config2; /* extension of config1 */
};
__u64 branch_sample_type; /* enum perf_branch_sample_type */
--
2.9.5
^ permalink raw reply related
* [PATCH v2] perf_event_open.2: add type PERF_TYPE_KPROBE and PERF_TYPE_UPROBE
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
Two new types PERF_TYPE_KPROBE and PERF_TYPE_UPROBE are being added
to perf_event_attr. This patch adds information about this type.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
man2/perf_event_open.2 | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/man2/perf_event_open.2 b/man2/perf_event_open.2
index c91da3f..e662332 100644
--- a/man2/perf_event_open.2
+++ b/man2/perf_event_open.2
@@ -256,11 +256,15 @@ struct perf_event_attr {
union {
__u64 bp_addr; /* breakpoint address */
+ __u64 kprobe_func; /* for PERF_TYPE_KPROBE */
+ __u64 uprobe_path; /* for PERF_TYPE_KPROBE */
__u64 config1; /* extension of config */
};
union {
__u64 bp_len; /* breakpoint length */
+ __u64 kprobe_addr; /* for PERF_TYPE_KPROBE, with kprobe_func == NULL */
+ __u64 probe_offset; /* for PERF_TYPE_[K,U]PROBE */
__u64 config2; /* extension of config1 */
};
__u64 branch_sample_type; /* enum perf_branch_sample_type */
@@ -317,6 +321,13 @@ This indicates a hardware breakpoint as provided by the CPU.
Breakpoints can be read/write accesses to an address as well as
execution of an instruction address.
.TP
+.BR PERF_TYPE_KPROBE " and " PERF_TYPE_UPROBE " (since Linux 4.TBD)"
+This indicates a kprobe or uprobe should be created and
+attached to the file descriptor.
+See fields
+.IR kprobe_func ", " uprobe_path ", " kprobe_addr ", and " probe_offset
+for more details.
+.TP
.RB "dynamic PMU"
Since Linux 2.6.38,
.\" commit 2e80a82a49c4c7eca4e35734380f28298ba5db19
@@ -627,6 +638,37 @@ then leave
.I config
set to zero.
Its parameters are set in other places.
+.PP
+If
+.I type
+is
+.BR PERF_TYPE_KPROBE
+or
+.BR PERF_TYPE_UPROBE ,
+.I config
+of 0 means kprobe/uprobe, while
+.I config
+of 1 means kretprobe/uretprobe.
+.RE
+.TP
+.IR kprobe_func ", " uprobe_path ", " kprobe_addr ", and " probe_offset
+.EE
+These fields describes the kprobe/uprobe for
+.BR PERF_TYPE_KPROBE
+and
+.BR PERF_TYPE_UPROBE .
+For kprobe: use
+.I kprobe_func
+and
+.IR probe_offset ,
+or use
+.I kprobe_addr
+and leave
+.I kprobe_func
+as NULL. For uprobe: use
+.I uprobe_path
+and
+.IR probe_offset .
.RE
.TP
.IR sample_period ", " sample_freq
--
2.9.5
^ permalink raw reply related
* [PATCH v2 1/6] perf: Add new types PERF_TYPE_KPROBE and PERF_TYPE_UPROBE
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
Two new perf types, PERF_TYPE_KPROBE and PERF_TYPE_UPROBE, are added
to allow creating [k,u]probe with perf_event_open. These [k,u]probe
are associated with the file decriptor created by perf_event_open,
thus are easy to clean when the file descriptor is destroyed.
kprobe_func and uprobe_path are added to union config1 for pointers
to function name for kprobe or binary path for uprobe.
kprobe_addr and probe_offset are added to union config2 for kernel
address (when kprobe_func is NULL), or [k,u]probe offset.
Signed-off-by: Song Liu <songliubraving@fb.com>
Reviewed-by: Yonghong Song <yhs@fb.com>
Reviewed-by: Josef Bacik <jbacik@fb.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
include/uapi/linux/perf_event.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 362493a..5220600 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -33,6 +33,8 @@ enum perf_type_id {
PERF_TYPE_HW_CACHE = 3,
PERF_TYPE_RAW = 4,
PERF_TYPE_BREAKPOINT = 5,
+ PERF_TYPE_KPROBE = 6,
+ PERF_TYPE_UPROBE = 7,
PERF_TYPE_MAX, /* non-ABI */
};
@@ -299,6 +301,8 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */
#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */
+#define MAX_PROBE_FUNC_NAME_LEN 64
+
/*
* Hardware event_id to monitor via a performance monitoring event:
*
@@ -380,10 +384,14 @@ struct perf_event_attr {
__u32 bp_type;
union {
__u64 bp_addr;
+ __u64 kprobe_func; /* for PERF_TYPE_KPROBE */
+ __u64 uprobe_path; /* for PERF_TYPE_UPROBE */
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
+ __u64 kprobe_addr; /* for PERF_TYPE_KPROBE, with kprobe_func == NULL */
+ __u64 probe_offset; /* for PERF_TYPE_[K,U]PROBE */
__u64 config2; /* extension of config1 */
};
__u64 branch_sample_type; /* enum perf_branch_sample_type */
--
2.9.5
^ permalink raw reply related
* [PATCH v2] bcc: Try use new API to create [k,u]probe with perf_event_open
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com>
New kernel API allows creating [k,u]probe with perf_event_open.
This patch tries to use the new API. If the new API doesn't work,
we fall back to old API.
bpf_detach_probe() looks up the event being removed. If the event
is not found, we skip the clean up procedure.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
src/cc/libbpf.c | 224 +++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 155 insertions(+), 69 deletions(-)
diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
index ef6daf3..5bbcdfd 100644
--- a/src/cc/libbpf.c
+++ b/src/cc/libbpf.c
@@ -526,38 +526,72 @@ int bpf_attach_socket(int sock, int prog) {
return setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog, sizeof(prog));
}
+/*
+ * new kernel API allows creating [k,u]probe with perf_event_open, which
+ * makes it easier to clean up the [k,u]probe. This function tries to
+ * create pfd with the new API.
+ */
+static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs,
+ int pid, int cpu, int group_fd, int is_uprobe, int is_return)
+{
+ struct perf_event_attr attr = {};
+
+ attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
+ attr.config = is_return ? 1 : 0;
+ attr.probe_offset = offs; /* for kprobe, if name is NULL, this the addr */
+ attr.size = sizeof(attr)
+ if (is_uprobe) {
+ attr.type = PERF_TYPE_UPROBE;
+ attr.uprobe_path = ptr_to_u64((void *)name);
+ } else {
+ attr.type = PERF_TYPE_KPROBE;
+ attr.kprobe_func = ptr_to_u64((void *)name);
+ }
+ return syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd,
+ PERF_FLAG_FD_CLOEXEC);
+}
+
static int bpf_attach_tracing_event(int progfd, const char *event_path,
- struct perf_reader *reader, int pid, int cpu, int group_fd) {
- int efd, pfd;
+ struct perf_reader *reader, int pid, int cpu, int group_fd, int pfd) {
+ int efd;
ssize_t bytes;
char buf[256];
struct perf_event_attr attr = {};
- snprintf(buf, sizeof(buf), "%s/id", event_path);
- efd = open(buf, O_RDONLY, 0);
- if (efd < 0) {
- fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
- return -1;
- }
+ /*
+ * Only look up id and call perf_event_open when
+ * bpf_try_perf_event_open_with_probe() didn't returns valid pfd.
+ */
+ if (pfd < 0) {
+ snprintf(buf, sizeof(buf), "%s/id", event_path);
+ efd = open(buf, O_RDONLY, 0);
+ if (efd < 0) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ return -1;
+ }
- bytes = read(efd, buf, sizeof(buf));
- if (bytes <= 0 || bytes >= sizeof(buf)) {
- fprintf(stderr, "read(%s): %s\n", buf, strerror(errno));
+ bytes = read(efd, buf, sizeof(buf));
+ if (bytes <= 0 || bytes >= sizeof(buf)) {
+ fprintf(stderr, "read(%s): %s\n", buf, strerror(errno));
+ close(efd);
+ return -1;
+ }
close(efd);
- return -1;
- }
- close(efd);
- buf[bytes] = '\0';
- attr.config = strtol(buf, NULL, 0);
- attr.type = PERF_TYPE_TRACEPOINT;
- attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
- attr.sample_period = 1;
- attr.wakeup_events = 1;
- pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, PERF_FLAG_FD_CLOEXEC);
- if (pfd < 0) {
- fprintf(stderr, "perf_event_open(%s/id): %s\n", event_path, strerror(errno));
- return -1;
+ buf[bytes] = '\0';
+ attr.config = strtol(buf, NULL, 0);
+ attr.type = PERF_TYPE_TRACEPOINT;
+ attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
+ pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, PERF_FLAG_FD_CLOEXEC);
+ if (pfd < 0) {
+ fprintf(stderr, "perf_event_open(%s/id): %s\n", event_path, strerror(errno));
+ return -1;
+ }
}
+
perf_reader_set_fd(reader, pfd);
if (perf_reader_mmap(reader, attr.type, attr.sample_type) < 0)
@@ -585,31 +619,38 @@ void * bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type, con
char event_alias[128];
struct perf_reader *reader = NULL;
static char *event_type = "kprobe";
+ int pfd;
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt);
if (!reader)
goto error;
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
- kfd = open(buf, O_WRONLY | O_APPEND, 0);
- if (kfd < 0) {
- fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
- goto error;
- }
+ /* try use new API to create kprobe */
+ pfd = bpf_try_perf_event_open_with_probe(fn_name, 0, pid, cpu, group_fd, 0,
+ attach_type != BPF_PROBE_ENTRY);
- snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
- snprintf(buf, sizeof(buf), "%c:%ss/%s %s", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
- event_type, event_alias, fn_name);
- if (write(kfd, buf, strlen(buf)) < 0) {
- if (errno == EINVAL)
- fprintf(stderr, "check dmesg output for possible cause\n");
+ if (pfd < 0) {
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
+ kfd = open(buf, O_WRONLY | O_APPEND, 0);
+ if (kfd < 0) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ goto error;
+ }
+
+ snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
+ snprintf(buf, sizeof(buf), "%c:%ss/%s %s", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
+ event_type, event_alias, fn_name);
+ if (write(kfd, buf, strlen(buf)) < 0) {
+ if (errno == EINVAL)
+ fprintf(stderr, "check dmesg output for possible cause\n");
+ close(kfd);
+ goto error;
+ }
close(kfd);
- goto error;
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
}
- close(kfd);
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
- if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
+ if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd, pfd) < 0)
goto error;
return reader;
@@ -691,42 +732,50 @@ void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, con
struct perf_reader *reader = NULL;
static char *event_type = "uprobe";
int res, kfd = -1, ns_fd = -1;
+ int pfd;
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt);
if (!reader)
goto error;
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
- kfd = open(buf, O_WRONLY | O_APPEND, 0);
- if (kfd < 0) {
- fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
- goto error;
- }
+ /* try use new API to create uprobe */
+ pfd = bpf_try_perf_event_open_with_probe(binary_path, offset, pid, cpu,
+ group_fd, 1, attach_type != BPF_PROBE_ENTRY);
- res = snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
- if (res < 0 || res >= sizeof(event_alias)) {
- fprintf(stderr, "Event name (%s) is too long for buffer\n", ev_name);
- goto error;
- }
- res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
- event_type, event_alias, binary_path, offset);
- if (res < 0 || res >= sizeof(buf)) {
- fprintf(stderr, "Event alias (%s) too long for buffer\n", event_alias);
- goto error;
- }
+ if (pfd < 0) {
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
+ kfd = open(buf, O_WRONLY | O_APPEND, 0);
+ if (kfd < 0) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ goto error;
+ }
- ns_fd = enter_mount_ns(pid);
- if (write(kfd, buf, strlen(buf)) < 0) {
- if (errno == EINVAL)
- fprintf(stderr, "check dmesg output for possible cause\n");
- goto error;
+ res = snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
+ if (res < 0 || res >= sizeof(event_alias)) {
+ fprintf(stderr, "Event name (%s) is too long for buffer\n", ev_name);
+ goto error;
+ }
+ res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
+ event_type, event_alias, binary_path, offset);
+ if (res < 0 || res >= sizeof(buf)) {
+ fprintf(stderr, "Event alias (%s) too long for buffer\n", event_alias);
+ goto error;
+ }
+
+ ns_fd = enter_mount_ns(pid);
+ if (write(kfd, buf, strlen(buf)) < 0) {
+ if (errno == EINVAL)
+ fprintf(stderr, "check dmesg output for possible cause\n");
+ goto error;
+ }
+ close(kfd);
+ exit_mount_ns(ns_fd);
+ ns_fd = -1;
+
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
}
- close(kfd);
- exit_mount_ns(ns_fd);
- ns_fd = -1;
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
- if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
+ if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd, pfd) < 0)
goto error;
return reader;
@@ -741,8 +790,43 @@ error:
static int bpf_detach_probe(const char *ev_name, const char *event_type)
{
- int kfd, res;
+ int kfd = -1, res;
char buf[PATH_MAX];
+ int found_event = 0;
+ size_t bufsize = 0;
+ char *cptr = NULL;
+ FILE *fp;
+
+ /*
+ * For [k,u]probe created with perf_event_open (on newer kernel), it is
+ * not necessary to clean it up in [k,u]probe_events. We first look up
+ * the %s_bcc_%d line in [k,u]probe_events. If the event is not found,
+ * it is safe to skip the cleaning up process (write -:... to the file).
+ */
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
+ fp = fopen(buf, "r");
+ if (!fp) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ goto error;
+ }
+
+ res = snprintf(buf, sizeof(buf), "%ss/%s_bcc_%d", event_type, ev_name, getpid());
+ if (res < 0 || res >= sizeof(buf)) {
+ fprintf(stderr, "snprintf(%s): %d\n", ev_name, res);
+ goto error;
+ }
+
+ while (getline(&cptr, &bufsize, fp) != -1)
+ if (strstr(cptr, buf) != NULL) {
+ found_event = 1;
+ break;
+ }
+ fclose(fp);
+ fp = NULL;
+
+ if (!found_event)
+ return 0;
+
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
kfd = open(buf, O_WRONLY | O_APPEND, 0);
if (kfd < 0) {
@@ -766,6 +850,8 @@ static int bpf_detach_probe(const char *ev_name, const char *event_type)
error:
if (kfd >= 0)
close(kfd);
+ if (fp)
+ fclose(fp);
return -1;
}
@@ -792,7 +878,7 @@ void * bpf_attach_tracepoint(int progfd, const char *tp_category,
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/%s",
tp_category, tp_name);
- if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
+ if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd, -1) < 0)
goto error;
return reader;
--
2.9.5
^ permalink raw reply related
* [PATCH v2 0/6] enable creating [k,u]probe with perf_event_open
From: Song Liu @ 2017-11-30 1:44 UTC (permalink / raw)
To: peterz, rostedt, mingo, davem, netdev, linux-kernel, daniel
Cc: kernel-team, Song Liu
Changes PATCH v1 to PATCH v2:
Split PERF_TYPE_PROBE into PERF_TYPE_KPROBE and PERF_TYPE_UPROBE.
Split perf_probe into perf_kprobe and perf_uprobe.
Remove struct probe_desc, use config1 and config2 instead.
Changes RFC v2 to PATCH v1:
Check type PERF_TYPE_PROBE in perf_event_set_filter().
Rebase on to tip perf/core.
Changes RFC v1 to RFC v2:
Fix build issue reported by kbuild test bot by adding ifdef of
CONFIG_KPROBE_EVENTS, and CONFIG_UPROBE_EVENTS.
RFC v1 cover letter:
This is to follow up the discussion over "new kprobe api" at Linux
Plumbers 2017:
https://www.linuxplumbersconf.org/2017/ocw/proposals/4808
With current kernel, user space tools can only create/destroy [k,u]probes
with a text-based API (kprobe_events and uprobe_events in tracefs). This
approach relies on user space to clean up the [k,u]probe after using them.
However, this is not easy for user space to clean up properly.
To solve this problem, we introduce a file descriptor based API.
Specifically, we extended perf_event_open to create [k,u]probe, and attach
this [k,u]probe to the file descriptor created by perf_event_open. These
[k,u]probe are associated with this file descriptor, so they are not
available in tracefs.
We reuse large portion of existing trace_kprobe and trace_uprobe code.
Currently, the file descriptor API does not support arguments as the
text-based API does. This should not be a problem, as user of the file
decriptor based API read data through other methods (bpf, etc.).
I also include a patch to to bcc, and a patch to man-page perf_even_open.
Please see the list below. A fork of bcc with this patch is also available
on github:
https://github.com/liu-song-6/bcc/tree/perf_event_open
Thanks,
Song
man-pages patch:
perf_event_open.2: add type PERF_TYPE_KPROBE and PERF_TYPE_UPROBE
bcc patch:
bcc: Try use new API to create [k,u]probe with perf_event_open
kernel patches:
Song Liu (6):
perf: Add new types PERF_TYPE_KPROBE and PERF_TYPE_UPROBE
perf: copy new perf_event.h to tools/include/uapi
perf: implement support of PERF_TYPE_KPROBE
perf: implement support of PERF_TYPE_UPROBE
bpf: add option for bpf_load.c to use PERF_TYPE_KPROBE
bpf: add new test test_many_kprobe
include/linux/trace_events.h | 4 +
include/uapi/linux/perf_event.h | 8 ++
kernel/events/core.c | 76 +++++++++++++-
kernel/trace/trace_event_perf.c | 111 +++++++++++++++++++++
kernel/trace/trace_kprobe.c | 91 +++++++++++++++--
kernel/trace/trace_probe.h | 11 ++
kernel/trace/trace_uprobe.c | 90 +++++++++++++++--
samples/bpf/Makefile | 3 +
samples/bpf/bpf_load.c | 59 ++++++-----
samples/bpf/bpf_load.h | 12 +++
samples/bpf/test_many_kprobe_user.c | 182 ++++++++++++++++++++++++++++++++++
tools/include/uapi/linux/perf_event.h | 8 ++
12 files changed, 611 insertions(+), 44 deletions(-)
create mode 100644 samples/bpf/test_many_kprobe_user.c
--
2.9.5
^ permalink raw reply
* [PATCH net] tcp: remove buggy call to tcp_v6_restore_cb()
From: Eric Dumazet @ 2017-11-30 1:43 UTC (permalink / raw)
To: Florian Westphal; +Cc: netdev, David Miller
From: Eric Dumazet <edumazet@google.com>
tcp_v6_send_reset() expects to receive an skb with skb->cb[] layout as
used in TCP stack.
MD5 lookup uses tcp_v6_iif() and tcp_v6_sdif() and thus
TCP_SKB_CB(skb)->header.h6
This patch probably fixes RST packets sent on behalf of a timewait md5
ipv6 socket.
Before Florian patch, tcp_v6_restore_cb() was needed before jumping to
no_tcp_socket label.
Fixes: 271c3b9b7bda ("tcp: honour SO_BINDTODEVICE for TW_RST case too")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Florian Westphal <fw@strlen.de>
---
net/ipv6/tcp_ipv6.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 6bb98c93edfe2ed2f16fe5229605f8108cfc7f9a..be11dc13aa705145a83177e17d23594e9416e11a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1590,7 +1590,6 @@ static int tcp_v6_rcv(struct sk_buff *skb)
tcp_v6_timewait_ack(sk, skb);
break;
case TCP_TW_RST:
- tcp_v6_restore_cb(skb);
tcp_v6_send_reset(sk, skb);
inet_twsk_deschedule_put(inet_twsk(sk));
goto discard_it;
^ permalink raw reply related
* Re: [PATCH 1/6] perf: Add new type PERF_TYPE_PROBE
From: Song Liu @ 2017-11-30 1:43 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Steven Rostedt, mingo@redhat.com, David Miller,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
daniel@iogearbox.net, Kernel Team
In-Reply-To: <20171123102209.mqhrpaxym35eg7hq@hirez.programming.kicks-ass.net>
> On Nov 23, 2017, at 2:22 AM, Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Wed, Nov 15, 2017 at 09:23:33AM -0800, Song Liu wrote:
>> A new perf type PERF_TYPE_PROBE is added to allow creating [k,u]probe
>> with perf_event_open. These [k,u]probe are associated with the file
>> decriptor created by perf_event_open, thus are easy to clean when
>> the file descriptor is destroyed.
>>
>> Struct probe_desc and two flags, is_uprobe and is_return, are added
>> to describe the probe being created with perf_event_open.
>
>> ---
>> include/uapi/linux/perf_event.h | 35 +++++++++++++++++++++++++++++++++--
>> 1 file changed, 33 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
>> index 362493a..cc42d59 100644
>> --- a/include/uapi/linux/perf_event.h
>> +++ b/include/uapi/linux/perf_event.h
>> @@ -33,6 +33,7 @@ enum perf_type_id {
>> PERF_TYPE_HW_CACHE = 3,
>> PERF_TYPE_RAW = 4,
>> PERF_TYPE_BREAKPOINT = 5,
>> + PERF_TYPE_PROBE = 6,
>
> Not required.. these fixed types are mostly legacy at this point.
Dear Peter,
Thanks a lot for your feedback. I have incorporated them in the next version
(sending soon).
I added two fixed types (PERF_TYPE_KPROBE and PERF_TYPE_UPROBE) in the new
version. I know that perf doesn't need them any more. But currently bcc still
relies on these fixed types to use the probes/tracepoints.
Thanks,
Song
^ permalink raw reply
* [PATCH resend] trace/xdp: fix compile warning: 'struct bpf_map' declared inside parameter list
From: Xie XiuQi @ 2017-11-30 1:41 UTC (permalink / raw)
To: rostedt, mingo, davem, brouer, daniel
Cc: netdev, ast, kstewart, gregkh, john.fastabend, linux-kernel,
xiexiuqi, huangdaode, Hanjun Guo
We meet this compile warning, which caused by missing bpf.h in xdp.h.
In file included from ./include/trace/events/xdp.h:10:0,
from ./include/linux/bpf_trace.h:6,
from drivers/net/ethernet/intel/i40e/i40e_txrx.c:29:
./include/trace/events/xdp.h:93:17: warning: ‘struct bpf_map’ declared inside parameter list will not be visible outside of this definition or declaration
const struct bpf_map *map, u32 map_index),
^
./include/linux/tracepoint.h:187:34: note: in definition of macro ‘__DECLARE_TRACE’
static inline void trace_##name(proto) \
^~~~~
./include/linux/tracepoint.h:352:24: note: in expansion of macro ‘PARAMS’
__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \
^~~~~~
./include/linux/tracepoint.h:477:2: note: in expansion of macro ‘DECLARE_TRACE’
DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
^~~~~~~~~~~~~
./include/linux/tracepoint.h:477:22: note: in expansion of macro ‘PARAMS’
DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
^~~~~~
./include/trace/events/xdp.h:89:1: note: in expansion of macro ‘DEFINE_EVENT’
DEFINE_EVENT(xdp_redirect_template, xdp_redirect,
^~~~~~~~~~~~
./include/trace/events/xdp.h:90:2: note: in expansion of macro ‘TP_PROTO’
TP_PROTO(const struct net_device *dev,
^~~~~~~~
./include/trace/events/xdp.h:93:17: warning: ‘struct bpf_map’ declared inside parameter list will not be visible outside of this definition or declaration
const struct bpf_map *map, u32 map_index),
^
./include/linux/tracepoint.h:203:38: note: in definition of macro ‘__DECLARE_TRACE’
register_trace_##name(void (*probe)(data_proto), void *data) \
^~~~~~~~~~
./include/linux/tracepoint.h:354:4: note: in expansion of macro ‘PARAMS’
PARAMS(void *__data, proto), \
^~~~~~
Reported-by: Huang Daode <huangdaode@hisilicon.com>
Cc: Hanjun Guo <guohanjun@huawei.com>
Fixes: 8d3b778ff544 ("xdp: tracepoint xdp_redirect also need a map argument")
Signed-off-by: Xie XiuQi <xiexiuqi@huawei.com>
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
include/trace/events/xdp.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/trace/events/xdp.h b/include/trace/events/xdp.h
index 4cd0f05..8989a92 100644
--- a/include/trace/events/xdp.h
+++ b/include/trace/events/xdp.h
@@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include <linux/filter.h>
#include <linux/tracepoint.h>
+#include <linux/bpf.h>
#define __XDP_ACT_MAP(FN) \
FN(ABORTED) \
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH] [RFC v3] packet: experimental support for 64-bit timestamps
From: Willem de Bruijn @ 2017-11-30 1:39 UTC (permalink / raw)
To: Arnd Bergmann
Cc: David S. Miller, Willem de Bruijn, Björn Töpel,
Richard Cochran, Thomas Gleixner, Mike Maloney, Eric Dumazet,
Kees Cook, Hans Liljestrand, Andrey Konovalov, Rosen, Rami,
Reshetova, Elena, Sowmini Varadhan, Network Development, LKML
In-Reply-To: <CAK8P3a14x_1fFRdS0avr-abCem+TZas7jknH_o+93aNtvtiTAw@mail.gmail.com>
On Wed, Nov 29, 2017 at 3:06 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Wed, Nov 29, 2017 at 5:51 PM, Willem de Bruijn
> <willemdebruijn.kernel@gmail.com> wrote:
>>> Thanks for the review! Any suggestions for how to do the testing? If you have
>>> existing test cases, could you give my next version a test run to see if there
>>> are any regressions and if the timestamps work as expected?
>>>
>>> I see that there are test cases in tools/testing/selftests/net/, but none
>>> of them seem to use the time stamps so far, and I'm not overly familiar
>>> with how it works in the details to extend it in a meaningful way.
>>
>> I could not find any good tests for this interface, either. The only
>> user of the interface I found was a little tool I wrote a few years
>> ago that compares timestamps at multiple points in the transmit
>> path for latency measurement [1]. But it may be easier to just write
>> a new test under tools/testing/selftests/net for this purpose. I can
>> help with that, too, if you want.
>
> Thanks, that would be great!
I'll reply to this thread with git send-email with an extension to
tools/testing/selftests/net/psock_tpacket.c. I can resend that for
submission after your feature is merged (as it depends on it) or
feel free to include it in your patchset. The test currently fails for
the ns64 case. I probably did not convert correctly, but have to leave
the office and want to send what I have.
Two other comments: the test crashed the kernel due to a NULL ptr
in tpacket_get_timestamp. We cannot rely on skb->sk being set to
the packet socket here. And assignment to bitfield requires a cast to
boolean.
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index f55f330ab547..e9decc7fc5c3 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -439,9 +439,9 @@ static int __packet_get_status(struct packet_sock
*po, void *frame)
}
}
-static __u32 tpacket_get_timestamp(struct sk_buff *skb, __u32 *hi, __u32 *lo)
+static __u32 tpacket_get_timestamp(struct packet_sock *po, struct sk_buff *skb,
+ __u32 *hi, __u32 *lo)
{
- struct packet_sock *po = pkt_sk(skb->sk);
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
ktime_t stamp;
u32 type;
@@ -508,7 +508,7 @@ static __u32 __packet_set_timestamp(struct
packet_sock *po, void *frame,
union tpacket_uhdr h;
__u32 ts_status, hi, lo;
- if (!(ts_status = tpacket_get_timestamp(skb, &hi, &lo)))
+ if (!(ts_status = tpacket_get_timestamp(po, skb, &hi, &lo)))
return 0;
h.raw = frame;
@@ -2352,7 +2352,7 @@ static int tpacket_rcv(struct sk_buff *skb,
struct net_device *dev,
skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
- if (!(ts_status = tpacket_get_timestamp(skb, &tstamp_hi, &tstamp_lo)))
+ if (!(ts_status = tpacket_get_timestamp(po, skb, &tstamp_hi,
&tstamp_lo)))
packet_get_time(po, &tstamp_hi, &tstamp_lo);
status |= ts_status;
@@ -3835,7 +3835,7 @@ packet_setsockopt(struct socket *sock, int
level, int optname, char __user *optv
if (copy_from_user(&val, optval, sizeof(val)))
return -EFAULT;
- po->tp_skiptstamp = val;
+ po->tp_skiptstamp = !!val;
return 0;
}
case PACKET_TIMESTAMP_NS64:
@@ -3847,7 +3847,7 @@ packet_setsockopt(struct socket *sock, int
level, int optname, char __user *optv
if (copy_from_user(&val, optval, sizeof(val)))
return -EFAULT;
- po->tp_tstamp_ns64 = val;
+ po->tp_tstamp_ns64 = !!val;
return 0;
}
case PACKET_FANOUT:
^ permalink raw reply related
* Re: [PATCH] trace/xdp: fix compile warning: ‘struct bpf_map’ declared inside parameter list
From: Xie XiuQi @ 2017-11-30 1:28 UTC (permalink / raw)
To: Daniel Borkmann, Jesper Dangaard Brouer
Cc: rostedt, mingo, davem, ast, kstewart, gregkh, john.fastabend,
linux-kernel, huangdaode, Hanjun Guo, netdev@vger.kernel.org
In-Reply-To: <1a544a0e-3dae-9b3c-338a-6267cddfc477@iogearbox.net>
On 2017/11/29 19:13, Daniel Borkmann wrote:
> Xie, thanks for the patch! We could route this fix via bpf tree if you want.
>
> Could you resend your patch with below Fixes and Acked-by tag added to
> netdev@vger.kernel.org in Cc, so that it ends up in patchwork there?
>
Sure, I'll resend soon.
>> Fixes: 8d3b778ff544 ("xdp: tracepoint xdp_redirect also need a map argument")
>>
>> Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
> Thanks,
> Daniel
--
Thanks,
Xie XiuQi
^ permalink raw reply
* Re: [PATCH v5 next 3/5] modules:capabilities: automatic module loading restriction
From: Luis R. Rodriguez @ 2017-11-30 1:23 UTC (permalink / raw)
To: Djalal Harouni
Cc: Kees Cook, Andy Lutomirski, Andrew Morton, Luis R. Rodriguez,
James Morris, Ben Hutchings, Solar Designer, Serge Hallyn,
Jessica Yu, Rusty Russell, linux-kernel, linux-security-module,
kernel-hardening, Jonathan Corbet, Ingo Molnar, David S. Miller,
netdev, Peter Zijlstra, Linus Torvalds
In-Reply-To: <1511803118-2552-4-git-send-email-tixxdz@gmail.com>
On Mon, Nov 27, 2017 at 06:18:36PM +0100, Djalal Harouni wrote:
> diff --git a/include/linux/module.h b/include/linux/module.h
> index 5cbb239..c36aed8 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -261,7 +261,16 @@ struct notifier_block;
>
> #ifdef CONFIG_MODULES
>
> -extern int modules_disabled; /* for sysctl */
> +enum {
> + MODULES_AUTOLOAD_ALLOWED = 0,
> + MODULES_AUTOLOAD_PRIVILEGED = 1,
> + MODULES_AUTOLOAD_DISABLED = 2,
> +};
> +
Can you kdocify these and add a respective rst doc file? Maybe stuff your
extensive docs which you are currently adding to
Documentation/sysctl/kernel.txt to this new file and in kernel.txt just refer
to it. This way this can be also nicely visibly documented on the web with the
new sphinx.
This way you can take advantage of the kdocs you are already adding and refer
to them.
> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> index 2fb4e27..0b6f0c8 100644
> --- a/kernel/sysctl.c
> +++ b/kernel/sysctl.c
> @@ -683,6 +688,15 @@ static struct ctl_table kern_table[] = {
> .extra1 = &one,
> .extra2 = &one,
> },
> + {
> + .procname = "modules_autoload_mode",
> + .data = &modules_autoload_mode,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = modules_autoload_dointvec_minmax,
It would seem this is a unint ... so why not reflect that?
> @@ -2499,6 +2513,20 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write,
> }
> #endif
>
> +#ifdef CONFIG_MODULES
> +static int modules_autoload_dointvec_minmax(struct ctl_table *table, int write,
> + void __user *buffer, size_t *lenp, loff_t *ppos)
> +{
> + /*
> + * Only CAP_SYS_MODULE in init user namespace are allowed to change this
> + */
> + if (write && !capable(CAP_SYS_MODULE))
> + return -EPERM;
> +
> + return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> +}
> +#endif
We now have proc_douintvec_minmax().
Luis
^ permalink raw reply
* Re: [PATCH net 0/6] tools: bpftool: fix a minor issues with JSON and Makefiles
From: Daniel Borkmann @ 2017-11-30 1:17 UTC (permalink / raw)
To: Jakub Kicinski, netdev; +Cc: oss-drivers
In-Reply-To: <20171129014434.31694-1-jakub.kicinski@netronome.com>
On 11/29/2017 02:44 AM, Jakub Kicinski wrote:
> Quentin says:
>
> First commit in this series fixes a crash that occurs when incorrect
> arguments are passed to bpftool after the `--json` option. It comes from
> the usage() function trying to use the JSON writer, although the latter
> has not been created yet at that point.
>
> Other patches add destruction of the writer in case the program exits in
> usage(), fix error messages handling when an unrecognized option is
> encountered, remove a spurious new-line character in an error message.
>
> Last patches are related to the Makefiles. They fix the installation
> directory prefix and .PHONY targets.
Applied to bpf tree, thanks guys!
^ permalink raw reply
* Re: [PATCH RFC 2/2] veth: propagate bridge GSO to peer
From: Solio Sarabia @ 2017-11-30 0:35 UTC (permalink / raw)
To: David Ahern, stephen; +Cc: davem, netdev, sthemmin, shiny.sebastian
In-Reply-To: <91628267-2e48-a231-7cc2-4830eb95ceef@gmail.com>
On Mon, Nov 27, 2017 at 07:02:01PM -0700, David Ahern wrote:
> On 11/27/17 6:42 PM, Solio Sarabia wrote:
> > Adding ioctl support for 'ip link set' would work. I'm still concerned
> > how to enforce the upper limit to not exceed that of the lower devices.
> >
Actually, giving the user control to change gso doesn't solve the issue.
In a VM, user could simple ignore setting the gso, still hurting host
perf. We need to enforce the lower gso on the bridge/veth.
Should this issue be fixed at hv_netvsc level? Why is the driver passing
down gso buffer sizes greater than what synthetic interface allows.
> > Consider a system with three NICs, each reporting values in the range
> > [60,000 - 62,780]. Users could set virtual interfaces' gso to 65,536,
> > exceeding the limit, and having the host do sw gso (vms settings must
> > not affect host performance.)
> >
> > Looping through interfaces? With the difference that now it'd be
> > trigger upon user's request, not every time a veth is created (like one
> > previous patch discussed.)
> >
>
> You are concerned about the routed case right? One option is to have VRF
> devices propagate gso sizes to all devices (veth, vlan, etc) enslaved to
> it. VRF devices are Layer 3 master devices so an L3 parallel to a bridge.
Having the VRF device propagate the gso to its slaves is opposite of
what we do now: get minimum of all ports and assign it to bridge
(net/bridge/br_if.c, br_min_mtu, br_set_gso_limits.)
Would it be right to change the logic flow? If so, this this could work:
(1) bridge gets gso from lower devices upon init/setup
(2) when new device is attached to bridge, bridge sets gso for this new
slave (and its peer if it's veth.)
(3) as the code is now, there's an optimization opportunity: for every
new interface attached to bridge, bridge loops through all ports to
set gso, mtu. It's not necessary as bridge already has the minimum
from previous interfaces attached. Could be O(1) instead of O(n).
^ permalink raw reply
* Re: [PATCH v5 next 1/5] modules:capabilities: add request_module_cap()
From: Theodore Ts'o @ 2017-11-30 0:35 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: David Miller, gnomes, keescook, mcgrof, tixxdz, luto, akpm,
james.l.morris, ben.hutchings, solar, jeyu, rusty, linux-kernel,
linux-security-module, kernel-hardening, corbet, mingo, netdev,
peterz, torvalds
In-Reply-To: <20171129172852.GA14545@mail.hallyn.com>
On Wed, Nov 29, 2017 at 11:28:52AM -0600, Serge E. Hallyn wrote:
>
> Just to be clear, module loading requires - and must always continue to
> require - CAP_SYS_MODULE against the initial user namespace. Containers
> in user namespaces do not have that.
>
> I don't believe anyone has ever claimed that containers which are not in
> a user namespace are in any way secure.
Unless the container performs some action which causes the kernel to
call request_module(), which then loads some kernel module,
potentially containing cr*p unmaintained code which was included when
the distro compiled the world, into the host kernel.
This is an attack vector that doesn't exist if you are using VM's.
And in general, the attack surface of the entire Linux
kernel<->userspace API is far larger than that which is exposed by the
guest<->host interface.
For that reason, containers are *far* more insecure than VM's, since
once the attacker gets root on the guest VM, they then have to attack
the hypervisor interface. And if you compare the attack surface of
the two, it's pretty clear which is larger, and it's not the
hypervisor interface.
- Ted
^ permalink raw reply
* Re: [BUG] kernel stack corruption during/after Netlabel error
From: James Morris @ 2017-11-30 0:31 UTC (permalink / raw)
To: Casey Schaufler
Cc: Paul Moore, Eric Dumazet, netdev, Stephen Smalley, selinux, LSM
In-Reply-To: <4d73f839-7a86-6edc-b44b-e296bd5947c2@schaufler-ca.com>
On Wed, 29 Nov 2017, Casey Schaufler wrote:
> I see that there is a proposed fix later in the thread, but I don't see
> the patch. Could you send it to me, so I can try it on my problem?
Forwarded off-list.
Interestingly, I didn't see the KASAN output email from Stephen here.
--
James Morris
<james.l.morris@oracle.com>
^ permalink raw reply
* [RFC] bpf: offload: report device information for offloaded programs
From: Jakub Kicinski @ 2017-11-30 0:22 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, oss-drivers, alexei.starovoitov, daniel,
Eric W . Biederman, Kirill Tkhai, Jakub Kicinski
Report to the user ifindex and namespace information of offloaded
programs. Always set dev_bound to true if program was loaded for
a device which has been since removed. Specify the namespace
using dev/inode combination.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
fs/nsfs.c | 2 +-
include/linux/bpf.h | 2 ++
include/linux/proc_ns.h | 1 +
include/uapi/linux/bpf.h | 5 +++++
kernel/bpf/offload.c | 34 ++++++++++++++++++++++++++++++++++
kernel/bpf/syscall.c | 6 ++++++
tools/include/uapi/linux/bpf.h | 5 +++++
7 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/fs/nsfs.c b/fs/nsfs.c
index ef243e14b6eb..d2b89372544a 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -51,7 +51,7 @@ static void nsfs_evict(struct inode *inode)
ns->ops->put(ns);
}
-static void *__ns_get_path(struct path *path, struct ns_common *ns)
+void *__ns_get_path(struct path *path, struct ns_common *ns)
{
struct vfsmount *mnt = nsfs_mnt;
struct dentry *dentry;
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index e55e4255a210..fc7ab26e10bf 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -516,6 +516,8 @@ static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
int bpf_prog_offload_compile(struct bpf_prog *prog);
void bpf_prog_offload_destroy(struct bpf_prog *prog);
+int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
+ struct bpf_prog *prog);
#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr);
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index 2ff18c9840a7..1733359cf713 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -76,6 +76,7 @@ static inline int ns_alloc_inum(struct ns_common *ns)
extern struct file *proc_ns_fget(int fd);
#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private)
+extern void *__ns_get_path(struct path *path, struct ns_common *ns);
extern void *ns_get_path(struct path *path, struct task_struct *task,
const struct proc_ns_operations *ns_ops);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 4c223ab30293..3183674496a2 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -910,6 +910,11 @@ struct bpf_prog_info {
__u32 nr_map_ids;
__aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN];
+ __u32 dev_bound:1;
+ __u32 reserved:31;
+ __u32 ifindex;
+ __u64 ns_dev;
+ __u64 ns_inode;
} __attribute__((aligned(8)));
struct bpf_map_info {
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index 8455b89d1bbf..da98349c647d 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -16,9 +16,11 @@
#include <linux/bpf.h>
#include <linux/bpf_verifier.h>
#include <linux/bug.h>
+#include <linux/kdev_t.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
+#include <linux/proc_ns.h>
#include <linux/rtnetlink.h>
/* protected by RTNL */
@@ -164,6 +166,38 @@ int bpf_prog_offload_compile(struct bpf_prog *prog)
return bpf_prog_offload_translate(prog);
}
+int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
+ struct bpf_prog *prog)
+{
+ struct bpf_dev_offload *offload = prog->aux->offload;
+ struct inode *ns_inode;
+ struct path ns_path;
+ struct net *net;
+ int ret = 0;
+ void *ptr;
+
+ info->dev_bound = 1;
+
+ rtnl_lock();
+ if (!offload->netdev)
+ goto out;
+
+ net = dev_net(offload->netdev);
+ get_net(net); /* __ns_get_path() drops the reference */
+ ptr = __ns_get_path(&ns_path, &net->ns);
+ ret = PTR_ERR_OR_ZERO(ptr);
+ if (ret)
+ goto out;
+ ns_inode = ns_path.dentry->d_inode;
+
+ info->ns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
+ info->ns_inode = ns_inode->i_ino;
+ info->ifindex = offload->netdev->ifindex;
+out:
+ rtnl_unlock();
+ return ret;
+}
+
const struct bpf_prog_ops bpf_offload_prog_ops = {
};
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 2c4cfeaa8d5e..101ee3a3e80e 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1616,6 +1616,12 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
return -EFAULT;
}
+ if (bpf_prog_is_dev_bound(prog->aux)) {
+ err = bpf_prog_offload_info_fill(&info, prog);
+ if (err)
+ return err;
+ }
+
done:
if (copy_to_user(uinfo, &info, info_len) ||
put_user(info_len, &uattr->info.info_len))
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 4c223ab30293..3183674496a2 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -910,6 +910,11 @@ struct bpf_prog_info {
__u32 nr_map_ids;
__aligned_u64 map_ids;
char name[BPF_OBJ_NAME_LEN];
+ __u32 dev_bound:1;
+ __u32 reserved:31;
+ __u32 ifindex;
+ __u64 ns_dev;
+ __u64 ns_inode;
} __attribute__((aligned(8)));
struct bpf_map_info {
--
2.14.1
^ permalink raw reply related
* Re: [BUG] kernel stack corruption during/after Netlabel error
From: Casey Schaufler @ 2017-11-30 0:22 UTC (permalink / raw)
To: James Morris, Paul Moore, Eric Dumazet
Cc: netdev, Stephen Smalley, selinux, LSM
In-Reply-To: <alpine.LFD.2.20.1711292113350.7808@localhost>
On 11/29/2017 2:26 AM, James Morris wrote:
> I'm seeing a kernel stack corruption bug (detected via gcc) when running
> the SELinux testsuite on a 4.15-rc1 kernel, in the 2nd inet_socket test:
>
> https://github.com/SELinuxProject/selinux-testsuite/blob/master/tests/inet_socket/test
>
> # Verify that unauthorized client cannot communicate with the server.
> $result = system
> "runcon -t test_inet_bad_client_t -- $basedir/client stream 127.0.0.1 65535 2>&1";
>
> This correctlly causes an access control error in the Netlabel code, and
> the bug seems to be triggered during the ICMP send:
>
> ...<SNIP>...
>
> This is mostly reliable, and I'm only seeing it on bare metal (not in a
> virtualbox vm).
>
> The SELinux skb parse error at the start only sometimes appears, and
> looking at the code, I suspect some kind of memory corruption being the
> cause at that point (basic packet header checks).
>
> I bisected the bug down to the following change:
>
> commit bffa72cf7f9df842f0016ba03586039296b4caaf
> Author: Eric Dumazet <edumazet@google.com>
> Date: Tue Sep 19 05:14:24 2017 -0700
>
> net: sk_buff rbnode reorg
> ...
>
>
> Anyone else able to reproduce this, or have any ideas on what's happening?
I have also bisected a problem to this change. I do not have a trace
because the problem manifests as a hard system hang without a trace
being presented. The issue arises when Smack attempts to relabel a TCP
socket using netlbl_sock_setattr().
I see that there is a proposed fix later in the thread, but I don't see
the patch. Could you send it to me, so I can try it on my problem?
Thank you.
>
>
>
> - James
^ permalink raw reply
* Re: [RFC 1/3] kallsyms: don't leak address when symbol not found
From: Tobin C. Harding @ 2017-11-30 0:16 UTC (permalink / raw)
To: Steven Rostedt
Cc: Tycho Andersen, Daniel Borkmann, Masahiro Yamada, David S. Miller,
Alexei Starovoitov, Network Development, linux-kernel,
kernel-hardening
In-Reply-To: <1511821819-5496-2-git-send-email-me@tobin.cc>
I reordered the To's and CC's, I hope this doesn't break
threading. (clearly I haven't groked email yet :( )
On Tue, Nov 28, 2017 at 09:30:17AM +1100, Tobin C. Harding wrote:
> Currently if kallsyms_lookup() fails to find the symbol then the address
> is printed. This potentially leaks sensitive information. Instead of
> printing the address we can return an error, giving the calling code the
> option to print the address or print some sanitized message.
>
> Return error instead of printing address to argument buffer. Leave
> buffer in a sane state.
>
> Signed-off-by: Tobin C. Harding <me@tobin.cc>
> ---
> kernel/kallsyms.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
> index 531ffa984bc2..4bfa4ee3ce93 100644
> --- a/kernel/kallsyms.c
> +++ b/kernel/kallsyms.c
> @@ -394,8 +394,10 @@ static int __sprint_symbol(char *buffer, unsigned long address,
>
> address += symbol_offset;
> name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
> - if (!name)
> - return sprintf(buffer, "0x%lx", address - symbol_offset);
> + if (!name) {
> + buffer[0] = '\0';
> + return -1;
> + }
>
> if (name != buffer)
> strcpy(buffer, name);
> --
> 2.7.4
>
Do you want a Suggested-by: tag for this patch Steve? I mentioned you in
the cover letter but as far as going into the git history I'm not
entirely sure on the protocol for adding suggested-by. The kernel docs
say not to add it without authorization, so ...
thanks,
Tobin.
^ permalink raw reply
* RE: [PATCH] sched/deadline: fix one-bit signed bitfields to be unsigned
From: Keller, Jacob E @ 2017-11-30 0:12 UTC (permalink / raw)
To: Jakub Kicinski, Kirsher, Jeffrey T
Cc: mingo@redhat.com, peterz@infradead.org,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
nhorman@redhat.com, sassmann@redhat.com, jogreene@redhat.com,
luca abeni
In-Reply-To: <20171128200726.1c806eb7@cakuba.netronome.com>
> -----Original Message-----
> From: Jakub Kicinski [mailto:kubakici@wp.pl]
> Sent: Tuesday, November 28, 2017 8:08 PM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>
> Cc: mingo@redhat.com; peterz@infradead.org; Keller, Jacob E
> <jacob.e.keller@intel.com>; linux-kernel@vger.kernel.org;
> netdev@vger.kernel.org; nhorman@redhat.com; sassmann@redhat.com;
> jogreene@redhat.com; luca abeni <luca.abeni@santannapisa.it>
> Subject: Re: [PATCH] sched/deadline: fix one-bit signed bitfields to be unsigned
>
> On Tue, 28 Nov 2017 12:36:19 -0800, Jeff Kirsher wrote:
> > From: Jacob Keller <jacob.e.keller@intel.com>
> >
> > Commit 799ba82de01e ("sched/deadline: Use C bitfields for the state
> > flags", 2017-10-10) introduced the use of C bitfields for these
> > variables. However, sparse complains about them:
> >
> > ./include/linux/sched.h:476:62: error: dubious one-bit signed bitfield
> > ./include/linux/sched.h:477:62: error: dubious one-bit signed bitfield
> > ./include/linux/sched.h:478:62: error: dubious one-bit signed bitfield
> > ./include/linux/sched.h:479:62: error: dubious one-bit signed bitfield
> >
> > This is because a one-bit signed bitfield can only hold the values 0 and
> > -1, which can cause problems if the program expects to be able to
> > represent the value positive 1.
> >
> > In practice, this may not cause a bug since -1 would be considered
> > "true" in logical tests, however we should avoid the practice anyways.
> >
> > Fixes: 799ba82de01e ("sched/deadline: Use C bitfields for the state flags", 2017-
> 10-10)
> > Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> > Cc: luca abeni <luca.abeni@santannapisa.it>
> > Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
> > Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
>
> This is already in Linus's tree (I've been waiting for it to land as
> well :))
>
Excellent.
Regards,
Jake
^ permalink raw reply
* [Patch net v2] act_sample: get rid of tcf_sample_cleanup_rcu()
From: Cong Wang @ 2017-11-30 0:07 UTC (permalink / raw)
To: netdev; +Cc: eric.dumazet, Cong Wang, Jamal Hadi Salim, Jiri Pirko, Yotam Gigi
Similar to commit d7fb60b9cafb ("net_sched: get rid of tcfa_rcu"),
TC actions don't need to respect RCU grace period, because it
is either just detached from tc filter (standalone case) or
it is removed together with tc filter (bound case) in which case
RCU grace period is already respected at filter layer.
Fixes: 5c5670fae430 ("net/sched: Introduce sample tc action")
Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Cc: Yotam Gigi <yotamg@mellanox.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
include/net/tc_act/tc_sample.h | 1 -
net/sched/act_sample.c | 14 +++-----------
2 files changed, 3 insertions(+), 12 deletions(-)
diff --git a/include/net/tc_act/tc_sample.h b/include/net/tc_act/tc_sample.h
index 524cee4f4c81..01dbfea32672 100644
--- a/include/net/tc_act/tc_sample.h
+++ b/include/net/tc_act/tc_sample.h
@@ -14,7 +14,6 @@ struct tcf_sample {
struct psample_group __rcu *psample_group;
u32 psample_group_num;
struct list_head tcfm_list;
- struct rcu_head rcu;
};
#define to_sample(a) ((struct tcf_sample *)a)
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 8b5abcd2f32f..9438969290a6 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -96,23 +96,16 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
return ret;
}
-static void tcf_sample_cleanup_rcu(struct rcu_head *rcu)
+static void tcf_sample_cleanup(struct tc_action *a, int bind)
{
- struct tcf_sample *s = container_of(rcu, struct tcf_sample, rcu);
+ struct tcf_sample *s = to_sample(a);
struct psample_group *psample_group;
- psample_group = rcu_dereference_protected(s->psample_group, 1);
+ psample_group = rtnl_dereference(s->psample_group);
RCU_INIT_POINTER(s->psample_group, NULL);
psample_group_put(psample_group);
}
-static void tcf_sample_cleanup(struct tc_action *a, int bind)
-{
- struct tcf_sample *s = to_sample(a);
-
- call_rcu(&s->rcu, tcf_sample_cleanup_rcu);
-}
-
static bool tcf_sample_dev_ok_push(struct net_device *dev)
{
switch (dev->type) {
@@ -264,7 +257,6 @@ static int __init sample_init_module(void)
static void __exit sample_cleanup_module(void)
{
- rcu_barrier();
tcf_unregister_action(&act_sample_ops, &sample_net_ops);
}
--
2.13.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox