Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6788fac8 authored by David S. Miller's avatar David S. Miller
Browse files


Daniel Borkmann says:

====================
pull-request: bpf 2018-10-27

The following pull-request contains BPF updates for your *net* tree.

The main changes are:

1) Fix toctou race in BTF header validation, from Martin and Wenwen.

2) Fix devmap interface comparison in notifier call which was
   neglecting netns, from Taehee.

3) Several fixes in various places, for example, correcting direct
   packet access and helper function availability, from Daniel.

4) Fix BPF kselftest config fragment to include af_xdp and sockmap,
   from Naresh.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 345671ea d8fd9e10
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -92,6 +92,14 @@ Values :
	0 - disable JIT kallsyms export (default value)
	1 - enable JIT kallsyms export for privileged users only

bpf_jit_limit
-------------

This enforces a global limit for memory allocations to the BPF JIT
compiler in order to reject unprivileged JIT requests once it has
been surpassed. bpf_jit_limit contains the value of the global limit
in bytes.

dev_weight
--------------

+1 −0
Original line number Diff line number Diff line
@@ -854,6 +854,7 @@ bpf_run_sk_reuseport(struct sock_reuseport *reuse, struct sock *sk,
extern int bpf_jit_enable;
extern int bpf_jit_harden;
extern int bpf_jit_kallsyms;
extern int bpf_jit_limit;

typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);

+25 −33
Original line number Diff line number Diff line
@@ -2067,56 +2067,47 @@ static int btf_check_sec_info(struct btf_verifier_env *env,
	return 0;
}

static int btf_parse_hdr(struct btf_verifier_env *env, void __user *btf_data,
			 u32 btf_data_size)
static int btf_parse_hdr(struct btf_verifier_env *env)
{
	u32 hdr_len, hdr_copy, btf_data_size;
	const struct btf_header *hdr;
	u32 hdr_len, hdr_copy;
	/*
	 * Minimal part of the "struct btf_header" that
	 * contains the hdr_len.
	 */
	struct btf_min_header {
		u16	magic;
		u8	version;
		u8	flags;
		u32	hdr_len;
	} __user *min_hdr;
	struct btf *btf;
	int err;

	btf = env->btf;
	min_hdr = btf_data;
	btf_data_size = btf->data_size;

	if (btf_data_size < sizeof(*min_hdr)) {
	if (btf_data_size <
	    offsetof(struct btf_header, hdr_len) + sizeof(hdr->hdr_len)) {
		btf_verifier_log(env, "hdr_len not found");
		return -EINVAL;
	}

	if (get_user(hdr_len, &min_hdr->hdr_len))
		return -EFAULT;

	hdr = btf->data;
	hdr_len = hdr->hdr_len;
	if (btf_data_size < hdr_len) {
		btf_verifier_log(env, "btf_header not found");
		return -EINVAL;
	}

	err = bpf_check_uarg_tail_zero(btf_data, sizeof(btf->hdr), hdr_len);
	if (err) {
		if (err == -E2BIG)
	/* Ensure the unsupported header fields are zero */
	if (hdr_len > sizeof(btf->hdr)) {
		u8 *expected_zero = btf->data + sizeof(btf->hdr);
		u8 *end = btf->data + hdr_len;

		for (; expected_zero < end; expected_zero++) {
			if (*expected_zero) {
				btf_verifier_log(env, "Unsupported btf_header");
		return err;
				return -E2BIG;
			}
		}
	}

	hdr_copy = min_t(u32, hdr_len, sizeof(btf->hdr));
	if (copy_from_user(&btf->hdr, btf_data, hdr_copy))
		return -EFAULT;
	memcpy(&btf->hdr, btf->data, hdr_copy);

	hdr = &btf->hdr;

	if (hdr->hdr_len != hdr_len)
		return -EINVAL;

	btf_verifier_log_hdr(env, btf_data_size);

	if (hdr->magic != BTF_MAGIC) {
@@ -2186,10 +2177,6 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
	}
	env->btf = btf;

	err = btf_parse_hdr(env, btf_data, btf_data_size);
	if (err)
		goto errout;

	data = kvmalloc(btf_data_size, GFP_KERNEL | __GFP_NOWARN);
	if (!data) {
		err = -ENOMEM;
@@ -2198,13 +2185,18 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,

	btf->data = data;
	btf->data_size = btf_data_size;
	btf->nohdr_data = btf->data + btf->hdr.hdr_len;

	if (copy_from_user(data, btf_data, btf_data_size)) {
		err = -EFAULT;
		goto errout;
	}

	err = btf_parse_hdr(env);
	if (err)
		goto errout;

	btf->nohdr_data = btf->data + btf->hdr.hdr_len;

	err = btf_parse_str_sec(env);
	if (err)
		goto errout;
+46 −3
Original line number Diff line number Diff line
@@ -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
+1 −2
Original line number Diff line number Diff line
@@ -512,8 +512,7 @@ static int dev_map_notification(struct notifier_block *notifier,
				struct bpf_dtab_netdev *dev, *odev;

				dev = READ_ONCE(dtab->netdev_map[i]);
				if (!dev ||
				    dev->dev->ifindex != netdev->ifindex)
				if (!dev || netdev != dev->dev)
					continue;
				odev = cmpxchg(&dtab->netdev_map[i], dev, NULL);
				if (dev == odev)
Loading