diff options
Diffstat (limited to 'samples/bpf')
-rw-r--r-- | samples/bpf/Makefile | 4 | ||||
-rw-r--r-- | samples/bpf/bpf_helpers.h | 39 | ||||
-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 |
10 files changed, 213 insertions, 12 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 4450fed91..63e7d50e6 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 bdf1c1607..af44e564d 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,41 @@ 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]) + +#elif defined(__aarch64__) + +#define PT_REGS_PARM1(x) ((x)->regs[0]) +#define PT_REGS_PARM2(x) ((x)->regs[1]) +#define PT_REGS_PARM3(x) ((x)->regs[2]) +#define PT_REGS_PARM4(x) ((x)->regs[3]) +#define PT_REGS_PARM5(x) ((x)->regs[4]) +#define PT_REGS_RET(x) ((x)->regs[30]) +#define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[0]) +#define PT_REGS_SP(x) ((x)->sp) + +#endif #endif diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 693605997..ee0f110c9 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 316204637..3f450a8fa 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 dc50f4f29..b32367cfb 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 255ff2792..bf337fbb0 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 126b80512..ac4671420 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 b71fe07a7..b3f4295bf 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 000000000..be479c4af --- /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 000000000..8ea4976cf --- /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; +} |