bpf: Fix u32 overflow issue in map batch operations - #13431
bpf: Fix u32 overflow issue in map batch operations#13431kernel-patches-daemon-bpf[bot] wants to merge 1 commit into
Conversation
|
Upstream branch: 5e289c5 |
AI reviewed your patch. Please fix the bug or email reply why it's not a bug. In-Reply-To-Subject: |
|
Forwarding comment 5395055493 via email |
71e031f to
909ca3a
Compare
|
Upstream branch: d83fba2 |
519307b to
7d86a68
Compare
909ca3a to
b010507
Compare
|
Upstream branch: ce36e38 |
7d86a68 to
2edb36e
Compare
b010507 to
975b11a
Compare
|
Upstream branch: 05ea1b6 |
2edb36e to
6bfcbaf
Compare
975b11a to
f8c8078
Compare
|
Upstream branch: 1555de3 |
6bfcbaf to
4b00d39
Compare
f8c8078 to
be2aea4
Compare
|
Upstream branch: 48b69cc |
4b00d39 to
012fd66
Compare
be2aea4 to
40e2bc1
Compare
|
Upstream branch: 48b69cc |
012fd66 to
3ea923f
Compare
40e2bc1 to
62cdc87
Compare
|
Upstream branch: 5e875ae |
3ea923f to
0f3fa92
Compare
62cdc87 to
8a47bad
Compare
Several map batch operation implementations such as
generic_map_lookup_batch() use calculations in the form of
"values + cp * map->value_size" to compute the desired userspace memory
address for reading or writing. This can overflow the u32 type
(the result of "cp * map->value_size") when the map size exceeds 4GB.
generic_map_lookup_batch() may corrupt values for some keys in
userspace memory, and in some cases it mismatches values for some keys
while still reporting success.
Other batch operations may fail to delete or update some keys,
or the syscall may return unexpected errors.
This patch resolves the mentioned issues by converting the cp's type
to size_t in the effected places.
I created a BPF and a userspace C program to demonstrate the issue.
Example BPF program:
```c
struct my_value {
char buf[0x10000000];
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 17);
__type(key, int);
__type(value, struct my_value);
} map SEC(".maps");
char LICENSE[] SEC("license") = "GPL";
```
Example userspace program:
```c
int main(int argc, char *argv[]) {
struct bpf_object *obj;
char filename[256];
int err, ret = 0;
struct bpf_map *map;
int map_fd;
const __u64 max_entries = 17;
const __u64 value_size = 0x10000000; // 256MB
char *values, *keys;
__u32 count, out_batch;
if (argc != 2) {
printf("Usage: %s [bpf_prog.o]", argv[0]);
return EXIT_FAILURE;
}
snprintf(filename, sizeof(filename), "%s", argv[1]);
obj = bpf_object__open(filename);
if (libbpf_get_error(obj)) {
printf("BPF open failed!\n");
return EXIT_FAILURE;
}
values = calloc(max_entries, value_size);
if (!values) {
printf("calloc values failed!\n");
goto err_out;
}
keys = calloc(max_entries, sizeof(__u32));
if (!keys) {
printf("calloc keys failed!\n");
goto err_out;
}
err = bpf_object__load(obj);
if (err) {
printf("BPF load failed! err:%d\n", err);
goto err_out;
}
map = bpf_object__find_map_by_name(obj, "map");
if (!map) {
printf("map not found!\n");
goto err_out;
}
map_fd = bpf_map__fd(map);
if (map_fd < 0) {
printf("invalid map FD!\n");
goto err_out;
}
__u32 key;
for (__u64 i = 0; i < max_entries; i++) {
memset(values + (i * value_size), i & 0xFF, value_size);
key = i;
err = bpf_map_update_elem(map_fd, &key, values + (i * value_size), BPF_ANY);
if (err) {
printf("bpf_map_update_elem failed: %d\n", err);
goto err_out;
}
}
count = max_entries;
err = bpf_map_lookup_batch(map_fd, NULL, &out_batch, keys, values, &count,
NULL);
if (err) {
printf("bpf_map_lookup_batch failed: %d\n", err);
goto err_out;
}
printf("count: %u, out_batch: %u\n", count, out_batch);
for (__u64 i = 0; i < max_entries; i++) {
for (__u64 j = 0; j < value_size; j++) {
if (values[(i * value_size) + j] != (unsigned char)(i & 0xFF)) {
printf("Invalid map entry, key: %u, value: %hhu, i: %llu, j: %llu\n",
*(((__u32 *)keys) + i), values[(i * value_size) + j], i, j);
goto err_out;
}
}
}
printf("Finished with no errors!\n");
ret = EXIT_SUCCESS;
goto out;
err_out:
ret = EXIT_FAILURE;
out:
bpf_object__close(obj);
if (values)
free(values);
if (keys)
free(keys);
return ret;
}
```
The test needs enough free memory (around 14GB for the total system).
The key/value mismatch occurs when max_entries is 17 and value_size
is 0x10000000 (256MB). Reducing max_entries to 16 eliminates the issue.
Fixes: cb4d03a ("bpf: Add generic support for lookup batch op")
Signed-off-by: Masoud Aghasi <maghasi@disroot.org>
|
Upstream branch: cd35e1b |
0f3fa92 to
e69d6d8
Compare
Pull request for series with
subject: bpf: Fix u32 overflow issue in map batch operations
version: 1
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=1150846