Alper Nebi Yasak has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/81366?usp=email )
Change subject: lib/ramdetect: Limit probe size to avoid uintptr_t overflow ......................................................................
lib/ramdetect: Limit probe size to avoid uintptr_t overflow
The probe_mb() function used in DRAM size detection and its variants used for QEMU mainboards use the following address calculation which can overflow on 32-bit architectures:
uintptr_t addr = dram_start + (size * MiB) - sizeof(uint32_t);
This can be observed on 32-bit RISC-V QEMU virtual machines where DRAM starts at 2 GiB. The process starts bisecting RAM with an initial size of 2 GiB (half of uintptr_t maximum) which makes the probed address just below 4 GiB due to the last term. If we have less than 2 GiB of DRAM, that probe fails and everything goes fine. Otherwise, following iterations overflow and probe the [1 GiB, 2 GiB) address range mistaking it for [3 GiB, 4 GiB) of DRAM. Somehow all of those succeed and we get a wrong result of 4095 MiB.
Make sure we don't pass sizes to probe_mb() that will result in these overflows. We could check for overflow in the calculation instead, but we already have other similar checks in probe_ramsize() and the primary user of this function (cbmem_top()) eventually returns uintptr_t anyway.
Change-Id: I65d0e97fff8708a034d1fd82fda32f0aecfb3382 Signed-off-by: Alper Nebi Yasak alpernebiyasak@gmail.com --- M src/lib/ramdetect.c 1 file changed, 3 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/66/81366/1
diff --git a/src/lib/ramdetect.c b/src/lib/ramdetect.c index cef3d57..6301e12 100644 --- a/src/lib/ramdetect.c +++ b/src/lib/ramdetect.c @@ -39,13 +39,14 @@ ssize_t i; size_t msb = 0; size_t discovered = 0; + size_t probe_safe = MIN(probe_size, (UINTPTR_MAX - dram_start) / MiB);
static size_t saved_result; if (saved_result) return saved_result;
/* Find the MSB + 1. */ - size_t tmp = probe_size; + size_t tmp = probe_safe; do { msb++; } while (tmp >>= 1); @@ -55,7 +56,7 @@
/* Compact binary search. */ for (i = msb; i >= 0; i--) { - if ((discovered | (1ULL << i)) > probe_size) + if ((discovered | (1ULL << i)) > probe_safe) continue; if (probe_mb(dram_start, (discovered | (1ULL << i)))) discovered |= (1ULL << i);