Patch "libbpf: Use elf_getshdrnum() instead of e_shnum" has been added to the 6.0-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    libbpf: Use elf_getshdrnum() instead of e_shnum

to the 6.0-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     libbpf-use-elf_getshdrnum-instead-of-e_shnum.patch
and it can be found in the queue-6.0 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 141f0dc1324ca4ff7f01aa7b89f51a31f7a81327
Author: Shung-Hsi Yu <shung-hsi.yu@xxxxxxxx>
Date:   Wed Oct 12 10:23:51 2022 +0800

    libbpf: Use elf_getshdrnum() instead of e_shnum
    
    [ Upstream commit 51deedc9b8680953437dfe359e5268120de10e30 ]
    
    This commit replace e_shnum with the elf_getshdrnum() helper to fix two
    oss-fuzz-reported heap-buffer overflow in __bpf_object__open. Both
    reports are incorrectly marked as fixed and while still being
    reproducible in the latest libbpf.
    
      # clusterfuzz-testcase-minimized-bpf-object-fuzzer-5747922482888704
      libbpf: loading object 'fuzz-object' from buffer
      libbpf: sec_cnt is 0
      libbpf: elf: section(1) .data, size 0, link 538976288, flags 2020202020202020, type=2
      libbpf: elf: section(2) .data, size 32, link 538976288, flags 202020202020ff20, type=1
      =================================================================
      ==13==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000c0 at pc 0x0000005a7b46 bp 0x7ffd12214af0 sp 0x7ffd12214ae8
      WRITE of size 4 at 0x6020000000c0 thread T0
      SCARINESS: 46 (4-byte-write-heap-buffer-overflow-far-from-bounds)
          #0 0x5a7b45 in bpf_object__elf_collect /src/libbpf/src/libbpf.c:3414:24
          #1 0x5733c0 in bpf_object_open /src/libbpf/src/libbpf.c:7223:16
          #2 0x5739fd in bpf_object__open_mem /src/libbpf/src/libbpf.c:7263:20
          ...
    
    The issue lie in libbpf's direct use of e_shnum field in ELF header as
    the section header count. Where as libelf implemented an extra logic
    that, when e_shnum == 0 && e_shoff != 0, will use sh_size member of the
    initial section header as the real section header count (part of ELF
    spec to accommodate situation where section header counter is larger
    than SHN_LORESERVE).
    
    The above inconsistency lead to libbpf writing into a zero-entry calloc
    area. So intead of using e_shnum directly, use the elf_getshdrnum()
    helper provided by libelf to retrieve the section header counter into
    sec_cnt.
    
    Fixes: 0d6988e16a12 ("libbpf: Fix section counting logic")
    Fixes: 25bbbd7a444b ("libbpf: Remove assumptions about uniqueness of .rodata/.data/.bss maps")
    Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@xxxxxxxx>
    Signed-off-by: Andrii Nakryiko <andrii@xxxxxxxxxx>
    Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40868
    Link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=40957
    Link: https://lore.kernel.org/bpf/20221012022353.7350-2-shung-hsi.yu@xxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 264790796001..7f3cec7e7349 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -590,7 +590,7 @@ struct elf_state {
 	size_t shstrndx; /* section index for section name strings */
 	size_t strtabidx;
 	struct elf_sec_desc *secs;
-	int sec_cnt;
+	size_t sec_cnt;
 	int btf_maps_shndx;
 	__u32 btf_maps_sec_btf_id;
 	int text_shndx;
@@ -3282,10 +3282,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 	Elf64_Shdr *sh;
 
 	/* ELF section indices are 0-based, but sec #0 is special "invalid"
-	 * section. e_shnum does include sec #0, so e_shnum is the necessary
-	 * size of an array to keep all the sections.
+	 * section. Since section count retrieved by elf_getshdrnum() does
+	 * include sec #0, it is already the necessary size of an array to keep
+	 * all the sections.
 	 */
-	obj->efile.sec_cnt = obj->efile.ehdr->e_shnum;
+	if (elf_getshdrnum(obj->efile.elf, &obj->efile.sec_cnt)) {
+		pr_warn("elf: failed to get the number of sections for %s: %s\n",
+			obj->path, elf_errmsg(-1));
+		return -LIBBPF_ERRNO__FORMAT;
+	}
 	obj->efile.secs = calloc(obj->efile.sec_cnt, sizeof(*obj->efile.secs));
 	if (!obj->efile.secs)
 		return -ENOMEM;



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux