Skip to content

Commit c6bde95

Browse files
florianlAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: Lift hashtab key_size limit
Currently key_size of hashtab is limited to MAX_BPF_STACK. As the key of hashtab can also be a value from a per cpu map it can be larger than MAX_BPF_STACK. The use-case for this patch originates to implement allow/disallow lists for files and file paths. The maximum length of file paths is defined by PATH_MAX with 4096 chars including nul. This limit exceeds MAX_BPF_STACK. Changelog: v5: - Fix cast overflow v4: - Utilize BPF skeleton in tests - Rebase v3: - Rebase v2: - Add a test for bpf side Signed-off-by: Florian Lehner <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: John Fastabend <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent b6b466a commit c6bde95

File tree

4 files changed

+94
-12
lines changed

4 files changed

+94
-12
lines changed

kernel/bpf/hashtab.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -415,17 +415,11 @@ static int htab_map_alloc_check(union bpf_attr *attr)
415415
attr->value_size == 0)
416416
return -EINVAL;
417417

418-
if (attr->key_size > MAX_BPF_STACK)
419-
/* eBPF programs initialize keys on stack, so they cannot be
420-
* larger than max stack size
421-
*/
422-
return -E2BIG;
423-
424-
if (attr->value_size >= KMALLOC_MAX_SIZE -
425-
MAX_BPF_STACK - sizeof(struct htab_elem))
426-
/* if value_size is bigger, the user space won't be able to
427-
* access the elements via bpf syscall. This check also makes
428-
* sure that the elem_size doesn't overflow and it's
418+
if ((u64)attr->key_size + attr->value_size >= KMALLOC_MAX_SIZE -
419+
sizeof(struct htab_elem))
420+
/* if key_size + value_size is bigger, the user space won't be
421+
* able to access the elements via bpf syscall. This check
422+
* also makes sure that the elem_size doesn't overflow and it's
429423
* kmalloc-able later in htab_map_update_elem()
430424
*/
431425
return -E2BIG;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <test_progs.h>
4+
#include "test_hash_large_key.skel.h"
5+
6+
void test_hash_large_key(void)
7+
{
8+
int err, value = 21, duration = 0, hash_map_fd;
9+
struct test_hash_large_key *skel;
10+
11+
struct bigelement {
12+
int a;
13+
char b[4096];
14+
long long c;
15+
} key;
16+
bzero(&key, sizeof(key));
17+
18+
skel = test_hash_large_key__open_and_load();
19+
if (CHECK(!skel, "skel_open_and_load", "skeleton open/load failed\n"))
20+
return;
21+
22+
hash_map_fd = bpf_map__fd(skel->maps.hash_map);
23+
if (CHECK(hash_map_fd < 0, "bpf_map__fd", "failed\n"))
24+
goto cleanup;
25+
26+
err = test_hash_large_key__attach(skel);
27+
if (CHECK(err, "attach_raw_tp", "err %d\n", err))
28+
goto cleanup;
29+
30+
err = bpf_map_update_elem(hash_map_fd, &key, &value, BPF_ANY);
31+
if (CHECK(err, "bpf_map_update_elem", "errno=%d\n", errno))
32+
goto cleanup;
33+
34+
key.c = 1;
35+
err = bpf_map_lookup_elem(hash_map_fd, &key, &value);
36+
if (CHECK(err, "bpf_map_lookup_elem", "errno=%d\n", errno))
37+
goto cleanup;
38+
39+
CHECK_FAIL(value != 42);
40+
41+
cleanup:
42+
test_hash_large_key__destroy(skel);
43+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
char _license[] SEC("license") = "GPL";
7+
8+
struct {
9+
__uint(type, BPF_MAP_TYPE_HASH);
10+
__uint(max_entries, 2);
11+
__type(key, struct bigelement);
12+
__type(value, __u32);
13+
} hash_map SEC(".maps");
14+
15+
struct {
16+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
17+
__uint(max_entries, 1);
18+
__type(key, __u32);
19+
__type(value, struct bigelement);
20+
} key_map SEC(".maps");
21+
22+
struct bigelement {
23+
int a;
24+
char b[4096];
25+
long long c;
26+
};
27+
28+
SEC("raw_tracepoint/sys_enter")
29+
int bpf_hash_large_key_test(void *ctx)
30+
{
31+
int zero = 0, err = 1, value = 42;
32+
struct bigelement *key;
33+
34+
key = bpf_map_lookup_elem(&key_map, &zero);
35+
if (!key)
36+
return 0;
37+
38+
key->c = 1;
39+
if (bpf_map_update_elem(&hash_map, key, &value, BPF_ANY))
40+
return 0;
41+
42+
return 0;
43+
}
44+

tools/testing/selftests/bpf/test_maps.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1223,9 +1223,10 @@ static void test_map_in_map(void)
12231223

12241224
static void test_map_large(void)
12251225
{
1226+
12261227
struct bigkey {
12271228
int a;
1228-
char b[116];
1229+
char b[4096];
12291230
long long c;
12301231
} key;
12311232
int fd, i, value;

0 commit comments

Comments
 (0)