diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 070bde56474c..c871e0e76c2a 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -435,6 +435,30 @@ static int bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self) return 0; } +static int bpf_fill_jump_around_ld_abs(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct bpf_insn *insn; + int i = 0; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + insn[i++] = BPF_MOV64_REG(R6, R1); + insn[i++] = BPF_LD_ABS(BPF_B, 0); + insn[i] = BPF_JMP_IMM(BPF_JEQ, R0, 10, len - i - 2); + i++; + while (i < len - 1) + insn[i++] = BPF_LD_ABS(BPF_B, 1); + insn[i] = BPF_EXIT_INSN(); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + static int __bpf_fill_stxdw(struct bpf_test *self, int size) { unsigned int len = BPF_MAXINSNS; @@ -5044,6 +5068,14 @@ static struct bpf_test tests[] = { { { ETH_HLEN, 0xbef } }, .fill_helper = bpf_fill_ld_abs_vlan_push_pop, }, + { + "BPF_MAXINSNS: jump around ld_abs", + { }, + INTERNAL, + { 10, 11 }, + { { 2, 10 } }, + .fill_helper = bpf_fill_jump_around_ld_abs, + }, /* * LD_IND / LD_ABS on fragmented SKBs */ diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 6c7468eb3684..a0561dc762fe 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -160,6 +160,17 @@ clean: $(MAKE) -C ../../ M=$(CURDIR) clean @rm -f *~ +$(obj)/syscall_nrs.s: $(src)/syscall_nrs.c + $(call if_changed_dep,cc_s_c) + +$(obj)/syscall_nrs.h: $(obj)/syscall_nrs.s FORCE + $(call filechk,offsets,__SYSCALL_NRS_H__) + +clean-files += syscall_nrs.h + +FORCE: + + # Verify LLVM compiler tools are available and bpf target is supported by llc .PHONY: verify_cmds verify_target_bpf $(CLANG) $(LLC) @@ -180,6 +191,8 @@ verify_target_bpf: verify_cmds $(src)/*.c: verify_target_bpf +$(obj)/tracex5_kern.o: $(obj)/syscall_nrs.h + # asm/sysreg.h - inline assembly used by it is incompatible with llvm. # But, there is no easy way to fix it, so just exclude it since it is # useless for BPF samples. diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index 51e567bc70fc..f4840b8bb8f9 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -136,6 +136,19 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = #define PT_REGS_SP(x) ((x)->sp) #define PT_REGS_IP(x) ((x)->pc) +#elif defined(__mips__) + +#define PT_REGS_PARM1(x) ((x)->regs[4]) +#define PT_REGS_PARM2(x) ((x)->regs[5]) +#define PT_REGS_PARM3(x) ((x)->regs[6]) +#define PT_REGS_PARM4(x) ((x)->regs[7]) +#define PT_REGS_PARM5(x) ((x)->regs[8]) +#define PT_REGS_RET(x) ((x)->regs[31]) +#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[1]) +#define PT_REGS_SP(x) ((x)->regs[29]) +#define PT_REGS_IP(x) ((x)->cp0_epc) + #elif defined(__powerpc__) #define PT_REGS_PARM1(x) ((x)->gpr[3]) diff --git a/samples/bpf/syscall_nrs.c b/samples/bpf/syscall_nrs.c new file mode 100644 index 000000000000..ce2a30b11248 --- /dev/null +++ b/samples/bpf/syscall_nrs.c @@ -0,0 +1,12 @@ +#include +#include + +#define SYSNR(_NR) DEFINE(SYS ## _NR, _NR) + +void syscall_defines(void) +{ + COMMENT("Linux system call numbers."); + SYSNR(__NR_write); + SYSNR(__NR_read); + SYSNR(__NR_mmap); +} diff --git a/samples/bpf/tracex5_kern.c b/samples/bpf/tracex5_kern.c index 7e4cf74553ff..f57f4e1ea1ec 100644 --- a/samples/bpf/tracex5_kern.c +++ b/samples/bpf/tracex5_kern.c @@ -9,6 +9,7 @@ #include #include #include +#include "syscall_nrs.h" #include "bpf_helpers.h" #define PROG(F) SEC("kprobe/"__stringify(F)) int bpf_func_##F @@ -17,7 +18,11 @@ struct bpf_map_def SEC("maps") progs = { .type = BPF_MAP_TYPE_PROG_ARRAY, .key_size = sizeof(u32), .value_size = sizeof(u32), +#ifdef __mips__ + .max_entries = 6000, /* MIPS n64 syscalls start at 5000 */ +#else .max_entries = 1024, +#endif }; SEC("kprobe/__seccomp_filter") @@ -37,7 +42,7 @@ int bpf_prog1(struct pt_regs *ctx) } /* we jump here when syscall number == __NR_write */ -PROG(__NR_write)(struct pt_regs *ctx) +PROG(SYS__NR_write)(struct pt_regs *ctx) { struct seccomp_data sd; @@ -50,7 +55,7 @@ PROG(__NR_write)(struct pt_regs *ctx) return 0; } -PROG(__NR_read)(struct pt_regs *ctx) +PROG(SYS__NR_read)(struct pt_regs *ctx) { struct seccomp_data sd; @@ -63,7 +68,7 @@ PROG(__NR_read)(struct pt_regs *ctx) return 0; } -PROG(__NR_mmap)(struct pt_regs *ctx) +PROG(SYS__NR_mmap)(struct pt_regs *ctx) { char fmt[] = "mmap\n"; bpf_trace_printk(fmt, sizeof(fmt)); diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c index ad572e6cdbd0..422d9abd666a 100644 --- a/tools/net/bpf_jit_disasm.c +++ b/tools/net/bpf_jit_disasm.c @@ -159,8 +159,8 @@ static void put_log_buff(char *buff) free(buff); } -static unsigned int get_last_jit_image(char *haystack, size_t hlen, - uint8_t *image, size_t ilen) +static uint8_t *get_last_jit_image(char *haystack, size_t hlen, + unsigned int *ilen) { char *ptr, *pptr, *tmp; off_t off = 0; @@ -168,9 +168,10 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, regmatch_t pmatch[1]; unsigned long base; regex_t regex; + uint8_t *image; if (hlen == 0) - return 0; + return NULL; ret = regcomp(®ex, "flen=[[:alnum:]]+ proglen=[[:digit:]]+ " "pass=[[:digit:]]+ image=[[:xdigit:]]+", REG_EXTENDED); @@ -194,11 +195,22 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, &flen, &proglen, &pass, &base); if (ret != 4) { regfree(®ex); - return 0; + return NULL; + } + if (proglen > 1000000) { + printf("proglen of %d too big, stopping\n", proglen); + return NULL; } + image = malloc(proglen); + if (!image) { + printf("Out of memory\n"); + return NULL; + } + memset(image, 0, proglen); + tmp = ptr = haystack + off; - while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) { + while ((ptr = strtok(tmp, "\n")) != NULL && ulen < proglen) { tmp = NULL; if (!strstr(ptr, "JIT code")) continue; @@ -208,10 +220,12 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, ptr = pptr; do { image[ulen++] = (uint8_t) strtoul(pptr, &pptr, 16); - if (ptr == pptr || ulen >= ilen) { + if (ptr == pptr) { ulen--; break; } + if (ulen >= proglen) + break; ptr = pptr; } while (1); } @@ -222,7 +236,8 @@ static unsigned int get_last_jit_image(char *haystack, size_t hlen, printf("%lx + :\n", base); regfree(®ex); - return ulen; + *ilen = ulen; + return image; } static void usage(void) @@ -237,12 +252,12 @@ static void usage(void) int main(int argc, char **argv) { unsigned int len, klen, opt, opcodes = 0; - static uint8_t image[32768]; char *kbuff, *file = NULL; char *ofile = NULL; int ofd; ssize_t nr; uint8_t *pos; + uint8_t *image = NULL; while ((opt = getopt(argc, argv, "of:O:")) != -1) { switch (opt) { @@ -262,7 +277,6 @@ int main(int argc, char **argv) } bfd_init(); - memset(image, 0, sizeof(image)); kbuff = get_log_buff(file, &klen); if (!kbuff) { @@ -270,8 +284,8 @@ int main(int argc, char **argv) return -1; } - len = get_last_jit_image(kbuff, klen, image, sizeof(image)); - if (len <= 0) { + image = get_last_jit_image(kbuff, klen, &len); + if (!image) { fprintf(stderr, "No JIT image found!\n"); goto done; } @@ -301,5 +315,6 @@ int main(int argc, char **argv) done: put_log_buff(kbuff); + free(image); return 0; }