* [PATCH RFC 0/5] liveupdate: validate restored LUO metadata
@ 2026-05-01 9:46 Cris Jacob Maamor
2026-05-01 9:46 ` [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor
` (5 more replies)
0 siblings, 6 replies; 14+ messages in thread
From: Cris Jacob Maamor @ 2026-05-01 9:46 UTC (permalink / raw)
To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav
Cc: Alexander Graf, Andrew Morton, Dan Carpenter, Greg Kroah-Hartman,
kexec, linux-mm, linux-kernel
LUO restores metadata from KHO/FDT during liveupdate. The restored
metadata contains physical addresses and count fields used to access and
walk preserved session, file-set, and FLB arrays.
This series adds a non-consuming KHO preserved-range check and uses it
before phys_to_virt() on restored metadata addresses. It also rejects
restored counts above LUO_SESSION_MAX, LUO_FILE_MAX, and LUO_FLB_MAX
before traversal.
As far as I can tell, this is root/admin-only; I do not have evidence
that a normal unprivileged user can trigger it directly.
I have not reproduced this in a VM yet, so I may be missing a KHO
invariant or a preferred restore helper pattern. Feedback on the helper
semantics is welcome.
Cris Jacob Maamor (5):
kexec: handover: add helper to check preserved page ranges
liveupdate: validate restored LUO FDT before use
liveupdate: validate restored LUO session metadata
liveupdate: validate restored LUO file-set metadata
liveupdate: validate restored LUO FLB metadata
include/linux/kexec_handover.h | 6 +++++
kernel/liveupdate/kexec_handover.c | 35 ++++++++++++++++++++++++++++++
kernel/liveupdate/luo_core.c | 10 ++++++++-
kernel/liveupdate/luo_file.c | 14 ++++++++++--
kernel/liveupdate/luo_flb.c | 23 +++++++++++++++++++-
kernel/liveupdate/luo_session.c | 22 +++++++++++++++++--
6 files changed, 104 insertions(+), 6 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor @ 2026-05-01 9:46 ` Cris Jacob Maamor 2026-05-01 10:11 ` Greg Kroah-Hartman 2026-05-01 9:46 ` [PATCH RFC 2/5] liveupdate: validate restored LUO FDT before use Cris Jacob Maamor ` (4 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 9:46 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Dan Carpenter, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- include/linux/kexec_handover.h | 6 +++++ kernel/liveupdate/kexec_handover.c | 35 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 8968c56d2d73..fb09943ab232 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -19,6 +19,7 @@ struct page; #ifdef CONFIG_KEXEC_HANDOVER bool kho_is_enabled(void); bool is_kho_boot(void); +bool kho_is_preserved(phys_addr_t phys, unsigned long nr_pages); int kho_preserve_folio(struct folio *folio); void kho_unpreserve_folio(struct folio *folio); @@ -51,6 +52,11 @@ static inline bool is_kho_boot(void) return false; } +static inline bool kho_is_preserved(phys_addr_t phys, unsigned long nr_pages) +{ + return false; +} + static inline int kho_preserve_folio(struct folio *folio) { return -EOPNOTSUPP; diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 94762de1fe5f..fe9f11190705 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "KHO: " fmt +#include <linux/bits.h> #include <linux/cleanup.h> #include <linux/cma.h> #include <linux/kmemleak.h> @@ -429,6 +430,40 @@ static struct page *kho_restore_page(phys_addr_t phys, bool is_folio) return page; } +/** + * kho_is_preserved - Verify that a physical page range belongs to KHO. + * @phys: physical address of the first page in the range. + * @nr_pages: number of pages that the caller expects to access. + * + * Use this before phys_to_virt() when a physical address comes from restored + * metadata. It checks that @phys starts a KHO-preserved allocation large + * enough to cover @nr_pages. + * + * This only checks the KHO marker. It does not restore, free, or take + * ownership of the pages. + * + * Return: true if @phys starts a preserved KHO allocation large enough to cover + * @nr_pages, false otherwise. + */ +bool kho_is_preserved(phys_addr_t phys, unsigned long nr_pages) +{ + struct page *page; + union kho_page_info info; + + if (!nr_pages || !IS_ALIGNED(phys, PAGE_SIZE)) + return false; + + page = pfn_to_online_page(PHYS_PFN(phys)); + if (!page) + return false; + + info.page_private = page->private; + if (info.magic != KHO_PAGE_MAGIC || info.order >= BITS_PER_LONG) + return false; + + return nr_pages <= BIT(info.order); +} + /** * kho_restore_folio - recreates the folio from the preserved memory. * @phys: physical address of the folio. -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges 2026-05-01 9:46 ` [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor @ 2026-05-01 10:11 ` Greg Kroah-Hartman 0 siblings, 0 replies; 14+ messages in thread From: Greg Kroah-Hartman @ 2026-05-01 10:11 UTC (permalink / raw) To: Cris Jacob Maamor Cc: Mike Rapoport, Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Dan Carpenter, kexec, linux-mm, linux-kernel On Fri, May 01, 2026 at 05:46:33PM +0800, Cris Jacob Maamor wrote: > Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> For obvious reasons, we can't take patches without any changelog text (nor do you want us to.) And when a pathc is "RFC", what specific comments are you asking for? Why don't you feel this is good enough to take now? thanks, greg k-h ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH RFC 2/5] liveupdate: validate restored LUO FDT before use 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor @ 2026-05-01 9:46 ` Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 3/5] liveupdate: validate restored LUO session metadata Cris Jacob Maamor ` (3 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 9:46 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Dan Carpenter, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 803f51c84275..633a16434164 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -82,6 +82,7 @@ early_param("liveupdate", early_liveupdate_param); static int __init luo_early_startup(void) { + size_t fdt_size; phys_addr_t fdt_phys; int err, ln_size; const void *ptr; @@ -94,7 +95,8 @@ static int __init luo_early_startup(void) } /* Retrieve LUO subtree, and verify its format. */ - err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, NULL); + err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, + &fdt_size); if (err) { if (err != -ENOENT) { pr_err("failed to retrieve FDT '%s' from KHO: %pe\n", @@ -105,6 +107,12 @@ static int __init luo_early_startup(void) return 0; } + if (!fdt_size || fdt_size > LUO_FDT_SIZE || + !kho_is_preserved(fdt_phys, DIV_ROUND_UP(fdt_size, PAGE_SIZE))) { + pr_err("Invalid LUO FDT from KHO\n"); + return -EINVAL; + } + luo_global.fdt_in = phys_to_virt(fdt_phys); err = fdt_node_check_compatible(luo_global.fdt_in, 0, LUO_FDT_COMPATIBLE); -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH RFC 3/5] liveupdate: validate restored LUO session metadata 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 2/5] liveupdate: validate restored LUO FDT before use Cris Jacob Maamor @ 2026-05-01 9:46 ` Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 4/5] liveupdate: validate restored LUO file-set metadata Cris Jacob Maamor ` (2 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 9:46 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Dan Carpenter, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_session.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c index a3327a28fc1f..0244c071936d 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -501,7 +501,18 @@ int __init luo_session_setup_incoming(void *fdt_in) } header_ser_pa = get_unaligned((u64 *)ptr); + if (!kho_is_preserved(header_ser_pa, LUO_SESSION_PGCNT)) { + pr_err("Session header is not KHO preserved: %#llx\n", + (unsigned long long)header_ser_pa); + return -EINVAL; + } + header_ser = phys_to_virt(header_ser_pa); + if (header_ser->count > LUO_SESSION_MAX) { + pr_err("Invalid session count: %llu\n", + (unsigned long long)header_ser->count); + return -EINVAL; + } luo_session_global.incoming.header_ser = header_ser; luo_session_global.incoming.ser = (void *)(header_ser + 1); @@ -515,6 +526,7 @@ int luo_session_deserialize(void) struct luo_session_header *sh = &luo_session_global.incoming; static bool is_deserialized; static int err; + u64 count; /* If has been deserialized, always return the same error code */ if (is_deserialized) @@ -524,6 +536,13 @@ int luo_session_deserialize(void) if (!sh->active) return 0; + count = sh->header_ser->count; + if (count > LUO_SESSION_MAX) { + pr_err("Invalid session count: %llu\n", + (unsigned long long)count); + return -EINVAL; + } + /* * Note on error handling: * @@ -539,7 +558,7 @@ int luo_session_deserialize(void) * userspace to detect the failure and trigger a reboot, which will * reliably reset devices and reclaim memory. */ - for (int i = 0; i < sh->header_ser->count; i++) { + for (u64 i = 0; i < count; i++) { struct luo_session *session; session = luo_session_alloc(sh->ser[i].name); @@ -606,4 +625,3 @@ int luo_session_serialize(void) return err; } - -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH RFC 4/5] liveupdate: validate restored LUO file-set metadata 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor ` (2 preceding siblings ...) 2026-05-01 9:46 ` [PATCH RFC 3/5] liveupdate: validate restored LUO session metadata Cris Jacob Maamor @ 2026-05-01 9:46 ` Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 5/5] liveupdate: validate restored LUO FLB metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 9:46 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Dan Carpenter, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_file.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c index a0a419085e28..cde43d822f8f 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -783,11 +783,21 @@ int luo_file_deserialize(struct luo_file_set *file_set, struct luo_file_ser *file_ser; u64 i; - if (!file_set_ser->files) { - WARN_ON(file_set_ser->count); + if (!file_set_ser->count) { + if (file_set_ser->files) + return -EINVAL; return 0; } + if (file_set_ser->count > LUO_FILE_MAX) + return -EINVAL; + + if (!file_set_ser->files) + return -EINVAL; + + if (!kho_is_preserved(file_set_ser->files, LUO_FILE_PGCNT)) + return -EINVAL; + file_set->count = file_set_ser->count; file_set->files = phys_to_virt(file_set_ser->files); -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH RFC 5/5] liveupdate: validate restored LUO FLB metadata 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor ` (3 preceding siblings ...) 2026-05-01 9:46 ` [PATCH RFC 4/5] liveupdate: validate restored LUO file-set metadata Cris Jacob Maamor @ 2026-05-01 9:46 ` Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 9:46 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Dan Carpenter, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_flb.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c index 00f5494812c4..e80032669cea 100644 --- a/kernel/liveupdate/luo_flb.c +++ b/kernel/liveupdate/luo_flb.c @@ -162,6 +162,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb) struct luo_flb_header *fh = &luo_flb_global.incoming; struct liveupdate_flb_op_args args = {0}; bool found = false; + u64 count; int err; guard(mutex)(&private->incoming.lock); @@ -175,7 +176,14 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb) if (!fh->active) return -ENODATA; - for (int i = 0; i < fh->header_ser->count; i++) { + count = fh->header_ser->count; + if (count > LUO_FLB_MAX) { + pr_err("Invalid FLB count: %llu\n", + (unsigned long long)count); + return -EINVAL; + } + + for (u64 i = 0; i < count; i++) { if (!strcmp(fh->ser[i].name, flb->compatible)) { private->incoming.data = fh->ser[i].data; private->incoming.count = fh->ser[i].count; @@ -620,7 +628,20 @@ int __init luo_flb_setup_incoming(void *fdt_in) } header_ser_pa = get_unaligned((u64 *)ptr); + if (!kho_is_preserved(header_ser_pa, LUO_FLB_PGCNT)) { + pr_err("FLB header is not KHO preserved: %#llx\n", + (unsigned long long)header_ser_pa); + return -EINVAL; + } + header_ser = phys_to_virt(header_ser_pa); + if (header_ser->pgcnt != LUO_FLB_PGCNT || + header_ser->count > LUO_FLB_MAX) { + pr_err("Invalid FLB header: pgcnt %llu count %llu\n", + (unsigned long long)header_ser->pgcnt, + (unsigned long long)header_ser->count); + return -EINVAL; + } luo_flb_global.incoming.header_ser = header_ser; luo_flb_global.incoming.ser = (void *)(header_ser + 1); -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 0/5] liveupdate: validate restored LUO metadata 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor ` (4 preceding siblings ...) 2026-05-01 9:46 ` [PATCH RFC 5/5] liveupdate: validate restored LUO FLB metadata Cris Jacob Maamor @ 2026-05-01 17:30 ` Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor ` (5 more replies) 5 siblings, 6 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 17:30 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel LUO restores metadata from KHO/FDT during liveupdate. The restored metadata contains physical addresses and count fields used to access and walk preserved session, file set, and FLB arrays. This series adds a non-consuming KHO preserved-range check and uses it before phys_to_virt() on restored metadata addresses. It also rejects restored counts above LUO_SESSION_MAX, LUO_FILE_MAX, and LUO_FLB_MAX before traversal. As far as I can tell, this is root/admin-only; I do not have evidence that a normal unprivileged user can trigger it directly. Changes since v1: - Dropped RFC marking. - Added changelog text to each patch. - No code changes. Cris Jacob Maamor (5): kexec: handover: add helper to check preserved page ranges liveupdate: validate LUO FDT physical address before mapping liveupdate: validate restored LUO session metadata liveupdate: validate restored LUO file set metadata liveupdate: validate restored LUO FLB metadata include/linux/kexec_handover.h | 6 +++++ kernel/liveupdate/kexec_handover.c | 35 ++++++++++++++++++++++++++++++ kernel/liveupdate/luo_core.c | 10 ++++++++- kernel/liveupdate/luo_file.c | 14 ++++++++++-- kernel/liveupdate/luo_flb.c | 23 +++++++++++++++++++- kernel/liveupdate/luo_session.c | 22 +++++++++++++++++-- 6 files changed, 104 insertions(+), 6 deletions(-) -- 2.53.0 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/5] kexec: handover: add helper to check preserved page ranges 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor @ 2026-05-01 17:30 ` Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 2/5] liveupdate: validate LUO FDT physical address before mapping Cris Jacob Maamor ` (4 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 17:30 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel Restore code should not use phys_to_virt() on physical addresses from restored metadata until it verifies that the range was preserved by KHO. Add kho_is_preserved() so callers can check a preserved page range without restoring, freeing, or taking ownership of the pages. Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- include/linux/kexec_handover.h | 6 +++++ kernel/liveupdate/kexec_handover.c | 35 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 8968c56d2d73..fb09943ab232 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -19,6 +19,7 @@ struct page; #ifdef CONFIG_KEXEC_HANDOVER bool kho_is_enabled(void); bool is_kho_boot(void); +bool kho_is_preserved(phys_addr_t phys, unsigned long nr_pages); int kho_preserve_folio(struct folio *folio); void kho_unpreserve_folio(struct folio *folio); @@ -51,6 +52,11 @@ static inline bool is_kho_boot(void) return false; } +static inline bool kho_is_preserved(phys_addr_t phys, unsigned long nr_pages) +{ + return false; +} + static inline int kho_preserve_folio(struct folio *folio) { return -EOPNOTSUPP; diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 94762de1fe5f..fe9f11190705 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) "KHO: " fmt +#include <linux/bits.h> #include <linux/cleanup.h> #include <linux/cma.h> #include <linux/kmemleak.h> @@ -429,6 +430,40 @@ static struct page *kho_restore_page(phys_addr_t phys, bool is_folio) return page; } +/** + * kho_is_preserved - Verify that a physical page range belongs to KHO. + * @phys: physical address of the first page in the range. + * @nr_pages: number of pages that the caller expects to access. + * + * Use this before phys_to_virt() when a physical address comes from restored + * metadata. It checks that @phys starts a KHO-preserved allocation large + * enough to cover @nr_pages. + * + * This only checks the KHO marker. It does not restore, free, or take + * ownership of the pages. + * + * Return: true if @phys starts a preserved KHO allocation large enough to cover + * @nr_pages, false otherwise. + */ +bool kho_is_preserved(phys_addr_t phys, unsigned long nr_pages) +{ + struct page *page; + union kho_page_info info; + + if (!nr_pages || !IS_ALIGNED(phys, PAGE_SIZE)) + return false; + + page = pfn_to_online_page(PHYS_PFN(phys)); + if (!page) + return false; + + info.page_private = page->private; + if (info.magic != KHO_PAGE_MAGIC || info.order >= BITS_PER_LONG) + return false; + + return nr_pages <= BIT(info.order); +} + /** * kho_restore_folio - recreates the folio from the preserved memory. * @phys: physical address of the folio. -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/5] liveupdate: validate LUO FDT physical address before mapping 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor @ 2026-05-01 17:30 ` Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 3/5] liveupdate: validate restored LUO session metadata Cris Jacob Maamor ` (3 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 17:30 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel LUO gets the restored FDT address from KHO and maps it with phys_to_virt(). Check the FDT size and make sure the address range is KHO-preserved before mapping it. Reject empty or oversized FDT metadata. Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 803f51c84275..633a16434164 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -82,6 +82,7 @@ early_param("liveupdate", early_liveupdate_param); static int __init luo_early_startup(void) { + size_t fdt_size; phys_addr_t fdt_phys; int err, ln_size; const void *ptr; @@ -94,7 +95,8 @@ static int __init luo_early_startup(void) } /* Retrieve LUO subtree, and verify its format. */ - err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, NULL); + err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, + &fdt_size); if (err) { if (err != -ENOENT) { pr_err("failed to retrieve FDT '%s' from KHO: %pe\n", @@ -105,6 +107,12 @@ static int __init luo_early_startup(void) return 0; } + if (!fdt_size || fdt_size > LUO_FDT_SIZE || + !kho_is_preserved(fdt_phys, DIV_ROUND_UP(fdt_size, PAGE_SIZE))) { + pr_err("Invalid LUO FDT from KHO\n"); + return -EINVAL; + } + luo_global.fdt_in = phys_to_virt(fdt_phys); err = fdt_node_check_compatible(luo_global.fdt_in, 0, LUO_FDT_COMPATIBLE); -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/5] liveupdate: validate restored LUO session metadata 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 2/5] liveupdate: validate LUO FDT physical address before mapping Cris Jacob Maamor @ 2026-05-01 17:30 ` Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 4/5] liveupdate: validate restored LUO file set metadata Cris Jacob Maamor ` (2 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 17:30 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel The restored FDT contains the physical address of the LUO session header, which LUO maps before reading session metadata. Check that physical range against KHO-preserved memory before calling phys_to_virt(), and abort the restore if the physical range is not covered. The session header has a count that controls how far LUO walks the serialized session array. Check that count against LUO_SESSION_MAX before deserialization, and abort the restore if the value is out of range. Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_session.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c index a3327a28fc1f..0244c071936d 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -501,7 +501,18 @@ int __init luo_session_setup_incoming(void *fdt_in) } header_ser_pa = get_unaligned((u64 *)ptr); + if (!kho_is_preserved(header_ser_pa, LUO_SESSION_PGCNT)) { + pr_err("Session header is not KHO preserved: %#llx\n", + (unsigned long long)header_ser_pa); + return -EINVAL; + } + header_ser = phys_to_virt(header_ser_pa); + if (header_ser->count > LUO_SESSION_MAX) { + pr_err("Invalid session count: %llu\n", + (unsigned long long)header_ser->count); + return -EINVAL; + } luo_session_global.incoming.header_ser = header_ser; luo_session_global.incoming.ser = (void *)(header_ser + 1); @@ -515,6 +526,7 @@ int luo_session_deserialize(void) struct luo_session_header *sh = &luo_session_global.incoming; static bool is_deserialized; static int err; + u64 count; /* If has been deserialized, always return the same error code */ if (is_deserialized) @@ -524,6 +536,13 @@ int luo_session_deserialize(void) if (!sh->active) return 0; + count = sh->header_ser->count; + if (count > LUO_SESSION_MAX) { + pr_err("Invalid session count: %llu\n", + (unsigned long long)count); + return -EINVAL; + } + /* * Note on error handling: * @@ -539,7 +558,7 @@ int luo_session_deserialize(void) * userspace to detect the failure and trigger a reboot, which will * reliably reset devices and reclaim memory. */ - for (int i = 0; i < sh->header_ser->count; i++) { + for (u64 i = 0; i < count; i++) { struct luo_session *session; session = luo_session_alloc(sh->ser[i].name); @@ -606,4 +625,3 @@ int luo_session_serialize(void) return err; } - -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 4/5] liveupdate: validate restored LUO file set metadata 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor ` (2 preceding siblings ...) 2026-05-01 17:30 ` [PATCH v2 3/5] liveupdate: validate restored LUO session metadata Cris Jacob Maamor @ 2026-05-01 17:30 ` Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 5/5] liveupdate: validate restored LUO FLB metadata Cris Jacob Maamor 2026-05-01 19:34 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Pasha Tatashin 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 17:30 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel The restored session metadata provides the LUO file set address and count. LUO maps that address with phys_to_virt() and uses the restored count to walk the serialized file array. Reject invalid empty file set metadata, reject counts above LUO_FILE_MAX, and check that the physical range is KHO-preserved before mapping it. Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_file.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c index a0a419085e28..cde43d822f8f 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -783,11 +783,21 @@ int luo_file_deserialize(struct luo_file_set *file_set, struct luo_file_ser *file_ser; u64 i; - if (!file_set_ser->files) { - WARN_ON(file_set_ser->count); + if (!file_set_ser->count) { + if (file_set_ser->files) + return -EINVAL; return 0; } + if (file_set_ser->count > LUO_FILE_MAX) + return -EINVAL; + + if (!file_set_ser->files) + return -EINVAL; + + if (!kho_is_preserved(file_set_ser->files, LUO_FILE_PGCNT)) + return -EINVAL; + file_set->count = file_set_ser->count; file_set->files = phys_to_virt(file_set_ser->files); -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 5/5] liveupdate: validate restored LUO FLB metadata 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor ` (3 preceding siblings ...) 2026-05-01 17:30 ` [PATCH v2 4/5] liveupdate: validate restored LUO file set metadata Cris Jacob Maamor @ 2026-05-01 17:30 ` Cris Jacob Maamor 2026-05-01 19:34 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Pasha Tatashin 5 siblings, 0 replies; 14+ messages in thread From: Cris Jacob Maamor @ 2026-05-01 17:30 UTC (permalink / raw) To: Mike Rapoport, Pasha Tatashin, Pratyush Yadav Cc: Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel The restored FDT contains the physical address of the LUO FLB header, which LUO maps before using the restored FLB metadata. Check that the FLB header range is KHO-preserved before calling phys_to_virt(). Reject invalid page counts and counts above LUO_FLB_MAX before walking the restored FLB array. Signed-off-by: Cris Jacob Maamor <crisjacobmaamor@gmail.com> --- kernel/liveupdate/luo_flb.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c index 00f5494812c4..e80032669cea 100644 --- a/kernel/liveupdate/luo_flb.c +++ b/kernel/liveupdate/luo_flb.c @@ -162,6 +162,7 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb) struct luo_flb_header *fh = &luo_flb_global.incoming; struct liveupdate_flb_op_args args = {0}; bool found = false; + u64 count; int err; guard(mutex)(&private->incoming.lock); @@ -175,7 +176,14 @@ static int luo_flb_retrieve_one(struct liveupdate_flb *flb) if (!fh->active) return -ENODATA; - for (int i = 0; i < fh->header_ser->count; i++) { + count = fh->header_ser->count; + if (count > LUO_FLB_MAX) { + pr_err("Invalid FLB count: %llu\n", + (unsigned long long)count); + return -EINVAL; + } + + for (u64 i = 0; i < count; i++) { if (!strcmp(fh->ser[i].name, flb->compatible)) { private->incoming.data = fh->ser[i].data; private->incoming.count = fh->ser[i].count; @@ -620,7 +628,20 @@ int __init luo_flb_setup_incoming(void *fdt_in) } header_ser_pa = get_unaligned((u64 *)ptr); + if (!kho_is_preserved(header_ser_pa, LUO_FLB_PGCNT)) { + pr_err("FLB header is not KHO preserved: %#llx\n", + (unsigned long long)header_ser_pa); + return -EINVAL; + } + header_ser = phys_to_virt(header_ser_pa); + if (header_ser->pgcnt != LUO_FLB_PGCNT || + header_ser->count > LUO_FLB_MAX) { + pr_err("Invalid FLB header: pgcnt %llu count %llu\n", + (unsigned long long)header_ser->pgcnt, + (unsigned long long)header_ser->count); + return -EINVAL; + } luo_flb_global.incoming.header_ser = header_ser; luo_flb_global.incoming.ser = (void *)(header_ser + 1); -- 2.53.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/5] liveupdate: validate restored LUO metadata 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor ` (4 preceding siblings ...) 2026-05-01 17:30 ` [PATCH v2 5/5] liveupdate: validate restored LUO FLB metadata Cris Jacob Maamor @ 2026-05-01 19:34 ` Pasha Tatashin 5 siblings, 0 replies; 14+ messages in thread From: Pasha Tatashin @ 2026-05-01 19:34 UTC (permalink / raw) To: Cris Jacob Maamor Cc: Mike Rapoport, Pasha Tatashin, Pratyush Yadav, Alexander Graf, Andrew Morton, Greg Kroah-Hartman, kexec, linux-mm, linux-kernel On 05-02 01:30, Cris Jacob Maamor wrote: > LUO restores metadata from KHO/FDT during liveupdate. The restored > metadata contains physical addresses and count fields used to access and > walk preserved session, file set, and FLB arrays. > > This series adds a non-consuming KHO preserved-range check and uses it > before phys_to_virt() on restored metadata addresses. It also rejects > restored counts above LUO_SESSION_MAX, LUO_FILE_MAX, and LUO_FLB_MAX > before traversal. > > As far as I can tell, this is root/admin-only; I do not have evidence > that a normal unprivileged user can trigger it directly. > > Changes since v1: > - Dropped RFC marking. > - Added changelog text to each patch. > - No code changes. > > Cris Jacob Maamor (5): > kexec: handover: add helper to check preserved page ranges > liveupdate: validate LUO FDT physical address before mapping > liveupdate: validate restored LUO session metadata > liveupdate: validate restored LUO file set metadata > liveupdate: validate restored LUO FLB metadata I have replied separately in the security report to clarify that this is not a bug. The behavior follows the ABI specification exactly: we use the PA addresses and ranges provided by the KHO FDT tree. NAK > > include/linux/kexec_handover.h | 6 +++++ > kernel/liveupdate/kexec_handover.c | 35 ++++++++++++++++++++++++++++++ > kernel/liveupdate/luo_core.c | 10 ++++++++- > kernel/liveupdate/luo_file.c | 14 ++++++++++-- > kernel/liveupdate/luo_flb.c | 23 +++++++++++++++++++- > kernel/liveupdate/luo_session.c | 22 +++++++++++++++++-- > 6 files changed, 104 insertions(+), 6 deletions(-) > > -- > 2.53.0 > ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-05-01 19:34 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-01 9:46 [PATCH RFC 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor 2026-05-01 10:11 ` Greg Kroah-Hartman 2026-05-01 9:46 ` [PATCH RFC 2/5] liveupdate: validate restored LUO FDT before use Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 3/5] liveupdate: validate restored LUO session metadata Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 4/5] liveupdate: validate restored LUO file-set metadata Cris Jacob Maamor 2026-05-01 9:46 ` [PATCH RFC 5/5] liveupdate: validate restored LUO FLB metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 1/5] kexec: handover: add helper to check preserved page ranges Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 2/5] liveupdate: validate LUO FDT physical address before mapping Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 3/5] liveupdate: validate restored LUO session metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 4/5] liveupdate: validate restored LUO file set metadata Cris Jacob Maamor 2026-05-01 17:30 ` [PATCH v2 5/5] liveupdate: validate restored LUO FLB metadata Cris Jacob Maamor 2026-05-01 19:34 ` [PATCH v2 0/5] liveupdate: validate restored LUO metadata Pasha Tatashin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox