diff options
Diffstat (limited to 'samples')
| -rw-r--r-- | samples/bpf/Makefile | 4 | ||||
| -rw-r--r-- | samples/bpf/bpf_helpers.h | 27 | ||||
| -rw-r--r-- | samples/bpf/test_verifier.c | 59 | ||||
| -rw-r--r-- | samples/bpf/tracex1_kern.c | 2 | ||||
| -rw-r--r-- | samples/bpf/tracex2_kern.c | 6 | ||||
| -rw-r--r-- | samples/bpf/tracex3_kern.c | 4 | ||||
| -rw-r--r-- | samples/bpf/tracex4_kern.c | 6 | ||||
| -rw-r--r-- | samples/bpf/tracex5_kern.c | 6 | ||||
| -rw-r--r-- | samples/bpf/tracex6_kern.c | 27 | ||||
| -rw-r--r-- | samples/bpf/tracex6_user.c | 72 | ||||
| -rw-r--r-- | samples/trace_events/trace-events-sample.h | 7 | 
11 files changed, 206 insertions, 14 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 4450fed91ab4..63e7d50e6a4f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -12,6 +12,7 @@ hostprogs-y += tracex2  hostprogs-y += tracex3  hostprogs-y += tracex4  hostprogs-y += tracex5 +hostprogs-y += tracex6  hostprogs-y += lathist  test_verifier-objs := test_verifier.o libbpf.o @@ -25,6 +26,7 @@ tracex2-objs := bpf_load.o libbpf.o tracex2_user.o  tracex3-objs := bpf_load.o libbpf.o tracex3_user.o  tracex4-objs := bpf_load.o libbpf.o tracex4_user.o  tracex5-objs := bpf_load.o libbpf.o tracex5_user.o +tracex6-objs := bpf_load.o libbpf.o tracex6_user.o  lathist-objs := bpf_load.o libbpf.o lathist_user.o  # Tell kbuild to always build the programs @@ -37,6 +39,7 @@ always += tracex2_kern.o  always += tracex3_kern.o  always += tracex4_kern.o  always += tracex5_kern.o +always += tracex6_kern.o  always += tcbpf1_kern.o  always += lathist_kern.o @@ -51,6 +54,7 @@ HOSTLOADLIBES_tracex2 += -lelf  HOSTLOADLIBES_tracex3 += -lelf  HOSTLOADLIBES_tracex4 += -lelf -lrt  HOSTLOADLIBES_tracex5 += -lelf +HOSTLOADLIBES_tracex6 += -lelf  HOSTLOADLIBES_lathist += -lelf  # point this to your LLVM backend with bpf support diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index bdf1c1607b80..3a44d3a272af 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -31,6 +31,8 @@ static unsigned long long (*bpf_get_current_uid_gid)(void) =  	(void *) BPF_FUNC_get_current_uid_gid;  static int (*bpf_get_current_comm)(void *buf, int buf_size) =  	(void *) BPF_FUNC_get_current_comm; +static int (*bpf_perf_event_read)(void *map, int index) = +	(void *) BPF_FUNC_perf_event_read;  /* llvm builtin functions that eBPF C program may use to   * emit BPF_LD_ABS and BPF_LD_IND instructions @@ -60,4 +62,29 @@ static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flag  static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) =  	(void *) BPF_FUNC_l4_csum_replace; +#if defined(__x86_64__) + +#define PT_REGS_PARM1(x) ((x)->di) +#define PT_REGS_PARM2(x) ((x)->si) +#define PT_REGS_PARM3(x) ((x)->dx) +#define PT_REGS_PARM4(x) ((x)->cx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->sp) +#define PT_REGS_FP(x) ((x)->bp) +#define PT_REGS_RC(x) ((x)->ax) +#define PT_REGS_SP(x) ((x)->sp) + +#elif defined(__s390x__) + +#define PT_REGS_PARM1(x) ((x)->gprs[2]) +#define PT_REGS_PARM2(x) ((x)->gprs[3]) +#define PT_REGS_PARM3(x) ((x)->gprs[4]) +#define PT_REGS_PARM4(x) ((x)->gprs[5]) +#define PT_REGS_PARM5(x) ((x)->gprs[6]) +#define PT_REGS_RET(x) ((x)->gprs[14]) +#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->gprs[2]) +#define PT_REGS_SP(x) ((x)->gprs[15]) + +#endif  #endif diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 693605997abc..ee0f110c9c54 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c @@ -822,6 +822,65 @@ static struct bpf_test tests[] = {  		.result = ACCEPT,  		.prog_type = BPF_PROG_TYPE_SCHED_CLS,  	}, +	{ +		"PTR_TO_STACK store/load", +		.insns = { +			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10), +			BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c), +			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2), +			BPF_EXIT_INSN(), +		}, +		.result = ACCEPT, +	}, +	{ +		"PTR_TO_STACK store/load - bad alignment on off", +		.insns = { +			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), +			BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c), +			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2), +			BPF_EXIT_INSN(), +		}, +		.result = REJECT, +		.errstr = "misaligned access off -6 size 8", +	}, +	{ +		"PTR_TO_STACK store/load - bad alignment on reg", +		.insns = { +			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10), +			BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), +			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), +			BPF_EXIT_INSN(), +		}, +		.result = REJECT, +		.errstr = "misaligned access off -2 size 8", +	}, +	{ +		"PTR_TO_STACK store/load - out of bounds low", +		.insns = { +			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -80000), +			BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), +			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), +			BPF_EXIT_INSN(), +		}, +		.result = REJECT, +		.errstr = "invalid stack off=-79992 size=8", +	}, +	{ +		"PTR_TO_STACK store/load - out of bounds high", +		.insns = { +			BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), +			BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), +			BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), +			BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), +			BPF_EXIT_INSN(), +		}, +		.result = REJECT, +		.errstr = "invalid stack off=0 size=8", +	},  };  static int probe_filter_length(struct bpf_insn *fp) diff --git a/samples/bpf/tracex1_kern.c b/samples/bpf/tracex1_kern.c index 31620463701a..3f450a8fa1f3 100644 --- a/samples/bpf/tracex1_kern.c +++ b/samples/bpf/tracex1_kern.c @@ -29,7 +29,7 @@ int bpf_prog1(struct pt_regs *ctx)  	int len;  	/* non-portable! works for the given kernel only */ -	skb = (struct sk_buff *) ctx->di; +	skb = (struct sk_buff *) PT_REGS_PARM1(ctx);  	dev = _(skb->dev); diff --git a/samples/bpf/tracex2_kern.c b/samples/bpf/tracex2_kern.c index dc50f4f2943f..b32367cfbff4 100644 --- a/samples/bpf/tracex2_kern.c +++ b/samples/bpf/tracex2_kern.c @@ -27,10 +27,10 @@ int bpf_prog2(struct pt_regs *ctx)  	long init_val = 1;  	long *value; -	/* x64 specific: read ip of kfree_skb caller. +	/* x64/s390x specific: read ip of kfree_skb caller.  	 * non-portable version of __builtin_return_address(0)  	 */ -	bpf_probe_read(&loc, sizeof(loc), (void *)ctx->sp); +	bpf_probe_read(&loc, sizeof(loc), (void *)PT_REGS_RET(ctx));  	value = bpf_map_lookup_elem(&my_map, &loc);  	if (value) @@ -79,7 +79,7 @@ struct bpf_map_def SEC("maps") my_hist_map = {  SEC("kprobe/sys_write")  int bpf_prog3(struct pt_regs *ctx)  { -	long write_size = ctx->dx; /* arg3 */ +	long write_size = PT_REGS_PARM3(ctx);  	long init_val = 1;  	long *value;  	struct hist_key key = {}; diff --git a/samples/bpf/tracex3_kern.c b/samples/bpf/tracex3_kern.c index 255ff2792366..bf337fbb0947 100644 --- a/samples/bpf/tracex3_kern.c +++ b/samples/bpf/tracex3_kern.c @@ -23,7 +23,7 @@ struct bpf_map_def SEC("maps") my_map = {  SEC("kprobe/blk_mq_start_request")  int bpf_prog1(struct pt_regs *ctx)  { -	long rq = ctx->di; +	long rq = PT_REGS_PARM1(ctx);  	u64 val = bpf_ktime_get_ns();  	bpf_map_update_elem(&my_map, &rq, &val, BPF_ANY); @@ -51,7 +51,7 @@ struct bpf_map_def SEC("maps") lat_map = {  SEC("kprobe/blk_update_request")  int bpf_prog2(struct pt_regs *ctx)  { -	long rq = ctx->di; +	long rq = PT_REGS_PARM1(ctx);  	u64 *value, l, base;  	u32 index; diff --git a/samples/bpf/tracex4_kern.c b/samples/bpf/tracex4_kern.c index 126b80512228..ac4671420cf1 100644 --- a/samples/bpf/tracex4_kern.c +++ b/samples/bpf/tracex4_kern.c @@ -27,7 +27,7 @@ struct bpf_map_def SEC("maps") my_map = {  SEC("kprobe/kmem_cache_free")  int bpf_prog1(struct pt_regs *ctx)  { -	long ptr = ctx->si; +	long ptr = PT_REGS_PARM2(ctx);  	bpf_map_delete_elem(&my_map, &ptr);  	return 0; @@ -36,11 +36,11 @@ int bpf_prog1(struct pt_regs *ctx)  SEC("kretprobe/kmem_cache_alloc_node")  int bpf_prog2(struct pt_regs *ctx)  { -	long ptr = ctx->ax; +	long ptr = PT_REGS_RC(ctx);  	long ip = 0;  	/* get ip address of kmem_cache_alloc_node() caller */ -	bpf_probe_read(&ip, sizeof(ip), (void *)(ctx->bp + sizeof(ip))); +	bpf_probe_read(&ip, sizeof(ip), (void *)(PT_REGS_FP(ctx) + sizeof(ip)));  	struct pair v = {  		.val = bpf_ktime_get_ns(), diff --git a/samples/bpf/tracex5_kern.c b/samples/bpf/tracex5_kern.c index b71fe07a7a7a..b3f4295bf288 100644 --- a/samples/bpf/tracex5_kern.c +++ b/samples/bpf/tracex5_kern.c @@ -24,7 +24,7 @@ int bpf_prog1(struct pt_regs *ctx)  {  	struct seccomp_data sd = {}; -	bpf_probe_read(&sd, sizeof(sd), (void *)ctx->di); +	bpf_probe_read(&sd, sizeof(sd), (void *)PT_REGS_PARM1(ctx));  	/* dispatch into next BPF program depending on syscall number */  	bpf_tail_call(ctx, &progs, sd.nr); @@ -42,7 +42,7 @@ PROG(__NR_write)(struct pt_regs *ctx)  {  	struct seccomp_data sd = {}; -	bpf_probe_read(&sd, sizeof(sd), (void *)ctx->di); +	bpf_probe_read(&sd, sizeof(sd), (void *)PT_REGS_PARM1(ctx));  	if (sd.args[2] == 512) {  		char fmt[] = "write(fd=%d, buf=%p, size=%d)\n";  		bpf_trace_printk(fmt, sizeof(fmt), @@ -55,7 +55,7 @@ PROG(__NR_read)(struct pt_regs *ctx)  {  	struct seccomp_data sd = {}; -	bpf_probe_read(&sd, sizeof(sd), (void *)ctx->di); +	bpf_probe_read(&sd, sizeof(sd), (void *)PT_REGS_PARM1(ctx));  	if (sd.args[2] > 128 && sd.args[2] <= 1024) {  		char fmt[] = "read(fd=%d, buf=%p, size=%d)\n";  		bpf_trace_printk(fmt, sizeof(fmt), diff --git a/samples/bpf/tracex6_kern.c b/samples/bpf/tracex6_kern.c new file mode 100644 index 000000000000..be479c4af9e2 --- /dev/null +++ b/samples/bpf/tracex6_kern.c @@ -0,0 +1,27 @@ +#include <linux/ptrace.h> +#include <linux/version.h> +#include <uapi/linux/bpf.h> +#include "bpf_helpers.h" + +struct bpf_map_def SEC("maps") my_map = { +	.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, +	.key_size = sizeof(int), +	.value_size = sizeof(u32), +	.max_entries = 32, +}; + +SEC("kprobe/sys_write") +int bpf_prog1(struct pt_regs *ctx) +{ +	u64 count; +	u32 key = bpf_get_smp_processor_id(); +	char fmt[] = "CPU-%d   %llu\n"; + +	count = bpf_perf_event_read(&my_map, key); +	bpf_trace_printk(fmt, sizeof(fmt), key, count); + +	return 0; +} + +char _license[] SEC("license") = "GPL"; +u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/tracex6_user.c b/samples/bpf/tracex6_user.c new file mode 100644 index 000000000000..8ea4976cfcf1 --- /dev/null +++ b/samples/bpf/tracex6_user.c @@ -0,0 +1,72 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <fcntl.h> +#include <poll.h> +#include <sys/ioctl.h> +#include <linux/perf_event.h> +#include <linux/bpf.h> +#include "libbpf.h" +#include "bpf_load.h" + +#define SAMPLE_PERIOD  0x7fffffffffffffffULL + +static void test_bpf_perf_event(void) +{ +	int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); +	int *pmu_fd = malloc(nr_cpus * sizeof(int)); +	int status, i; + +	struct perf_event_attr attr_insn_pmu = { +		.freq = 0, +		.sample_period = SAMPLE_PERIOD, +		.inherit = 0, +		.type = PERF_TYPE_HARDWARE, +		.read_format = 0, +		.sample_type = 0, +		.config = 0,/* PMU: cycles */ +	}; + +	for (i = 0; i < nr_cpus; i++) { +		pmu_fd[i] = perf_event_open(&attr_insn_pmu, -1/*pid*/, i/*cpu*/, -1/*group_fd*/, 0); +		if (pmu_fd[i] < 0) { +			printf("event syscall failed\n"); +			goto exit; +		} + +		bpf_update_elem(map_fd[0], &i, &pmu_fd[i], BPF_ANY); +		ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE, 0); +	} + +	status = system("ls > /dev/null"); +	if (status) +		goto exit; +	status = system("sleep 2"); +	if (status) +		goto exit; + +exit: +	for (i = 0; i < nr_cpus; i++) +		close(pmu_fd[i]); +	close(map_fd[0]); +	free(pmu_fd); +} + +int main(int argc, char **argv) +{ +	char filename[256]; + +	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); + +	if (load_bpf_file(filename)) { +		printf("%s", bpf_log_buf); +		return 1; +	} + +	test_bpf_perf_event(); +	read_trace_pipe(); + +	return 0; +} diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h index 8965d1bb8811..125d6402f64f 100644 --- a/samples/trace_events/trace-events-sample.h +++ b/samples/trace_events/trace-events-sample.h @@ -168,7 +168,10 @@   *   *      For __dynamic_array(int, foo, bar) use __get_dynamic_array(foo)   *            Use __get_dynamic_array_len(foo) to get the length of the array - *            saved. + *            saved. Note, __get_dynamic_array_len() returns the total allocated + *            length of the dynamic array; __print_array() expects the second + *            parameter to be the number of elements. To get that, the array length + *            needs to be divided by the element size.   *   *      For __string(foo, bar) use __get_str(foo)   * @@ -288,7 +291,7 @@ TRACE_EVENT(foo_bar,   *    This prints out the array that is defined by __array in a nice format.   */  		  __print_array(__get_dynamic_array(list), -				__get_dynamic_array_len(list), +				__get_dynamic_array_len(list) / sizeof(int),  				sizeof(int)),  		  __get_str(str), __get_bitmask(cpus))  );  |