Patch "bpf: fix refcnt overflow" has been added to the 4.5-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
bpf: fix refcnt overflow
to the 4.5-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
bpf-fix-refcnt-overflow.patch
and it can be found in the queue-4.5 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From foo@baz Mon May 16 11:20:33 PDT 2016
From: Alexei Starovoitov <[email protected]>
Date: Wed, 27 Apr 2016 18:56:20 -0700
Subject: bpf: fix refcnt overflow
From: Alexei Starovoitov <[email protected]>
[ Upstream commit 92117d8443bc5afacc8d5ba82e541946310f106e ]
On a system with >32Gbyte of phyiscal memory and infinite RLIMIT_MEMLOCK, the malicious application may overflow 32-bit bpf program refcnt. It's also possible to overflow map refcnt on 1Tb system. Impose 32k hard limit which means that the same bpf program or map cannot be shared by more than 32k processes.
--- include/linux/bpf.h | 3 ++- kernel/bpf/inode.c | 7 ++++--- kernel/bpf/syscall.c | 24 ++++++++++++++++++++---- kernel/bpf/verifier.c | 11 +++++++---- 4 files changed, 33 insertions(+), 12 deletions(-)
include/linux/bpf.h +2 -1
@@ -165,12 +165,13 @@ void bpf_register_prog_type(struct bpf_pvoid bpf_register_map_type (struct bpf_map_type_list *tl);struct bpf_prog *bpf_prog_get (u32 ufd); +struct bpf_prog *bpf_prog_inc (struct bpf_prog *prog);void bpf_prog_put (struct bpf_prog *prog);void bpf_prog_put_rcu (struct bpf_prog *prog);struct bpf_map *bpf_map_get_with_uref (u32 ufd);struct bpf_map *__bpf_map_get (struct fd f); -void bpf_map_inc (struct bpf_map *map,bool uref); +struct bpf_map *bpf_map_inc (struct bpf_map *map,bool uref);void bpf_map_put_with_uref (struct bpf_map *map);void bpf_map_put (struct bpf_map *map);
kernel/bpf/inode.c +4 -3
@@ -31,10 +31,10 @@ static void *bpf_any_get(void *raw, enum {switch (type) {case BPF_TYPE_PROG : -atomic_inc (&((struct bpf_prog *)raw)->aux->refcnt); + raw =bpf_prog_inc (raw);break ;case BPF_TYPE_MAP : -bpf_map_inc (raw, true); + raw =bpf_map_inc (raw, true);break ;default :WARN_ON_ONCE (1 );
@@ -297,7 +297,8 @@ static void *bpf_obj_do_get(const struct goto out; raw =bpf_any_get (inode->i_private, *type); -touch_atime (&path); +if (!IS_ERR (raw)) +touch_atime (&path);path_put (&path);return raw;
kernel/bpf/syscall.c +20 -4
@@ -201,11 +201,18 @@ struct bpf_map *__bpf_map_get(struct fdreturn f.file->private_data; } -void bpf_map_inc (struct bpf_map *map,bool uref) +/* prog's and map's refcnt limit */ +#define BPF_MAX_REFCNT 32768 + +struct bpf_map *bpf_map_inc (struct bpf_map *map,bool uref) { -atomic_inc (&map->refcnt); +if (atomic_inc_return (&map->refcnt) >BPF_MAX_REFCNT ) { +atomic_dec (&map->refcnt); +return ERR_PTR (-EBUSY ); + }if (uref)atomic_inc (&map->usercnt); +return map; }struct bpf_map *bpf_map_get_with_uref (u32 ufd)
@@ -217,7 +224,7 @@ struct bpf_map *bpf_map_get_with_uref(u3if (IS_ERR (map))return map; -bpf_map_inc (map, true); + map =bpf_map_inc (map, true);fdput (f);return map;
@@ -600,6 +607,15 @@ static struct bpf_prog *__bpf_prog_get(sreturn f.file->private_data; } +struct bpf_prog *bpf_prog_inc (struct bpf_prog *prog) +{ +if (atomic_inc_return (&prog->aux->refcnt) >BPF_MAX_REFCNT ) { +atomic_dec (&prog->aux->refcnt); +return ERR_PTR (-EBUSY ); + } +return prog; +} +/* called by sockets/tracing/seccomp before attaching program to an event * pairs with bpf_prog_put() */
@@ -612,7 +628,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd)if (IS_ERR (prog))return prog; -atomic_inc (&prog->aux->refcnt); + prog =bpf_prog_inc (prog);fdput (f);return prog;
kernel/bpf/verifier.c +7 -4
@@ -2023,15 +2023,18 @@ static int replace_map_fd_with_map_ptr(sreturn -E2BIG ; } -/* remember this map */ - env->used_maps[env->used_map_cnt++] = map; -/* hold the map. If the program is rejected by verifier, * the map will be released by release_maps() or it * will be used by the valid program until it's unloaded * and all maps are released in free_bpf_prog_info() */ -bpf_map_inc (map, false); + map =bpf_map_inc (map, false); +if (IS_ERR (map)) { +fdput (f); +return PTR_ERR (map); + } + env->used_maps[env->used_map_cnt++] = map; +fdput (f); next_insn: insn++;
Patches currently in stable-queue which might be from [email protected] are
queue-4.5/samples-bpf-fix-trace_output-example.patch queue-4.5/bpf-fix-refcnt-overflow.patch queue-4.5/bpf-verifier-reject-invalid-ld_abs-bpf_dw-instruction.patch queue-4.5/bpf-fix-check_map_func_compatibility-logic.patch