libbpf: Fix double-free when linker processes empty sections
Double-free error in bpf_linker__free() was reported by James Hilliard. The error is caused by miss-use of realloc() in extend_sec(). The error occurs when two files with empty sections of the same name are linked: - when first file is processed: - extend_sec() calls realloc(dst->raw_data, dst_align_sz) with dst->raw_data == NULL and dst_align_sz == 0; - dst->raw_data is set to a special pointer to a memory block of size zero; - when second file is processed: - extend_sec() calls realloc(dst->raw_data, dst_align_sz) with dst->raw_data == <special pointer> and dst_align_sz == 0; - realloc() "frees" dst->raw_data special pointer and returns NULL; - extend_sec() exits with -ENOMEM, and the old dst->raw_data value is preserved (it is now invalid); - eventually, bpf_linker__free() attempts to free dst->raw_data again. This patch fixes the bug by avoiding -ENOMEM exit for dst_align_sz == 0. The fix was suggested by Andrii Nakryiko <andrii.nakryiko@gmail.com>. Reported-by: James Hilliard <james.hilliard1@gmail.com> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Tested-by: James Hilliard <james.hilliard1@gmail.com> Link: https://lore.kernel.org/bpf/CADvTj4o7ZWUikKwNTwFq0O_AaX+46t_+Ca9gvWMYdWdRtTGeHQ@mail.gmail.com/ Link: https://lore.kernel.org/bpf/20230328004738.381898-3-eddyz87@gmail.com
This commit is contained in:
Родитель
7283137a76
Коммит
d08ab82f59
|
@ -1115,7 +1115,19 @@ static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src
|
||||||
|
|
||||||
if (src->shdr->sh_type != SHT_NOBITS) {
|
if (src->shdr->sh_type != SHT_NOBITS) {
|
||||||
tmp = realloc(dst->raw_data, dst_final_sz);
|
tmp = realloc(dst->raw_data, dst_final_sz);
|
||||||
if (!tmp)
|
/* If dst_align_sz == 0, realloc() behaves in a special way:
|
||||||
|
* 1. When dst->raw_data is NULL it returns:
|
||||||
|
* "either NULL or a pointer suitable to be passed to free()" [1].
|
||||||
|
* 2. When dst->raw_data is not-NULL it frees dst->raw_data and returns NULL,
|
||||||
|
* thus invalidating any "pointer suitable to be passed to free()" obtained
|
||||||
|
* at step (1).
|
||||||
|
*
|
||||||
|
* The dst_align_sz > 0 check avoids error exit after (2), otherwise
|
||||||
|
* dst->raw_data would be freed again in bpf_linker__free().
|
||||||
|
*
|
||||||
|
* [1] man 3 realloc
|
||||||
|
*/
|
||||||
|
if (!tmp && dst_align_sz > 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
dst->raw_data = tmp;
|
dst->raw_data = tmp;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче