* [PATCH] kho: fix signed shift UB in kho_preserved_memory_reserve()
@ 2026-08-16 9:00 Kiarash Azarnia
2026-08-16 9:25 ` Kiarash Azarnia
2026-08-17 5:51 ` Mike Rapoport
0 siblings, 2 replies; 3+ messages in thread
From: Kiarash Azarnia @ 2026-08-16 9:00 UTC (permalink / raw)
To: rppt, pasha.tatashin, pratyush
Cc: graf, kexec, linux-mm, linux-kernel, stable
kho_preserved_memory_reserve() computes the size of a preserved
reservation as:
sz = 1 << (order + PAGE_SHIFT);
`1` is a signed int, so the shift is signed-int arithmetic. For order
19 (a 2 GiB region) it produces 1 << 31, which is unrepresentable in
int and is undefined behavior; in practice it yields 0x80000000,
sign-extended on the assignment to the u64 sz. For order >= 20 the
shift count exceeds the width of int, which is also undefined. The
return value of memblock_reserve() is ignored and memblock_cap_size()
clamps the bogus size, so the kernel silently reserves the wrong
amount of memory for the preserved region.
kho_alloc_preserve() caps order at MAX_PAGE_ORDER and cannot reach
order 19, but a boot-time reserve_mem= region of at least 2 GiB drives
kho_preserve_pages() to compute order 19, and kho_preserve_pages() is
EXPORT_SYMBOL_GPL(), so the path is reachable.
Cast the shift operand to u64 so the arithmetic is done in 64 bits:
sz = (u64)1 << (order + PAGE_SHIFT);
Fixes: 3f2ad90060f6 ("kho: adopt radix tree for preserved memory tracking")
Cc: stable@vger.kernel.org
Signed-off-by: Kiarash Azarnia <kiarash.azarnia@gmail.com>
---
kernel/liveupdate/kexec_handover.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 175c08a6e41e..c79f48bd64ac 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -501,7 +501,7 @@ static int __init kho_preserved_memory_reserve(phys_addr_t phys,
struct page *page;
u64 sz;
- sz = 1 << (order + PAGE_SHIFT);
+ sz = (u64)1 << (order + PAGE_SHIFT);
page = kho_get_preserved_page(phys, order);
/* Reserve the memory preserved in KHO in memblock */
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] kho: fix signed shift UB in kho_preserved_memory_reserve()
2026-08-16 9:00 [PATCH] kho: fix signed shift UB in kho_preserved_memory_reserve() Kiarash Azarnia
@ 2026-08-16 9:25 ` Kiarash Azarnia
2026-08-17 5:51 ` Mike Rapoport
1 sibling, 0 replies; 3+ messages in thread
From: Kiarash Azarnia @ 2026-08-16 9:25 UTC (permalink / raw)
To: rppt, pasha.tatashin, pratyush; +Cc: graf, kexec, linux-mm, linux-kernel
Here is how I reproduced this, in case it is useful for review.
Minimal reproducer (prints what the function computes, both ways):
#include <stdio.h>
#define PAGE_SHIFT 12
int main(void)
{
int order;
for (order = 18; order <= 20; order++) {
unsigned long long before = 1 << (order + PAGE_SHIFT);
unsigned long long after = (unsigned long long)1 << (order + PAGE_SHIFT);
printf("order=%2d before=0x%llx after=0x%llx\n", order, before, after);
}
return 0;
}
prints:
order=18 before=0x40000000 after=0x40000000
order=19 before=0xffffffff80000000 after=0x80000000
order=20 before=0x1 after=0x100000000
Order 19 is a 2 GiB region, reachable from a reserve_mem=2G boot.
It also shows on a real boot: with CONFIG_KEXEC_HANDOVER=y, CONFIG_LIVEUPDATE=y,
CONFIG_UBSAN unset, and
reserve_mem=2G:2G:khotest kho_scratch=128M,128M,128M kho=on liveupdate=on
kexec -l -s --reuse-cmdline --append=" luo_stage=2"
stage 2 warned in memblock_add_range and lost ~820 MB (MemTotal 5181908 kB vs
6004928 kB in stage 1); after the fix, no WARN, MemTotal 6004884 kB.
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] kho: fix signed shift UB in kho_preserved_memory_reserve()
2026-08-16 9:00 [PATCH] kho: fix signed shift UB in kho_preserved_memory_reserve() Kiarash Azarnia
2026-08-16 9:25 ` Kiarash Azarnia
@ 2026-08-17 5:51 ` Mike Rapoport
1 sibling, 0 replies; 3+ messages in thread
From: Mike Rapoport @ 2026-08-17 5:51 UTC (permalink / raw)
To: Kiarash Azarnia
Cc: pasha.tatashin, pratyush, graf, kexec, linux-mm, linux-kernel,
stable
On Sun, Aug 16, 2026 at 12:30:37PM +0330, Kiarash Azarnia wrote:
> kho_preserved_memory_reserve() computes the size of a preserved
> reservation as:
>
> sz = 1 << (order + PAGE_SHIFT);
>
> `1` is a signed int, so the shift is signed-int arithmetic. For order
> 19 (a 2 GiB region) it produces 1 << 31, which is unrepresentable in
> int and is undefined behavior; in practice it yields 0x80000000,
> sign-extended on the assignment to the u64 sz. For order >= 20 the
> shift count exceeds the width of int, which is also undefined. The
> return value of memblock_reserve() is ignored and memblock_cap_size()
> clamps the bogus size, so the kernel silently reserves the wrong
> amount of memory for the preserved region.
>
> kho_alloc_preserve() caps order at MAX_PAGE_ORDER and cannot reach
> order 19, but a boot-time reserve_mem= region of at least 2 GiB drives
> kho_preserve_pages() to compute order 19, and kho_preserve_pages() is
> EXPORT_SYMBOL_GPL(), so the path is reachable.
This looks like LLM generated, please make sure to add Assisted-by tag next
time.
> Cast the shift operand to u64 so the arithmetic is done in 64 bits:
>
> sz = (u64)1 << (order + PAGE_SHIFT);
>
> Fixes: 3f2ad90060f6 ("kho: adopt radix tree for preserved memory tracking")
> Cc: stable@vger.kernel.org
> Signed-off-by: Kiarash Azarnia <kiarash.azarnia@gmail.com>
> ---
> kernel/liveupdate/kexec_handover.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
> index 175c08a6e41e..c79f48bd64ac 100644
> --- a/kernel/liveupdate/kexec_handover.c
> +++ b/kernel/liveupdate/kexec_handover.c
> @@ -501,7 +501,7 @@ static int __init kho_preserved_memory_reserve(phys_addr_t phys,
> struct page *page;
> u64 sz;
>
> - sz = 1 << (order + PAGE_SHIFT);
> + sz = (u64)1 << (order + PAGE_SHIFT);
> page = kho_get_preserved_page(phys, order);
This is already fixed:
https://patch.msgid.link/20260727150240.889555-1-pratyush@kernel.org
> /* Reserve the memory preserved in KHO in memblock */
> --
> 2.53.0
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-17 5:51 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-16 9:00 [PATCH] kho: fix signed shift UB in kho_preserved_memory_reserve() Kiarash Azarnia
2026-08-16 9:25 ` Kiarash Azarnia
2026-08-17 5:51 ` Mike Rapoport
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox