Skip to content

Commit 54713c8

Browse files
tohojoAlexei Starovoitov
authored andcommitted
bpf: Fix potential race in tail call compatibility check
Lorenzo noticed that the code testing for program type compatibility of tail call maps is potentially racy in that two threads could encounter a map with an unset type simultaneously and both return true even though they are inserting incompatible programs. The race window is quite small, but artificially enlarging it by adding a usleep_range() inside the check in bpf_prog_array_compatible() makes it trivial to trigger from userspace with a program that does, essentially: map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, 4, 4, 2, 0); pid = fork(); if (pid) { key = 0; value = xdp_fd; } else { key = 1; value = tc_fd; } err = bpf_map_update_elem(map_fd, &key, &value, 0); While the race window is small, it has potentially serious ramifications in that triggering it would allow a BPF program to tail call to a program of a different type. So let's get rid of it by protecting the update with a spinlock. The commit in the Fixes tag is the last commit that touches the code in question. v2: - Use a spinlock instead of an atomic variable and cmpxchg() (Alexei) v3: - Put lock and the members it protects into an embedded 'owner' struct (Daniel) Fixes: 3324b58 ("ebpf: misc core cleanup") Reported-by: Lorenzo Bianconi <[email protected]> Signed-off-by: Toke Høiland-Jørgensen <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 99d0a38 commit 54713c8

File tree

4 files changed

+23
-11
lines changed

4 files changed

+23
-11
lines changed

include/linux/bpf.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,11 @@ struct bpf_array_aux {
929929
* stored in the map to make sure that all callers and callees have
930930
* the same prog type and JITed flag.
931931
*/
932-
enum bpf_prog_type type;
933-
bool jited;
932+
struct {
933+
spinlock_t lock;
934+
enum bpf_prog_type type;
935+
bool jited;
936+
} owner;
934937
/* Programs with direct jumps into programs part of this array. */
935938
struct list_head poke_progs;
936939
struct bpf_map *map;

kernel/bpf/arraymap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,7 @@ static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr)
10721072
INIT_WORK(&aux->work, prog_array_map_clear_deferred);
10731073
INIT_LIST_HEAD(&aux->poke_progs);
10741074
mutex_init(&aux->poke_mutex);
1075+
spin_lock_init(&aux->owner.lock);
10751076

10761077
map = array_map_alloc(attr);
10771078
if (IS_ERR(map)) {

kernel/bpf/core.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,20 +1823,26 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx,
18231823
bool bpf_prog_array_compatible(struct bpf_array *array,
18241824
const struct bpf_prog *fp)
18251825
{
1826+
bool ret;
1827+
18261828
if (fp->kprobe_override)
18271829
return false;
18281830

1829-
if (!array->aux->type) {
1831+
spin_lock(&array->aux->owner.lock);
1832+
1833+
if (!array->aux->owner.type) {
18301834
/* There's no owner yet where we could check for
18311835
* compatibility.
18321836
*/
1833-
array->aux->type = fp->type;
1834-
array->aux->jited = fp->jited;
1835-
return true;
1837+
array->aux->owner.type = fp->type;
1838+
array->aux->owner.jited = fp->jited;
1839+
ret = true;
1840+
} else {
1841+
ret = array->aux->owner.type == fp->type &&
1842+
array->aux->owner.jited == fp->jited;
18361843
}
1837-
1838-
return array->aux->type == fp->type &&
1839-
array->aux->jited == fp->jited;
1844+
spin_unlock(&array->aux->owner.lock);
1845+
return ret;
18401846
}
18411847

18421848
static int bpf_check_tail_call(const struct bpf_prog *fp)

kernel/bpf/syscall.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,10 @@ static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
543543

544544
if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) {
545545
array = container_of(map, struct bpf_array, map);
546-
type = array->aux->type;
547-
jited = array->aux->jited;
546+
spin_lock(&array->aux->owner.lock);
547+
type = array->aux->owner.type;
548+
jited = array->aux->owner.jited;
549+
spin_unlock(&array->aux->owner.lock);
548550
}
549551

550552
seq_printf(m,

0 commit comments

Comments
 (0)