|
@@ -365,10 +365,13 @@ void bpf_prog_kallsyms_del_all(struct bpf_prog *fp)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_BPF_JIT
|
|
|
+# define BPF_JIT_LIMIT_DEFAULT (PAGE_SIZE * 40000)
|
|
|
+
|
|
|
/* All BPF JIT sysctl knobs here. */
|
|
|
int bpf_jit_enable __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_ALWAYS_ON);
|
|
|
int bpf_jit_harden __read_mostly;
|
|
|
int bpf_jit_kallsyms __read_mostly;
|
|
|
+int bpf_jit_limit __read_mostly = BPF_JIT_LIMIT_DEFAULT;
|
|
|
|
|
|
static __always_inline void
|
|
|
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,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static atomic_long_t bpf_jit_current;
|
|
|
+
|
|
|
+#if defined(MODULES_VADDR)
|
|
|
+static int __init bpf_jit_charge_init(void)
|
|
|
+{
|
|
|
+ /* Only used as heuristic here to derive limit. */
|
|
|
+ bpf_jit_limit = min_t(u64, round_up((MODULES_END - MODULES_VADDR) >> 2,
|
|
|
+ PAGE_SIZE), INT_MAX);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+pure_initcall(bpf_jit_charge_init);
|
|
|
+#endif
|
|
|
+
|
|
|
+static int bpf_jit_charge_modmem(u32 pages)
|
|
|
+{
|
|
|
+ if (atomic_long_add_return(pages, &bpf_jit_current) >
|
|
|
+ (bpf_jit_limit >> PAGE_SHIFT)) {
|
|
|
+ if (!capable(CAP_SYS_ADMIN)) {
|
|
|
+ atomic_long_sub(pages, &bpf_jit_current);
|
|
|
+ return -EPERM;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void bpf_jit_uncharge_modmem(u32 pages)
|
|
|
+{
|
|
|
+ atomic_long_sub(pages, &bpf_jit_current);
|
|
|
+}
|
|
|
+
|
|
|
struct bpf_binary_header *
|
|
|
bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
|
|
|
unsigned int alignment,
|
|
|
bpf_jit_fill_hole_t bpf_fill_ill_insns)
|
|
|
{
|
|
|
struct bpf_binary_header *hdr;
|
|
|
- unsigned int size, hole, start;
|
|
|
+ u32 size, hole, start, pages;
|
|
|
|
|
|
/* Most of BPF filters are really small, but if some of them
|
|
|
* fill a page, allow at least 128 extra bytes to insert a
|
|
|
* random section of illegal instructions.
|
|
|
*/
|
|
|
size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE);
|
|
|
+ pages = size / PAGE_SIZE;
|
|
|
+
|
|
|
+ if (bpf_jit_charge_modmem(pages))
|
|
|
+ return NULL;
|
|
|
hdr = module_alloc(size);
|
|
|
- if (hdr == NULL)
|
|
|
+ if (!hdr) {
|
|
|
+ bpf_jit_uncharge_modmem(pages);
|
|
|
return NULL;
|
|
|
+ }
|
|
|
|
|
|
/* Fill space with illegal/arch-dep instructions. */
|
|
|
bpf_fill_ill_insns(hdr, size);
|
|
|
|
|
|
- hdr->pages = size / PAGE_SIZE;
|
|
|
+ hdr->pages = pages;
|
|
|
hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)),
|
|
|
PAGE_SIZE - sizeof(*hdr));
|
|
|
start = (get_random_int() % hole) & ~(alignment - 1);
|
|
@@ -610,7 +650,10 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
|
|
|
|
|
|
void bpf_jit_binary_free(struct bpf_binary_header *hdr)
|
|
|
{
|
|
|
+ u32 pages = hdr->pages;
|
|
|
+
|
|
|
module_memfree(hdr);
|
|
|
+ bpf_jit_uncharge_modmem(pages);
|
|
|
}
|
|
|
|
|
|
/* This symbol is only overridden by archs that have different
|