diff options
Diffstat (limited to 'kernel/bpf/core.c')
-rw-r--r-- | kernel/bpf/core.c | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 7c7eeea8cffc..6377225b2082 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c | |||
@@ -365,10 +365,13 @@ void bpf_prog_kallsyms_del_all(struct bpf_prog *fp) | |||
365 | } | 365 | } |
366 | 366 | ||
367 | #ifdef CONFIG_BPF_JIT | 367 | #ifdef CONFIG_BPF_JIT |
368 | # define BPF_JIT_LIMIT_DEFAULT (PAGE_SIZE * 40000) | ||
369 | |||
368 | /* All BPF JIT sysctl knobs here. */ | 370 | /* All BPF JIT sysctl knobs here. */ |
369 | int bpf_jit_enable __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_ALWAYS_ON); | 371 | int bpf_jit_enable __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_ALWAYS_ON); |
370 | int bpf_jit_harden __read_mostly; | 372 | int bpf_jit_harden __read_mostly; |
371 | int bpf_jit_kallsyms __read_mostly; | 373 | int bpf_jit_kallsyms __read_mostly; |
374 | int bpf_jit_limit __read_mostly = BPF_JIT_LIMIT_DEFAULT; | ||
372 | 375 | ||
373 | static __always_inline void | 376 | static __always_inline void |
374 | bpf_get_prog_addr_region(const struct bpf_prog *prog, | 377 | bpf_get_prog_addr_region(const struct bpf_prog *prog, |
@@ -577,27 +580,64 @@ int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type, | |||
577 | return ret; | 580 | return ret; |
578 | } | 581 | } |
579 | 582 | ||
583 | static atomic_long_t bpf_jit_current; | ||
584 | |||
585 | #if defined(MODULES_VADDR) | ||
586 | static int __init bpf_jit_charge_init(void) | ||
587 | { | ||
588 | /* Only used as heuristic here to derive limit. */ | ||
589 | bpf_jit_limit = min_t(u64, round_up((MODULES_END - MODULES_VADDR) >> 2, | ||
590 | PAGE_SIZE), INT_MAX); | ||
591 | return 0; | ||
592 | } | ||
593 | pure_initcall(bpf_jit_charge_init); | ||
594 | #endif | ||
595 | |||
596 | static int bpf_jit_charge_modmem(u32 pages) | ||
597 | { | ||
598 | if (atomic_long_add_return(pages, &bpf_jit_current) > | ||
599 | (bpf_jit_limit >> PAGE_SHIFT)) { | ||
600 | if (!capable(CAP_SYS_ADMIN)) { | ||
601 | atomic_long_sub(pages, &bpf_jit_current); | ||
602 | return -EPERM; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static void bpf_jit_uncharge_modmem(u32 pages) | ||
610 | { | ||
611 | atomic_long_sub(pages, &bpf_jit_current); | ||
612 | } | ||
613 | |||
580 | struct bpf_binary_header * | 614 | struct bpf_binary_header * |
581 | bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr, | 615 | bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr, |
582 | unsigned int alignment, | 616 | unsigned int alignment, |
583 | bpf_jit_fill_hole_t bpf_fill_ill_insns) | 617 | bpf_jit_fill_hole_t bpf_fill_ill_insns) |
584 | { | 618 | { |
585 | struct bpf_binary_header *hdr; | 619 | struct bpf_binary_header *hdr; |
586 | unsigned int size, hole, start; | 620 | u32 size, hole, start, pages; |
587 | 621 | ||
588 | /* Most of BPF filters are really small, but if some of them | 622 | /* Most of BPF filters are really small, but if some of them |
589 | * fill a page, allow at least 128 extra bytes to insert a | 623 | * fill a page, allow at least 128 extra bytes to insert a |
590 | * random section of illegal instructions. | 624 | * random section of illegal instructions. |
591 | */ | 625 | */ |
592 | size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE); | 626 | size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE); |
627 | pages = size / PAGE_SIZE; | ||
628 | |||
629 | if (bpf_jit_charge_modmem(pages)) | ||
630 | return NULL; | ||
593 | hdr = module_alloc(size); | 631 | hdr = module_alloc(size); |
594 | if (hdr == NULL) | 632 | if (!hdr) { |
633 | bpf_jit_uncharge_modmem(pages); | ||
595 | return NULL; | 634 | return NULL; |
635 | } | ||
596 | 636 | ||
597 | /* Fill space with illegal/arch-dep instructions. */ | 637 | /* Fill space with illegal/arch-dep instructions. */ |
598 | bpf_fill_ill_insns(hdr, size); | 638 | bpf_fill_ill_insns(hdr, size); |
599 | 639 | ||
600 | hdr->pages = size / PAGE_SIZE; | 640 | hdr->pages = pages; |
601 | hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)), | 641 | hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)), |
602 | PAGE_SIZE - sizeof(*hdr)); | 642 | PAGE_SIZE - sizeof(*hdr)); |
603 | start = (get_random_int() % hole) & ~(alignment - 1); | 643 | start = (get_random_int() % hole) & ~(alignment - 1); |
@@ -610,7 +650,10 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr, | |||
610 | 650 | ||
611 | void bpf_jit_binary_free(struct bpf_binary_header *hdr) | 651 | void bpf_jit_binary_free(struct bpf_binary_header *hdr) |
612 | { | 652 | { |
653 | u32 pages = hdr->pages; | ||
654 | |||
613 | module_memfree(hdr); | 655 | module_memfree(hdr); |
656 | bpf_jit_uncharge_modmem(pages); | ||
614 | } | 657 | } |
615 | 658 | ||
616 | /* This symbol is only overridden by archs that have different | 659 | /* This symbol is only overridden by archs that have different |