From nobody Mon Feb 9 06:28:12 2026 Received: from mail-yx1-f65.google.com (mail-yx1-f65.google.com [74.125.224.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0BEF7548EE for ; Fri, 19 Dec 2025 00:24:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766103842; cv=none; b=gRzaBAlvBPENViQrbL1vmCI79CgqyIr0Xrcg1kq74AK/10p5/fQzVEZbQpO2u5LSJYOeCkEhloGLVLQEuy5V7rgOnBxfJP0CAeWXazKXkudU/KJu32uHiadxSLJn+iGxmEn6QBmHEGFotesAtDEizerhNo8hI52JqLsz7RyaIzQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766103842; c=relaxed/simple; bh=o594dWfVT0pJl+4tlRpcFXI/UZEpe1lH7H3wLpZmKiA=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=AR1hH5h4v4XcXszG3/dLI8ScvH0hJbj6Z56MwbkgSsAmpTECs2nj3zHa6HqLjXix4jgqBkgoZFoQcjyDwGy3Ps6FEwi/l5iyQOWtpwR5GAdyL2YAsNJLbs6k5hksCmNxTl1vuUMKD2r8FNYpyX5X0yTcn/hiOCNWf+UTD0G/ZpE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=QmOmgcv0; arc=none smtp.client-ip=74.125.224.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="QmOmgcv0" Received: by mail-yx1-f65.google.com with SMTP id 956f58d0204a3-6432842cafdso1098975d50.2 for ; Thu, 18 Dec 2025 16:24:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1766103840; x=1766708640; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=VRLIZ+Id1A3SMxQgIBWSqDdOfJhpJaefDTuwxeIWUn4=; b=QmOmgcv0XsW6LBSwPa9Jy5H37Yr4HkPgOEZWEqWClfn+Bc6RclVQf1UnKr4dI5nnlN Xa5qs1WXAn96jdtC1oEmMV1U6Mbzg4+7P6AYJLiZ8Qmg9fMvIikX3LgOnJe+23z4BAu3 lDkb/goKk1rPpcRF5cScWP48hUM57CoB/1Uks9bCaS/Y1Ub/cEUNJLcnBpFmhgpuRjCx E94A4Q7JE/bd4hD/b5qwN8WInIzUEKaTL9lboz2juk9DM7PxrsghhRcybA3Q30/qV+76 /M7qF6OFgDmgwKWo/LdwsjpwZENTF2WWM2ow8RaO78qMtL9vpd4xUn7AjeontBFW7kzT 7IKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766103840; x=1766708640; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=VRLIZ+Id1A3SMxQgIBWSqDdOfJhpJaefDTuwxeIWUn4=; b=Y96k95I7tpKA6D27ZwcSTXRCb5xCXS270v9fwRTteXLK3XYFqFJQcGJWaFRYyKR+PM U+oqQSfYGufzSCUe5tyU1TiFv9hFnyqi9ivWcQMwADbLcTYRK2xn9A6QVLexWqR7lKA5 VzK6Ih4A1jVBjlF3uB5JdhhfGhsPjcvwzRY15kaGwUj1M+Gxq2ZHeFZJ7cGINJGnbLNG SutSNb3hV4az4T6aArIXKKyfU2g3//FWuUkSJUSmkAm2qKbOCdlmEwMgWohXClkfS3jG JAHcafJPJNB/j1zZjrxb71O8Yu9WWEozR8w95SvjR6FOOO3X4u/C0oyMmM1c3ekrIOTV FDPQ== X-Forwarded-Encrypted: i=1; AJvYcCW5UeX/43XtYAuVcfAeZojghz4BFvxk1otVsSxP8w2tqxEWu1oDfvNt0d6bnfw99RMHNM2iRl66cfy7HMo=@vger.kernel.org X-Gm-Message-State: AOJu0Yw9untcuuqYFe/4vncbJRMMNiM4V2ydjWdfF1f3AQNMIA4rLZ4O x/jZ/qKhfcvXdmVCEpch2Yjq6na9khBW4JrjCB9W17XrGwwKOM/ZvL6Tr+xhRfS78eoSXcAlKMc ePkVh X-Gm-Gg: AY/fxX4QO7oSWfMUSghXQ5/yqRDoCRsTTCiFKLkJaIIMzFX7olzBjLxmIaSoxb/JbUM nBUXcVWUAKTT9UAqeaZ0dL3RSGLtyn8r5IyudhG6kUEPQ51mrFDwq6HvWAMsAnIBCztLvXWho87 O9pkSbdhvxliz7/DKW/Y1lqFvuUDejvXk71s7gjhg/cWg5AryIRA5ogKnA/6zIvg4Wo+pl3LuKf Yr++IGx9hrMJ5N+awJ8uUarUKTvxqVEKhM++GUfj+vh+vTxtGCviRDX333wPQDWu/dkp3vdtmYi vETSZSmCf4DiHCGNNtiR9W9559dPxGIUpawe7i0vg5eqKbLndxM/pTa77+AwHL7tpP5WE2I0YPd sIFYS7OMl5eW3ER+0amF9XSD5EfyU8b0j0eA3ORGtyET+rudDBpHnLWY+NFXLAXyvpRqhjAahoc 1gS3LZGif2OYEDNcvxEaSPNYlE/bwA8wy5vuy7ATxcuyjD3Zy/sRtyn98w+Z1wRuj9bA2IJWEeD arDYwrf6d/dqX8jpSdMCijreUCCQTshiw4fkQ== X-Google-Smtp-Source: AGHT+IEFAtXPoKS1+Zlj4yJmeQNwxl11BdgyoU/smQ241gIO6ZqWceiGoF12B4JGc5G8V13yPkNL6g== X-Received: by 2002:a05:690e:169e:b0:640:fabf:565d with SMTP id 956f58d0204a3-6466a87e489mr1003195d50.43.1766103839999; Thu, 18 Dec 2025 16:23:59 -0800 (PST) Received: from soleen.c.googlers.com.com (182.221.85.34.bc.googleusercontent.com. [34.85.221.182]) by smtp.gmail.com with ESMTPSA id 00721157ae682-78fb452c471sm3599487b3.45.2025.12.18.16.23.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Dec 2025 16:23:59 -0800 (PST) From: Pasha Tatashin To: akpm@linux-foundation.org, pasha.tatashin@soleen.com, rppt@kernel.org, graf@amazon.com, linux-kernel@vger.kernel.org, kexec@lists.infradead.org, linux-mm@kvack.org, pratyush@kernel.org, ricardo.neri-calderon@linux.intel.com Subject: [PATCH] kho: validate preserved memory map during population Date: Thu, 18 Dec 2025 19:23:55 -0500 Message-ID: <20251219002355.3323896-1-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.52.0.322.g1dd061c0dc-goog Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If the previous kernel enabled KHO but did not call kho_finalize() (e.g., CONFIG_LIVEUPDATE=3Dn or userspace skipped the finalization step), the 'preserved-memory-map' property in the FDT remains empty/zero. Previously, kho_populate() would succeed regardless of the memory map's state, reserving the incoming scratch regions in memblock. However, kho_memory_init() would later fail to deserialize the empty map. By that time, the scratch regions were already registered, leading to partial initialization and subsequent list corruption (double-free) during kho_init(). Move the validation of the preserved memory map earlier into kho_populate(). If the memory map is empty/NULL: 1. Abort kho_populate() immediately with -ENOENT. 2. Do not register or reserve the incoming scratch memory, allowing the new kernel to reclaim those pages as standard free memory. 3. Leave the global 'kho_in' state uninitialized. Consequently, kho_memory_init() sees no active KHO context (kho_in.mem_chunks is NULL) and falls back to kho_reserve_scratch(), allocating fresh scratch memory as if it were a standard cold boot. Fixes: de51999e687c ("kho: allow memory preservation state updates after fi= nalization") Reported-by: Ricardo Closes: https://lore.kernel.org/all/20251218215613.GA17304@ranerica-svr.sc.= intel.com Signed-off-by: Pasha Tatashin --- kernel/liveupdate/kexec_handover.c | 36 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_h= andover.c index 9dc51fab604f..96c708f753d4 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -460,10 +460,9 @@ static void __init deserialize_bitmap(unsigned int ord= er, } } =20 -/* Return true if memory was deserizlied */ -static bool __init kho_mem_deserialize(const void *fdt) +/* Returns head of preserved physical memory chunks pointer from FDT */ +static struct khoser_mem_chunk * __init kho_get_mem_chunks(const void *fdt) { - struct khoser_mem_chunk *chunk; const void *mem_ptr; u64 mem; int len; @@ -471,16 +470,16 @@ static bool __init kho_mem_deserialize(const void *fd= t) mem_ptr =3D fdt_getprop(fdt, 0, PROP_PRESERVED_MEMORY_MAP, &len); if (!mem_ptr || len !=3D sizeof(u64)) { pr_err("failed to get preserved memory bitmaps\n"); - return false; + return NULL; } =20 mem =3D get_unaligned((const u64 *)mem_ptr); - chunk =3D mem ? phys_to_virt(mem) : NULL; =20 - /* No preserved physical pages were passed, no deserialization */ - if (!chunk) - return false; + return mem ? phys_to_virt(mem) : NULL; +} =20 +static void __init kho_mem_deserialize(struct khoser_mem_chunk *chunk) +{ while (chunk) { unsigned int i; =20 @@ -489,8 +488,6 @@ static bool __init kho_mem_deserialize(const void *fdt) &chunk->bitmaps[i]); chunk =3D KHOSER_LOAD_PTR(chunk->hdr.next); } - - return true; } =20 /* @@ -1253,6 +1250,7 @@ bool kho_finalized(void) struct kho_in { phys_addr_t fdt_phys; phys_addr_t scratch_phys; + struct khoser_mem_chunk *mem_chunks; struct kho_debugfs dbg; }; =20 @@ -1434,12 +1432,10 @@ static void __init kho_release_scratch(void) =20 void __init kho_memory_init(void) { - if (kho_in.scratch_phys) { + if (kho_in.mem_chunks) { kho_scratch =3D phys_to_virt(kho_in.scratch_phys); kho_release_scratch(); - - if (!kho_mem_deserialize(kho_get_fdt())) - kho_in.fdt_phys =3D 0; + kho_mem_deserialize(kho_in.mem_chunks); } else { kho_reserve_scratch(); } @@ -1448,8 +1444,9 @@ void __init kho_memory_init(void) void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys, u64 scratch_len) { - void *fdt =3D NULL; + struct khoser_mem_chunk *mem_chunks; struct kho_scratch *scratch =3D NULL; + void *fdt =3D NULL; int err =3D 0; unsigned int scratch_cnt =3D scratch_len / sizeof(*kho_scratch); =20 @@ -1475,6 +1472,14 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 f= dt_len, goto out; } =20 + mem_chunks =3D kho_get_mem_chunks(fdt); + if (!mem_chunks) { + pr_warn("setup: handover FDT (0x%llx) present but no preserved memory fo= und\n", + fdt_phys); + err =3D -ENOENT; + goto out; + } + scratch =3D early_memremap(scratch_phys, scratch_len); if (!scratch) { pr_warn("setup: failed to memremap scratch (phys=3D0x%llx, len=3D%lld)\n= ", @@ -1515,6 +1520,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fd= t_len, =20 kho_in.fdt_phys =3D fdt_phys; kho_in.scratch_phys =3D scratch_phys; + kho_in.mem_chunks =3D mem_chunks; kho_scratch_cnt =3D scratch_cnt; pr_info("found kexec handover data.\n"); =20 --=20 2.52.0.322.g1dd061c0dc-goog