Skip to content

Commit ee88bdd

Browse files
committed
Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Pull bpf fixes from Alexei Starovoitov: - Fix use-after-free in libbpf when map is resized (Adin Scannell) - Fix verifier assumptions about 2nd argument of bpf_sysctl_get_name (Jerome Marchand) - Fix verifier assumption of nullness of d_inode in dentry (Song Liu) - Fix global starvation of LRU map (Willem de Bruijn) - Fix potential NULL dereference in btf_dump__free (Yuan Chen) * tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: adapt one more case in test_lru_map to the new target_free libbpf: Fix possible use-after-free for externs selftests/bpf: Convert test_sysctl to prog_tests bpf: Specify access type of bpf_sysctl_get_name args libbpf: Fix null pointer dereference in btf_dump__free on allocation failure bpf: Adjust free target to avoid global starvation of LRU map bpf: Mark dentry->d_inode as trusted_or_null
2 parents c5c2a8b + 5e9388f commit ee88bdd

File tree

15 files changed

+142
-99
lines changed

15 files changed

+142
-99
lines changed

Documentation/bpf/map_hash.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,16 @@ attempts in order to enforce the LRU property which have increasing impacts on
233233
other CPUs involved in the following operation attempts:
234234

235235
- Attempt to use CPU-local state to batch operations
236-
- Attempt to fetch free nodes from global lists
236+
- Attempt to fetch ``target_free`` free nodes from global lists
237237
- Attempt to pull any node from a global list and remove it from the hashmap
238238
- Attempt to pull any node from any CPU's list and remove it from the hashmap
239239

240+
The number of nodes to borrow from the global list in a batch, ``target_free``,
241+
depends on the size of the map. Larger batch size reduces lock contention, but
242+
may also exhaust the global structure. The value is computed at map init to
243+
avoid exhaustion, by limiting aggregate reservation by all CPUs to half the map
244+
size. With a minimum of a single element and maximum budget of 128 at a time.
245+
240246
This algorithm is described visually in the following diagram. See the
241247
description in commit 3a08c2fd7634 ("bpf: LRU List") for a full explanation of
242248
the corresponding operations:

Documentation/bpf/map_lru_hash_update.dot

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,18 @@ digraph {
3535
fn_bpf_lru_list_pop_free_to_local [shape=rectangle,fillcolor=2,
3636
label="Flush local pending,
3737
Rotate Global list, move
38-
LOCAL_FREE_TARGET
38+
target_free
3939
from global -> local"]
4040
// Also corresponds to:
4141
// fn__local_list_flush()
4242
// fn_bpf_lru_list_rotate()
4343
fn___bpf_lru_node_move_to_free[shape=diamond,fillcolor=2,
44-
label="Able to free\nLOCAL_FREE_TARGET\nnodes?"]
44+
label="Able to free\ntarget_free\nnodes?"]
4545

4646
fn___bpf_lru_list_shrink_inactive [shape=rectangle,fillcolor=3,
4747
label="Shrink inactive list
4848
up to remaining
49-
LOCAL_FREE_TARGET
49+
target_free
5050
(global LRU -> local)"]
5151
fn___bpf_lru_list_shrink [shape=diamond,fillcolor=2,
5252
label="> 0 entries in\nlocal free list?"]

kernel/bpf/bpf_lru_list.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,12 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
337337
list) {
338338
__bpf_lru_node_move_to_free(l, node, local_free_list(loc_l),
339339
BPF_LRU_LOCAL_LIST_T_FREE);
340-
if (++nfree == LOCAL_FREE_TARGET)
340+
if (++nfree == lru->target_free)
341341
break;
342342
}
343343

344-
if (nfree < LOCAL_FREE_TARGET)
345-
__bpf_lru_list_shrink(lru, l, LOCAL_FREE_TARGET - nfree,
344+
if (nfree < lru->target_free)
345+
__bpf_lru_list_shrink(lru, l, lru->target_free - nfree,
346346
local_free_list(loc_l),
347347
BPF_LRU_LOCAL_LIST_T_FREE);
348348

@@ -577,6 +577,9 @@ static void bpf_common_lru_populate(struct bpf_lru *lru, void *buf,
577577
list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]);
578578
buf += elem_size;
579579
}
580+
581+
lru->target_free = clamp((nr_elems / num_possible_cpus()) / 2,
582+
1, LOCAL_FREE_TARGET);
580583
}
581584

582585
static void bpf_percpu_lru_populate(struct bpf_lru *lru, void *buf,

kernel/bpf/bpf_lru_list.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct bpf_lru {
5858
del_from_htab_func del_from_htab;
5959
void *del_arg;
6060
unsigned int hash_offset;
61+
unsigned int target_free;
6162
unsigned int nr_scans;
6263
bool percpu;
6364
};

kernel/bpf/cgroup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2134,7 +2134,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = {
21342134
.gpl_only = false,
21352135
.ret_type = RET_INTEGER,
21362136
.arg1_type = ARG_PTR_TO_CTX,
2137-
.arg2_type = ARG_PTR_TO_MEM,
2137+
.arg2_type = ARG_PTR_TO_MEM | MEM_WRITE,
21382138
.arg3_type = ARG_CONST_SIZE,
21392139
.arg4_type = ARG_ANYTHING,
21402140
};

kernel/bpf/verifier.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7027,8 +7027,7 @@ BTF_TYPE_SAFE_TRUSTED(struct file) {
70277027
struct inode *f_inode;
70287028
};
70297029

7030-
BTF_TYPE_SAFE_TRUSTED(struct dentry) {
7031-
/* no negative dentry-s in places where bpf can see it */
7030+
BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct dentry) {
70327031
struct inode *d_inode;
70337032
};
70347033

@@ -7066,7 +7065,6 @@ static bool type_is_trusted(struct bpf_verifier_env *env,
70667065
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct bpf_iter__task));
70677066
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct linux_binprm));
70687067
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct file));
7069-
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct dentry));
70707068

70717069
return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, "__safe_trusted");
70727070
}
@@ -7076,6 +7074,7 @@ static bool type_is_trusted_or_null(struct bpf_verifier_env *env,
70767074
const char *field_name, u32 btf_id)
70777075
{
70787076
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket));
7077+
BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct dentry));
70797078

70807079
return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id,
70817080
"__safe_trusted_or_null");

tools/lib/bpf/btf_dump.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ static void btf_dump_free_names(struct hashmap *map)
226226
size_t bkt;
227227
struct hashmap_entry *cur;
228228

229+
if (!map)
230+
return;
231+
229232
hashmap__for_each_entry(map, cur, bkt)
230233
free((void *)cur->pkey);
231234

tools/lib/bpf/libbpf.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ struct extern_desc {
597597
int sym_idx;
598598
int btf_id;
599599
int sec_btf_id;
600-
const char *name;
600+
char *name;
601601
char *essent_name;
602602
bool is_set;
603603
bool is_weak;
@@ -4259,7 +4259,9 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
42594259
return ext->btf_id;
42604260
}
42614261
t = btf__type_by_id(obj->btf, ext->btf_id);
4262-
ext->name = btf__name_by_offset(obj->btf, t->name_off);
4262+
ext->name = strdup(btf__name_by_offset(obj->btf, t->name_off));
4263+
if (!ext->name)
4264+
return -ENOMEM;
42634265
ext->sym_idx = i;
42644266
ext->is_weak = ELF64_ST_BIND(sym->st_info) == STB_WEAK;
42654267

@@ -9138,8 +9140,10 @@ void bpf_object__close(struct bpf_object *obj)
91389140
zfree(&obj->btf_custom_path);
91399141
zfree(&obj->kconfig);
91409142

9141-
for (i = 0; i < obj->nr_extern; i++)
9143+
for (i = 0; i < obj->nr_extern; i++) {
9144+
zfree(&obj->externs[i].name);
91429145
zfree(&obj->externs[i].essent_name);
9146+
}
91439147

91449148
zfree(&obj->externs);
91459149
obj->nr_extern = 0;

tools/testing/selftests/bpf/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ test_lirc_mode2_user
2121
flow_dissector_load
2222
test_tcpnotify_user
2323
test_libbpf
24-
test_sysctl
2524
xdping
2625
test_cpp
2726
*.d

tools/testing/selftests/bpf/Makefile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ endif
7373
# Order correspond to 'make run_tests' order
7474
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_progs \
7575
test_sockmap \
76-
test_tcpnotify_user test_sysctl \
76+
test_tcpnotify_user \
7777
test_progs-no_alu32
7878
TEST_INST_SUBDIRS := no_alu32
7979

@@ -220,7 +220,7 @@ ifeq ($(VMLINUX_BTF),)
220220
$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
221221
endif
222222

223-
# Define simple and short `make test_progs`, `make test_sysctl`, etc targets
223+
# Define simple and short `make test_progs`, `make test_maps`, etc targets
224224
# to build individual tests.
225225
# NOTE: Semicolon at the end is critical to override lib.mk's default static
226226
# rule for binaries.
@@ -329,7 +329,6 @@ NETWORK_HELPERS := $(OUTPUT)/network_helpers.o
329329
$(OUTPUT)/test_sockmap: $(CGROUP_HELPERS) $(TESTING_HELPERS)
330330
$(OUTPUT)/test_tcpnotify_user: $(CGROUP_HELPERS) $(TESTING_HELPERS) $(TRACE_HELPERS)
331331
$(OUTPUT)/test_sock_fields: $(CGROUP_HELPERS) $(TESTING_HELPERS)
332-
$(OUTPUT)/test_sysctl: $(CGROUP_HELPERS) $(TESTING_HELPERS)
333332
$(OUTPUT)/test_tag: $(TESTING_HELPERS)
334333
$(OUTPUT)/test_lirc_mode2_user: $(TESTING_HELPERS)
335334
$(OUTPUT)/xdping: $(TESTING_HELPERS)

0 commit comments

Comments
 (0)