2019-06-03 05:44:46 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2015-09-09 22:38:51 +00:00
|
|
|
/*
|
|
|
|
* kexec: kexec_file_load system call
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Red Hat Inc.
|
|
|
|
* Authors:
|
|
|
|
* Vivek Goyal <vgoyal@redhat.com>
|
|
|
|
*/
|
|
|
|
|
kexec: use file name as the output message prefix
kexec output message misses the prefix "kexec", when Dave Young split the
kexec code. Now, we use file name as the output message prefix.
Currently, the format of output message:
[ 140.290795] SYSC_kexec_load: hello, world
[ 140.291534] kexec: sanity_check_segment_list: hello, world
Ideally, the format of output message:
[ 30.791503] kexec: SYSC_kexec_load, Hello, world
[ 79.182752] kexec_core: sanity_check_segment_list, Hello, world
Remove the custom prefix "kexec" in output message.
Signed-off-by: Minfei Huang <mnfhuang@gmail.com>
Acked-by: Dave Young <dyoung@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-11-07 00:32:45 +00:00
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
#include <linux/capability.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/file.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/kexec.h>
|
2018-11-15 05:52:43 +00:00
|
|
|
#include <linux/memblock.h>
|
2015-09-09 22:38:51 +00:00
|
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/list.h>
|
2016-01-15 01:59:14 +00:00
|
|
|
#include <linux/fs.h>
|
2016-12-20 00:22:48 +00:00
|
|
|
#include <linux/ima.h>
|
2020-11-13 05:20:21 +00:00
|
|
|
#include <crypto/sha2.h>
|
2018-04-13 22:36:06 +00:00
|
|
|
#include <linux/elf.h>
|
|
|
|
#include <linux/elfcore.h>
|
|
|
|
#include <linux/kernel.h>
|
2020-10-02 17:38:15 +00:00
|
|
|
#include <linux/kernel_read_file.h>
|
2015-09-09 22:38:51 +00:00
|
|
|
#include <linux/syscalls.h>
|
|
|
|
#include <linux/vmalloc.h>
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
#include <linux/dma-map-ops.h>
|
2015-09-09 22:38:51 +00:00
|
|
|
#include "kexec_internal.h"
|
|
|
|
|
2022-07-13 07:21:11 +00:00
|
|
|
#ifdef CONFIG_KEXEC_SIG
|
|
|
|
static bool sig_enforce = IS_ENABLED(CONFIG_KEXEC_SIG_FORCE);
|
|
|
|
|
|
|
|
void set_kexec_sig_enforced(void)
|
|
|
|
{
|
|
|
|
sig_enforce = true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2025-04-21 22:25:10 +00:00
|
|
|
#ifdef CONFIG_IMA_KEXEC
|
|
|
|
static bool check_ima_segment_index(struct kimage *image, int i)
|
|
|
|
{
|
|
|
|
if (image->is_ima_segment_index_set && i == image->ima_segment_index)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static bool check_ima_segment_index(struct kimage *image, int i)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
static int kexec_calculate_store_digests(struct kimage *image);
|
|
|
|
|
2022-05-27 02:55:35 +00:00
|
|
|
/* Maximum size in bytes for kernel/initrd files. */
|
|
|
|
#define KEXEC_FILE_SIZE_MAX min_t(s64, 4LL << 30, SSIZE_MAX)
|
|
|
|
|
2018-04-13 22:35:49 +00:00
|
|
|
/*
|
|
|
|
* Currently this is the only default function that is exported as some
|
|
|
|
* architectures need it to do additional handlings.
|
|
|
|
* In the future, other default functions may be exported too if required.
|
|
|
|
*/
|
|
|
|
int kexec_image_probe_default(struct kimage *image, void *buf,
|
|
|
|
unsigned long buf_len)
|
|
|
|
{
|
|
|
|
const struct kexec_file_ops * const *fops;
|
|
|
|
int ret = -ENOEXEC;
|
|
|
|
|
|
|
|
for (fops = &kexec_file_loaders[0]; *fops && (*fops)->probe; ++fops) {
|
|
|
|
ret = (*fops)->probe(buf, buf_len);
|
|
|
|
if (!ret) {
|
|
|
|
image->fops = *fops;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-03-07 22:44:16 +00:00
|
|
|
static void *kexec_image_load_default(struct kimage *image)
|
2018-04-13 22:35:49 +00:00
|
|
|
{
|
|
|
|
if (!image->fops || !image->fops->load)
|
|
|
|
return ERR_PTR(-ENOEXEC);
|
|
|
|
|
|
|
|
return image->fops->load(image, image->kernel_buf,
|
|
|
|
image->kernel_buf_len, image->initrd_buf,
|
|
|
|
image->initrd_buf_len, image->cmdline_buf,
|
|
|
|
image->cmdline_buf_len);
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
2018-11-15 05:52:41 +00:00
|
|
|
int kexec_image_post_load_cleanup_default(struct kimage *image)
|
2018-04-13 22:35:49 +00:00
|
|
|
{
|
|
|
|
if (!image->fops || !image->fops->cleanup)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return image->fops->cleanup(image->image_loader_data);
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free up memory used by kernel, initrd, and command line. This is temporary
|
|
|
|
* memory allocation which is not needed any more after these buffers have
|
|
|
|
* been loaded into separate segments and have been copied elsewhere.
|
|
|
|
*/
|
|
|
|
void kimage_file_post_load_cleanup(struct kimage *image)
|
|
|
|
{
|
|
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
|
|
|
|
|
|
|
vfree(image->kernel_buf);
|
|
|
|
image->kernel_buf = NULL;
|
|
|
|
|
|
|
|
vfree(image->initrd_buf);
|
|
|
|
image->initrd_buf = NULL;
|
|
|
|
|
|
|
|
kfree(image->cmdline_buf);
|
|
|
|
image->cmdline_buf = NULL;
|
|
|
|
|
|
|
|
vfree(pi->purgatory_buf);
|
|
|
|
pi->purgatory_buf = NULL;
|
|
|
|
|
|
|
|
vfree(pi->sechdrs);
|
|
|
|
pi->sechdrs = NULL;
|
|
|
|
|
2021-02-04 17:49:51 +00:00
|
|
|
#ifdef CONFIG_IMA_KEXEC
|
|
|
|
vfree(image->ima_buffer);
|
|
|
|
image->ima_buffer = NULL;
|
|
|
|
#endif /* CONFIG_IMA_KEXEC */
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
/* See if architecture has anything to cleanup post load */
|
|
|
|
arch_kimage_file_post_load_cleanup(image);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Above call should have called into bootloader to free up
|
|
|
|
* any data stored in kimage->image_loader_data. It should
|
|
|
|
* be ok now to free it up.
|
|
|
|
*/
|
|
|
|
kfree(image->image_loader_data);
|
|
|
|
image->image_loader_data = NULL;
|
kexec_file: add kexec_file flag to control debug printing
Patch series "kexec_file: print out debugging message if required", v4.
Currently, specifying '-d' on kexec command will print a lot of debugging
informationabout kexec/kdump loading with kexec_load interface.
However, kexec_file_load prints nothing even though '-d' is specified.
It's very inconvenient to debug or analyze the kexec/kdump loading when
something wrong happened with kexec/kdump itself or develper want to check
the kexec/kdump loading.
In this patchset, a kexec_file flag is KEXEC_FILE_DEBUG added and checked
in code. If it's passed in, debugging message of kexec_file code will be
printed out and can be seen from console and dmesg. Otherwise, the
debugging message is printed like beofre when pr_debug() is taken.
Note:
****
=====
1) The code in kexec-tools utility also need be changed to support
passing KEXEC_FILE_DEBUG to kernel when 'kexec -s -d' is specified.
The patch link is here:
=========
[PATCH] kexec_file: add kexec_file flag to support debug printing
http://lists.infradead.org/pipermail/kexec/2023-November/028505.html
2) s390 also has kexec_file code, while I am not sure what debugging
information is necessary. So leave it to s390 developer.
Test:
****
====
Testing was done in v1 on x86_64 and arm64. For v4, tested on x86_64
again. And on x86_64, the printed messages look like below:
--------------------------------------------------------------
kexec measurement buffer for the loaded kernel at 0x207fffe000.
Loaded purgatory at 0x207fff9000
Loaded boot_param, command line and misc at 0x207fff3000 bufsz=0x1180 memsz=0x1180
Loaded 64bit kernel at 0x207c000000 bufsz=0xc88200 memsz=0x3c4a000
Loaded initrd at 0x2079e79000 bufsz=0x2186280 memsz=0x2186280
Final command line is: root=/dev/mapper/fedora_intel--knightslanding--lb--02-root ro
rd.lvm.lv=fedora_intel-knightslanding-lb-02/root console=ttyS0,115200N81 crashkernel=256M
E820 memmap:
0000000000000000-000000000009a3ff (1)
000000000009a400-000000000009ffff (2)
00000000000e0000-00000000000fffff (2)
0000000000100000-000000006ff83fff (1)
000000006ff84000-000000007ac50fff (2)
......
000000207fff6150-000000207fff615f (128)
000000207fff6160-000000207fff714f (1)
000000207fff7150-000000207fff715f (128)
000000207fff7160-000000207fff814f (1)
000000207fff8150-000000207fff815f (128)
000000207fff8160-000000207fffffff (1)
nr_segments = 5
segment[0]: buf=0x000000004e5ece74 bufsz=0x211 mem=0x207fffe000 memsz=0x1000
segment[1]: buf=0x000000009e871498 bufsz=0x4000 mem=0x207fff9000 memsz=0x5000
segment[2]: buf=0x00000000d879f1fe bufsz=0x1180 mem=0x207fff3000 memsz=0x2000
segment[3]: buf=0x000000001101cd86 bufsz=0xc88200 mem=0x207c000000 memsz=0x3c4a000
segment[4]: buf=0x00000000c6e38ac7 bufsz=0x2186280 mem=0x2079e79000 memsz=0x2187000
kexec_file_load: type:0, start:0x207fff91a0 head:0x109e004002 flags:0x8
---------------------------------------------------------------------------
This patch (of 7):
When specifying 'kexec -c -d', kexec_load interface will print loading
information, e.g the regions where kernel/initrd/purgatory/cmdline are
put, the memmap passed to 2nd kernel taken as system RAM ranges, and
printing all contents of struct kexec_segment, etc. These are very
helpful for analyzing or positioning what's happening when kexec/kdump
itself failed. The debugging printing for kexec_load interface is made in
user space utility kexec-tools.
Whereas, with kexec_file_load interface, 'kexec -s -d' print nothing.
Because kexec_file code is mostly implemented in kernel space, and the
debugging printing functionality is missed. It's not convenient when
debugging kexec/kdump loading and jumping with kexec_file_load interface.
Now add KEXEC_FILE_DEBUG to kexec_file flag to control the debugging
message printing. And add global variable kexec_file_dbg_print and macro
kexec_dprintk() to facilitate the printing.
This is a preparation, later kexec_dprintk() will be used to replace the
existing pr_debug(). Once 'kexec -s -d' is specified, it will print out
kexec/kdump loading information. If '-d' is not specified, it regresses
to pr_debug().
Link: https://lkml.kernel.org/r/20231213055747.61826-1-bhe@redhat.com
Link: https://lkml.kernel.org/r/20231213055747.61826-2-bhe@redhat.com
Signed-off-by: Baoquan He <bhe@redhat.com>
Cc: Conor Dooley <conor@kernel.org>
Cc: Joe Perches <joe@perches.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-12-13 05:57:41 +00:00
|
|
|
|
|
|
|
kexec_file_dbg_print = false;
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 00:17:44 +00:00
|
|
|
#ifdef CONFIG_KEXEC_SIG
|
2022-07-14 13:40:25 +00:00
|
|
|
#ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
|
|
|
|
int kexec_kernel_verify_pe_sig(const char *kernel, unsigned long kernel_len)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = verify_pefile_signature(kernel, kernel_len,
|
|
|
|
VERIFY_USE_SECONDARY_KEYRING,
|
|
|
|
VERIFYING_KEXEC_PE_SIGNATURE);
|
|
|
|
if (ret == -ENOKEY && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING)) {
|
|
|
|
ret = verify_pefile_signature(kernel, kernel_len,
|
|
|
|
VERIFY_USE_PLATFORM_KEYRING,
|
|
|
|
VERIFYING_KEXEC_PE_SIGNATURE);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-07-14 13:40:24 +00:00
|
|
|
static int kexec_image_verify_sig(struct kimage *image, void *buf,
|
|
|
|
unsigned long buf_len)
|
|
|
|
{
|
|
|
|
if (!image->fops || !image->fops->verify_sig) {
|
|
|
|
pr_debug("kernel loader does not support signature verification.\n");
|
|
|
|
return -EKEYREJECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return image->fops->verify_sig(buf, buf_len);
|
|
|
|
}
|
|
|
|
|
2019-08-20 00:17:44 +00:00
|
|
|
static int
|
|
|
|
kimage_validate_signature(struct kimage *image)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2022-07-14 13:40:24 +00:00
|
|
|
ret = kexec_image_verify_sig(image, image->kernel_buf,
|
|
|
|
image->kernel_buf_len);
|
kexec: do not verify the signature without the lockdown or mandatory signature
Signature verification is an important security feature, to protect
system from being attacked with a kernel of unknown origin. Kexec
rebooting is a way to replace the running kernel, hence need be secured
carefully.
In the current code of handling signature verification of kexec kernel,
the logic is very twisted. It mixes signature verification, IMA
signature appraising and kexec lockdown.
If there is no KEXEC_SIG_FORCE, kexec kernel image doesn't have one of
signature, the supported crypto, and key, we don't think this is wrong,
Unless kexec lockdown is executed. IMA is considered as another kind of
signature appraising method.
If kexec kernel image has signature/crypto/key, it has to go through the
signature verification and pass. Otherwise it's seen as verification
failure, and won't be loaded.
Seems kexec kernel image with an unqualified signature is even worse
than those w/o signature at all, this sounds very unreasonable. E.g.
If people get a unsigned kernel to load, or a kernel signed with expired
key, which one is more dangerous?
So, here, let's simplify the logic to improve code readability. If the
KEXEC_SIG_FORCE enabled or kexec lockdown enabled, signature
verification is mandated. Otherwise, we lift the bar for any kernel
image.
Link: http://lkml.kernel.org/r/20200602045952.27487-1-lijiang@redhat.com
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Reviewed-by: Jiri Bohac <jbohac@suse.cz>
Acked-by: Dave Young <dyoung@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: James Morris <jmorris@namei.org>
Cc: Matthew Garrett <mjg59@google.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-26 03:29:27 +00:00
|
|
|
if (ret) {
|
2019-08-20 00:17:44 +00:00
|
|
|
|
2022-07-13 07:21:11 +00:00
|
|
|
if (sig_enforce) {
|
kexec: do not verify the signature without the lockdown or mandatory signature
Signature verification is an important security feature, to protect
system from being attacked with a kernel of unknown origin. Kexec
rebooting is a way to replace the running kernel, hence need be secured
carefully.
In the current code of handling signature verification of kexec kernel,
the logic is very twisted. It mixes signature verification, IMA
signature appraising and kexec lockdown.
If there is no KEXEC_SIG_FORCE, kexec kernel image doesn't have one of
signature, the supported crypto, and key, we don't think this is wrong,
Unless kexec lockdown is executed. IMA is considered as another kind of
signature appraising method.
If kexec kernel image has signature/crypto/key, it has to go through the
signature verification and pass. Otherwise it's seen as verification
failure, and won't be loaded.
Seems kexec kernel image with an unqualified signature is even worse
than those w/o signature at all, this sounds very unreasonable. E.g.
If people get a unsigned kernel to load, or a kernel signed with expired
key, which one is more dangerous?
So, here, let's simplify the logic to improve code readability. If the
KEXEC_SIG_FORCE enabled or kexec lockdown enabled, signature
verification is mandated. Otherwise, we lift the bar for any kernel
image.
Link: http://lkml.kernel.org/r/20200602045952.27487-1-lijiang@redhat.com
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Reviewed-by: Jiri Bohac <jbohac@suse.cz>
Acked-by: Dave Young <dyoung@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: James Morris <jmorris@namei.org>
Cc: Matthew Garrett <mjg59@google.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-26 03:29:27 +00:00
|
|
|
pr_notice("Enforced kernel signature verification failed (%d).\n", ret);
|
2019-08-20 00:17:44 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
kexec: do not verify the signature without the lockdown or mandatory signature
Signature verification is an important security feature, to protect
system from being attacked with a kernel of unknown origin. Kexec
rebooting is a way to replace the running kernel, hence need be secured
carefully.
In the current code of handling signature verification of kexec kernel,
the logic is very twisted. It mixes signature verification, IMA
signature appraising and kexec lockdown.
If there is no KEXEC_SIG_FORCE, kexec kernel image doesn't have one of
signature, the supported crypto, and key, we don't think this is wrong,
Unless kexec lockdown is executed. IMA is considered as another kind of
signature appraising method.
If kexec kernel image has signature/crypto/key, it has to go through the
signature verification and pass. Otherwise it's seen as verification
failure, and won't be loaded.
Seems kexec kernel image with an unqualified signature is even worse
than those w/o signature at all, this sounds very unreasonable. E.g.
If people get a unsigned kernel to load, or a kernel signed with expired
key, which one is more dangerous?
So, here, let's simplify the logic to improve code readability. If the
KEXEC_SIG_FORCE enabled or kexec lockdown enabled, signature
verification is mandated. Otherwise, we lift the bar for any kernel
image.
Link: http://lkml.kernel.org/r/20200602045952.27487-1-lijiang@redhat.com
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Reviewed-by: Jiri Bohac <jbohac@suse.cz>
Acked-by: Dave Young <dyoung@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: James Morris <jmorris@namei.org>
Cc: Matthew Garrett <mjg59@google.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-26 03:29:27 +00:00
|
|
|
/*
|
|
|
|
* If IMA is guaranteed to appraise a signature on the kexec
|
2019-08-20 00:18:01 +00:00
|
|
|
* image, permit it even if the kernel is otherwise locked
|
|
|
|
* down.
|
|
|
|
*/
|
|
|
|
if (!ima_appraise_signature(READING_KEXEC_IMAGE) &&
|
|
|
|
security_locked_down(LOCKDOWN_KEXEC))
|
|
|
|
return -EPERM;
|
|
|
|
|
kexec: do not verify the signature without the lockdown or mandatory signature
Signature verification is an important security feature, to protect
system from being attacked with a kernel of unknown origin. Kexec
rebooting is a way to replace the running kernel, hence need be secured
carefully.
In the current code of handling signature verification of kexec kernel,
the logic is very twisted. It mixes signature verification, IMA
signature appraising and kexec lockdown.
If there is no KEXEC_SIG_FORCE, kexec kernel image doesn't have one of
signature, the supported crypto, and key, we don't think this is wrong,
Unless kexec lockdown is executed. IMA is considered as another kind of
signature appraising method.
If kexec kernel image has signature/crypto/key, it has to go through the
signature verification and pass. Otherwise it's seen as verification
failure, and won't be loaded.
Seems kexec kernel image with an unqualified signature is even worse
than those w/o signature at all, this sounds very unreasonable. E.g.
If people get a unsigned kernel to load, or a kernel signed with expired
key, which one is more dangerous?
So, here, let's simplify the logic to improve code readability. If the
KEXEC_SIG_FORCE enabled or kexec lockdown enabled, signature
verification is mandated. Otherwise, we lift the bar for any kernel
image.
Link: http://lkml.kernel.org/r/20200602045952.27487-1-lijiang@redhat.com
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Reviewed-by: Jiri Bohac <jbohac@suse.cz>
Acked-by: Dave Young <dyoung@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: James Morris <jmorris@namei.org>
Cc: Matthew Garrett <mjg59@google.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-26 03:29:27 +00:00
|
|
|
pr_debug("kernel signature verification failed (%d).\n", ret);
|
2019-08-20 00:17:44 +00:00
|
|
|
}
|
|
|
|
|
kexec: do not verify the signature without the lockdown or mandatory signature
Signature verification is an important security feature, to protect
system from being attacked with a kernel of unknown origin. Kexec
rebooting is a way to replace the running kernel, hence need be secured
carefully.
In the current code of handling signature verification of kexec kernel,
the logic is very twisted. It mixes signature verification, IMA
signature appraising and kexec lockdown.
If there is no KEXEC_SIG_FORCE, kexec kernel image doesn't have one of
signature, the supported crypto, and key, we don't think this is wrong,
Unless kexec lockdown is executed. IMA is considered as another kind of
signature appraising method.
If kexec kernel image has signature/crypto/key, it has to go through the
signature verification and pass. Otherwise it's seen as verification
failure, and won't be loaded.
Seems kexec kernel image with an unqualified signature is even worse
than those w/o signature at all, this sounds very unreasonable. E.g.
If people get a unsigned kernel to load, or a kernel signed with expired
key, which one is more dangerous?
So, here, let's simplify the logic to improve code readability. If the
KEXEC_SIG_FORCE enabled or kexec lockdown enabled, signature
verification is mandated. Otherwise, we lift the bar for any kernel
image.
Link: http://lkml.kernel.org/r/20200602045952.27487-1-lijiang@redhat.com
Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Reviewed-by: Jiri Bohac <jbohac@suse.cz>
Acked-by: Dave Young <dyoung@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: James Morris <jmorris@namei.org>
Cc: Matthew Garrett <mjg59@google.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-26 03:29:27 +00:00
|
|
|
return 0;
|
2019-08-20 00:17:44 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2025-04-21 22:25:12 +00:00
|
|
|
static int kexec_post_load(struct kimage *image, unsigned long flags)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_IMA_KEXEC
|
|
|
|
if (!(flags & KEXEC_FILE_ON_CRASH))
|
|
|
|
ima_kexec_post_load(image);
|
|
|
|
#endif
|
|
|
|
return machine_kexec_post_load(image);
|
|
|
|
}
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
/*
|
|
|
|
* In file mode list of segments is prepared by kernel. Copy relevant
|
|
|
|
* data from user space, do error checking, prepare segment list
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
|
|
|
const char __user *cmdline_ptr,
|
|
|
|
unsigned long cmdline_len, unsigned flags)
|
|
|
|
{
|
2022-05-27 02:55:35 +00:00
|
|
|
ssize_t ret;
|
2015-09-09 22:38:51 +00:00
|
|
|
void *ldata;
|
|
|
|
|
2020-10-02 17:38:25 +00:00
|
|
|
ret = kernel_read_file_from_fd(kernel_fd, 0, &image->kernel_buf,
|
2022-05-27 02:55:35 +00:00
|
|
|
KEXEC_FILE_SIZE_MAX, NULL,
|
|
|
|
READING_KEXEC_IMAGE);
|
2020-10-02 17:38:17 +00:00
|
|
|
if (ret < 0)
|
2015-09-09 22:38:51 +00:00
|
|
|
return ret;
|
2020-10-02 17:38:17 +00:00
|
|
|
image->kernel_buf_len = ret;
|
2023-12-13 05:57:42 +00:00
|
|
|
kexec_dprintk("kernel: %p kernel_size: %#lx\n",
|
|
|
|
image->kernel_buf, image->kernel_buf_len);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
/* Call arch image probe handlers */
|
|
|
|
ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
|
|
|
|
image->kernel_buf_len);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2019-08-20 00:17:44 +00:00
|
|
|
#ifdef CONFIG_KEXEC_SIG
|
|
|
|
ret = kimage_validate_signature(image);
|
|
|
|
|
|
|
|
if (ret)
|
2015-09-09 22:38:51 +00:00
|
|
|
goto out;
|
|
|
|
#endif
|
|
|
|
/* It is possible that there no initramfs is being loaded */
|
|
|
|
if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
|
2020-10-02 17:38:25 +00:00
|
|
|
ret = kernel_read_file_from_fd(initrd_fd, 0, &image->initrd_buf,
|
2022-05-27 02:55:35 +00:00
|
|
|
KEXEC_FILE_SIZE_MAX, NULL,
|
2016-01-15 01:59:14 +00:00
|
|
|
READING_KEXEC_INITRAMFS);
|
2020-10-02 17:38:17 +00:00
|
|
|
if (ret < 0)
|
2015-09-09 22:38:51 +00:00
|
|
|
goto out;
|
2020-10-02 17:38:17 +00:00
|
|
|
image->initrd_buf_len = ret;
|
|
|
|
ret = 0;
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
if (cmdline_len) {
|
2017-05-13 22:39:01 +00:00
|
|
|
image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);
|
|
|
|
if (IS_ERR(image->cmdline_buf)) {
|
|
|
|
ret = PTR_ERR(image->cmdline_buf);
|
|
|
|
image->cmdline_buf = NULL;
|
2015-09-09 22:38:51 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
image->cmdline_buf_len = cmdline_len;
|
|
|
|
|
|
|
|
/* command line should be a string with last byte null */
|
|
|
|
if (image->cmdline_buf[cmdline_len - 1] != '\0') {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-06-24 06:23:31 +00:00
|
|
|
|
2020-07-09 06:19:11 +00:00
|
|
|
ima_kexec_cmdline(kernel_fd, image->cmdline_buf,
|
2019-06-24 06:23:31 +00:00
|
|
|
image->cmdline_buf_len - 1);
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
2019-06-24 06:23:31 +00:00
|
|
|
/* IMA needs to pass the measurement list to the next kernel. */
|
|
|
|
ima_add_kexec_buffer(image);
|
|
|
|
|
2025-05-09 07:46:25 +00:00
|
|
|
/* If KHO is active, add its images to the list */
|
|
|
|
ret = kho_fill_kimage(image);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2023-03-07 22:44:16 +00:00
|
|
|
/* Call image load handler */
|
|
|
|
ldata = kexec_image_load_default(image);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
if (IS_ERR(ldata)) {
|
|
|
|
ret = PTR_ERR(ldata);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
image->image_loader_data = ldata;
|
|
|
|
out:
|
|
|
|
/* In case of error, free up all allocated memory in this function */
|
|
|
|
if (ret)
|
|
|
|
kimage_file_post_load_cleanup(image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
kimage_file_alloc_init(struct kimage **rimage, int kernel_fd,
|
|
|
|
int initrd_fd, const char __user *cmdline_ptr,
|
|
|
|
unsigned long cmdline_len, unsigned long flags)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct kimage *image;
|
|
|
|
bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH;
|
|
|
|
|
|
|
|
image = do_kimage_alloc_init();
|
|
|
|
if (!image)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
kexec_file: add kexec_file flag to control debug printing
Patch series "kexec_file: print out debugging message if required", v4.
Currently, specifying '-d' on kexec command will print a lot of debugging
informationabout kexec/kdump loading with kexec_load interface.
However, kexec_file_load prints nothing even though '-d' is specified.
It's very inconvenient to debug or analyze the kexec/kdump loading when
something wrong happened with kexec/kdump itself or develper want to check
the kexec/kdump loading.
In this patchset, a kexec_file flag is KEXEC_FILE_DEBUG added and checked
in code. If it's passed in, debugging message of kexec_file code will be
printed out and can be seen from console and dmesg. Otherwise, the
debugging message is printed like beofre when pr_debug() is taken.
Note:
****
=====
1) The code in kexec-tools utility also need be changed to support
passing KEXEC_FILE_DEBUG to kernel when 'kexec -s -d' is specified.
The patch link is here:
=========
[PATCH] kexec_file: add kexec_file flag to support debug printing
http://lists.infradead.org/pipermail/kexec/2023-November/028505.html
2) s390 also has kexec_file code, while I am not sure what debugging
information is necessary. So leave it to s390 developer.
Test:
****
====
Testing was done in v1 on x86_64 and arm64. For v4, tested on x86_64
again. And on x86_64, the printed messages look like below:
--------------------------------------------------------------
kexec measurement buffer for the loaded kernel at 0x207fffe000.
Loaded purgatory at 0x207fff9000
Loaded boot_param, command line and misc at 0x207fff3000 bufsz=0x1180 memsz=0x1180
Loaded 64bit kernel at 0x207c000000 bufsz=0xc88200 memsz=0x3c4a000
Loaded initrd at 0x2079e79000 bufsz=0x2186280 memsz=0x2186280
Final command line is: root=/dev/mapper/fedora_intel--knightslanding--lb--02-root ro
rd.lvm.lv=fedora_intel-knightslanding-lb-02/root console=ttyS0,115200N81 crashkernel=256M
E820 memmap:
0000000000000000-000000000009a3ff (1)
000000000009a400-000000000009ffff (2)
00000000000e0000-00000000000fffff (2)
0000000000100000-000000006ff83fff (1)
000000006ff84000-000000007ac50fff (2)
......
000000207fff6150-000000207fff615f (128)
000000207fff6160-000000207fff714f (1)
000000207fff7150-000000207fff715f (128)
000000207fff7160-000000207fff814f (1)
000000207fff8150-000000207fff815f (128)
000000207fff8160-000000207fffffff (1)
nr_segments = 5
segment[0]: buf=0x000000004e5ece74 bufsz=0x211 mem=0x207fffe000 memsz=0x1000
segment[1]: buf=0x000000009e871498 bufsz=0x4000 mem=0x207fff9000 memsz=0x5000
segment[2]: buf=0x00000000d879f1fe bufsz=0x1180 mem=0x207fff3000 memsz=0x2000
segment[3]: buf=0x000000001101cd86 bufsz=0xc88200 mem=0x207c000000 memsz=0x3c4a000
segment[4]: buf=0x00000000c6e38ac7 bufsz=0x2186280 mem=0x2079e79000 memsz=0x2187000
kexec_file_load: type:0, start:0x207fff91a0 head:0x109e004002 flags:0x8
---------------------------------------------------------------------------
This patch (of 7):
When specifying 'kexec -c -d', kexec_load interface will print loading
information, e.g the regions where kernel/initrd/purgatory/cmdline are
put, the memmap passed to 2nd kernel taken as system RAM ranges, and
printing all contents of struct kexec_segment, etc. These are very
helpful for analyzing or positioning what's happening when kexec/kdump
itself failed. The debugging printing for kexec_load interface is made in
user space utility kexec-tools.
Whereas, with kexec_file_load interface, 'kexec -s -d' print nothing.
Because kexec_file code is mostly implemented in kernel space, and the
debugging printing functionality is missed. It's not convenient when
debugging kexec/kdump loading and jumping with kexec_file_load interface.
Now add KEXEC_FILE_DEBUG to kexec_file flag to control the debugging
message printing. And add global variable kexec_file_dbg_print and macro
kexec_dprintk() to facilitate the printing.
This is a preparation, later kexec_dprintk() will be used to replace the
existing pr_debug(). Once 'kexec -s -d' is specified, it will print out
kexec/kdump loading information. If '-d' is not specified, it regresses
to pr_debug().
Link: https://lkml.kernel.org/r/20231213055747.61826-1-bhe@redhat.com
Link: https://lkml.kernel.org/r/20231213055747.61826-2-bhe@redhat.com
Signed-off-by: Baoquan He <bhe@redhat.com>
Cc: Conor Dooley <conor@kernel.org>
Cc: Joe Perches <joe@perches.com>
Cc: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-12-13 05:57:41 +00:00
|
|
|
kexec_file_dbg_print = !!(flags & KEXEC_FILE_DEBUG);
|
2015-09-09 22:38:51 +00:00
|
|
|
image->file_mode = 1;
|
|
|
|
|
2024-01-24 05:12:44 +00:00
|
|
|
#ifdef CONFIG_CRASH_DUMP
|
2015-09-09 22:38:51 +00:00
|
|
|
if (kexec_on_panic) {
|
|
|
|
/* Enable special crash kernel control page alloc policy. */
|
|
|
|
image->control_page = crashk_res.start;
|
|
|
|
image->type = KEXEC_TYPE_CRASH;
|
|
|
|
}
|
2024-01-24 05:12:44 +00:00
|
|
|
#endif
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd,
|
|
|
|
cmdline_ptr, cmdline_len, flags);
|
|
|
|
if (ret)
|
|
|
|
goto out_free_image;
|
|
|
|
|
|
|
|
ret = sanity_check_segment_list(image);
|
|
|
|
if (ret)
|
|
|
|
goto out_free_post_load_bufs;
|
|
|
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
image->control_code_page = kimage_alloc_control_pages(image,
|
|
|
|
get_order(KEXEC_CONTROL_PAGE_SIZE));
|
|
|
|
if (!image->control_code_page) {
|
|
|
|
pr_err("Could not allocate control_code_buffer\n");
|
|
|
|
goto out_free_post_load_bufs;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!kexec_on_panic) {
|
|
|
|
image->swap_page = kimage_alloc_control_pages(image, 0);
|
|
|
|
if (!image->swap_page) {
|
|
|
|
pr_err("Could not allocate swap buffer\n");
|
|
|
|
goto out_free_control_pages;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*rimage = image;
|
|
|
|
return 0;
|
|
|
|
out_free_control_pages:
|
|
|
|
kimage_free_page_list(&image->control_pages);
|
|
|
|
out_free_post_load_bufs:
|
|
|
|
kimage_file_post_load_cleanup(image);
|
|
|
|
out_free_image:
|
|
|
|
kfree(image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
|
|
|
|
unsigned long, cmdline_len, const char __user *, cmdline_ptr,
|
|
|
|
unsigned long, flags)
|
|
|
|
{
|
2023-01-04 14:38:48 +00:00
|
|
|
int image_type = (flags & KEXEC_FILE_ON_CRASH) ?
|
|
|
|
KEXEC_TYPE_CRASH : KEXEC_TYPE_DEFAULT;
|
2015-09-09 22:38:51 +00:00
|
|
|
struct kimage **dest_image, *image;
|
2023-01-04 14:38:48 +00:00
|
|
|
int ret = 0, i;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
/* We only trust the superuser with rebooting the system. */
|
2023-01-04 14:38:48 +00:00
|
|
|
if (!kexec_load_permitted(image_type))
|
2015-09-09 22:38:51 +00:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
/* Make sure we have a legal set of flags */
|
|
|
|
if (flags != (flags & KEXEC_FILE_FLAGS))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
image = NULL;
|
|
|
|
|
2022-06-30 22:32:58 +00:00
|
|
|
if (!kexec_trylock())
|
2015-09-09 22:38:51 +00:00
|
|
|
return -EBUSY;
|
|
|
|
|
2024-01-24 05:12:44 +00:00
|
|
|
#ifdef CONFIG_CRASH_DUMP
|
2023-01-04 14:38:48 +00:00
|
|
|
if (image_type == KEXEC_TYPE_CRASH) {
|
2015-09-09 22:38:51 +00:00
|
|
|
dest_image = &kexec_crash_image;
|
2016-05-23 23:24:10 +00:00
|
|
|
if (kexec_crash_image)
|
|
|
|
arch_kexec_unprotect_crashkres();
|
2024-01-24 05:12:44 +00:00
|
|
|
} else
|
|
|
|
#endif
|
2023-01-04 14:38:48 +00:00
|
|
|
dest_image = &kexec_image;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
if (flags & KEXEC_FILE_UNLOAD)
|
|
|
|
goto exchange;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In case of crash, new kernel gets loaded in reserved region. It is
|
|
|
|
* same memory where old crash kernel might be loaded. Free any
|
|
|
|
* current crash dump kernel before we corrupt it.
|
|
|
|
*/
|
|
|
|
if (flags & KEXEC_FILE_ON_CRASH)
|
|
|
|
kimage_free(xchg(&kexec_crash_image, NULL));
|
|
|
|
|
|
|
|
ret = kimage_file_alloc_init(&image, kernel_fd, initrd_fd, cmdline_ptr,
|
|
|
|
cmdline_len, flags);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2024-03-26 05:54:09 +00:00
|
|
|
#ifdef CONFIG_CRASH_HOTPLUG
|
|
|
|
if ((flags & KEXEC_FILE_ON_CRASH) && arch_crash_hotplug_support(image, flags))
|
|
|
|
image->hotplug_support = 1;
|
|
|
|
#endif
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
ret = machine_kexec_prepare(image);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
kdump: protect vmcoreinfo data under the crash memory
Currently vmcoreinfo data is updated at boot time subsys_initcall(), it
has the risk of being modified by some wrong code during system is
running.
As a result, vmcore dumped may contain the wrong vmcoreinfo. Later on,
when using "crash", "makedumpfile", etc utility to parse this vmcore, we
probably will get "Segmentation fault" or other unexpected errors.
E.g. 1) wrong code overwrites vmcoreinfo_data; 2) further crashes the
system; 3) trigger kdump, then we obviously will fail to recognize the
crash context correctly due to the corrupted vmcoreinfo.
Now except for vmcoreinfo, all the crash data is well
protected(including the cpu note which is fully updated in the crash
path, thus its correctness is guaranteed). Given that vmcoreinfo data
is a large chunk prepared for kdump, we better protect it as well.
To solve this, we relocate and copy vmcoreinfo_data to the crash memory
when kdump is loading via kexec syscalls. Because the whole crash
memory will be protected by existing arch_kexec_protect_crashkres()
mechanism, we naturally protect vmcoreinfo_data from write(even read)
access under kernel direct mapping after kdump is loaded.
Since kdump is usually loaded at the very early stage after boot, we can
trust the correctness of the vmcoreinfo data copied.
On the other hand, we still need to operate the vmcoreinfo safe copy
when crash happens to generate vmcoreinfo_note again, we rely on vmap()
to map out a new kernel virtual address and update to use this new one
instead in the following crash_save_vmcoreinfo().
BTW, we do not touch vmcoreinfo_note, because it will be fully updated
using the protected vmcoreinfo_data after crash which is surely correct
just like the cpu crash note.
Link: http://lkml.kernel.org/r/1493281021-20737-3-git-send-email-xlpang@redhat.com
Signed-off-by: Xunlei Pang <xlpang@redhat.com>
Tested-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Dave Young <dyoung@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Hari Bathini <hbathini@linux.vnet.ibm.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-07-12 21:33:21 +00:00
|
|
|
/*
|
|
|
|
* Some architecture(like S390) may touch the crash memory before
|
|
|
|
* machine_kexec_prepare(), we must copy vmcoreinfo data after it.
|
|
|
|
*/
|
|
|
|
ret = kimage_crash_copy_vmcoreinfo(image);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
ret = kexec_calculate_store_digests(image);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2023-12-13 05:57:42 +00:00
|
|
|
kexec_dprintk("nr_segments = %lu\n", image->nr_segments);
|
2015-09-09 22:38:51 +00:00
|
|
|
for (i = 0; i < image->nr_segments; i++) {
|
|
|
|
struct kexec_segment *ksegment;
|
|
|
|
|
|
|
|
ksegment = &image->segment[i];
|
2023-12-13 05:57:42 +00:00
|
|
|
kexec_dprintk("segment[%d]: buf=0x%p bufsz=0x%zx mem=0x%lx memsz=0x%zx\n",
|
|
|
|
i, ksegment->buf, ksegment->bufsz, ksegment->mem,
|
|
|
|
ksegment->memsz);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
ret = kimage_load_segment(image, i);
|
2015-09-09 22:38:51 +00:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
kimage_terminate(image);
|
|
|
|
|
2025-04-21 22:25:12 +00:00
|
|
|
ret = kexec_post_load(image, flags);
|
2019-12-04 15:59:15 +00:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2023-12-13 05:57:42 +00:00
|
|
|
kexec_dprintk("kexec_file_load: type:%u, start:0x%lx head:0x%lx flags:0x%lx\n",
|
|
|
|
image->type, image->start, image->head, flags);
|
2015-09-09 22:38:51 +00:00
|
|
|
/*
|
|
|
|
* Free up any temporary buffers allocated which are not needed
|
|
|
|
* after image has been loaded
|
|
|
|
*/
|
|
|
|
kimage_file_post_load_cleanup(image);
|
|
|
|
exchange:
|
|
|
|
image = xchg(dest_image, image);
|
|
|
|
out:
|
2024-01-24 05:12:44 +00:00
|
|
|
#ifdef CONFIG_CRASH_DUMP
|
2016-05-23 23:24:10 +00:00
|
|
|
if ((flags & KEXEC_FILE_ON_CRASH) && kexec_crash_image)
|
|
|
|
arch_kexec_protect_crashkres();
|
2024-01-24 05:12:44 +00:00
|
|
|
#endif
|
2016-05-23 23:24:10 +00:00
|
|
|
|
2022-06-30 22:32:58 +00:00
|
|
|
kexec_unlock();
|
2015-09-09 22:38:51 +00:00
|
|
|
kimage_free(image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
|
|
|
|
struct kexec_buf *kbuf)
|
|
|
|
{
|
|
|
|
struct kimage *image = kbuf->image;
|
|
|
|
unsigned long temp_start, temp_end;
|
|
|
|
|
|
|
|
temp_end = min(end, kbuf->buf_max);
|
2023-12-17 03:35:27 +00:00
|
|
|
temp_start = temp_end - kbuf->memsz + 1;
|
kexec_file: allow to place kexec_buf randomly
Patch series "Support kdump with LUKS encryption by reusing LUKS volume
keys", v9.
LUKS is the standard for Linux disk encryption, widely adopted by users,
and in some cases, such as Confidential VMs, it is a requirement. With
kdump enabled, when the first kernel crashes, the system can boot into the
kdump/crash kernel to dump the memory image (i.e., /proc/vmcore) to a
specified target. However, there are two challenges when dumping vmcore
to a LUKS-encrypted device:
- Kdump kernel may not be able to decrypt the LUKS partition. For some
machines, a system administrator may not have a chance to enter the
password to decrypt the device in kdump initramfs after the 1st kernel
crashes; For cloud confidential VMs, depending on the policy the
kdump kernel may not be able to unseal the keys with TPM and the
console virtual keyboard is untrusted.
- LUKS2 by default use the memory-hard Argon2 key derivation function
which is quite memory-consuming compared to the limited memory reserved
for kdump. Take Fedora example, by default, only 256M is reserved for
systems having memory between 4G-64G. With LUKS enabled, ~1300M needs
to be reserved for kdump. Note if the memory reserved for kdump can't
be used by 1st kernel i.e. an user sees ~1300M memory missing in the
1st kernel.
Besides users (at least for Fedora) usually expect kdump to work out of
the box i.e. no manual password input or custom crashkernel value is
needed. And it doesn't make sense to derivate the keys again in kdump
kernel which seems to be redundant work.
This patchset addresses the above issues by making the LUKS volume keys
persistent for kdump kernel with the help of cryptsetup's new APIs
(--link-vk-to-keyring/--volume-key-keyring). Here is the life cycle of
the kdump copies of LUKS volume keys,
1. After the 1st kernel loads the initramfs during boot, systemd
use an user-input passphrase to de-crypt the LUKS volume keys
or TPM-sealed key and then save the volume keys to specified keyring
(using the --link-vk-to-keyring API) and the key will expire within
specified time.
2. A user space tool (kdump initramfs loader like kdump-utils) create
key items inside /sys/kernel/config/crash_dm_crypt_keys to inform
the 1st kernel which keys are needed.
3. When the kdump initramfs is loaded by the kexec_file_load
syscall, the 1st kernel will iterate created key items, save the
keys to kdump reserved memory.
4. When the 1st kernel crashes and the kdump initramfs is booted, the
kdump initramfs asks the kdump kernel to create a user key using the
key stored in kdump reserved memory by writing yes to
/sys/kernel/crash_dm_crypt_keys/restore. Then the LUKS encrypted
device is unlocked with libcryptsetup's --volume-key-keyring API.
5. The system gets rebooted to the 1st kernel after dumping vmcore to
the LUKS encrypted device is finished
After libcryptsetup saving the LUKS volume keys to specified keyring,
whoever takes this should be responsible for the safety of these copies of
keys. The keys will be saved in the memory area exclusively reserved for
kdump where even the 1st kernel has no direct access. And further more,
two additional protections are added,
- save the copy randomly in kdump reserved memory as suggested by Jan
- clear the _PAGE_PRESENT flag of the page that stores the copy as
suggested by Pingfan
This patchset only supports x86. There will be patches to support other
architectures once this patch set gets merged.
This patch (of 9):
Currently, kexec_buf is placed in order which means for the same machine,
the info in the kexec_buf is always located at the same position each time
the machine is booted. This may cause a risk for sensitive information
like LUKS volume key. Now struct kexec_buf has a new field random which
indicates it's supposed to be placed in a random position.
Note this feature is enabled only when CONFIG_CRASH_DUMP is enabled. So
it only takes effect for kdump and won't impact kexec reboot.
Link: https://lkml.kernel.org/r/20250502011246.99238-1-coxu@redhat.com
Link: https://lkml.kernel.org/r/20250502011246.99238-2-coxu@redhat.com
Signed-off-by: Coiby Xu <coxu@redhat.com>
Suggested-by: Jan Pazdziora <jpazdziora@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: "Daniel P. Berrange" <berrange@redhat.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Liu Pingfan <kernelfans@gmail.com>
Cc: Milan Broz <gmazyland@gmail.com>
Cc: Ondrej Kozina <okozina@redhat.com>
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-05-02 01:12:35 +00:00
|
|
|
kexec_random_range_start(temp_start, temp_end, kbuf, &temp_start);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
/* align down start */
|
2023-12-17 03:35:27 +00:00
|
|
|
temp_start = ALIGN_DOWN(temp_start, kbuf->buf_align);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
if (temp_start < start || temp_start < kbuf->buf_min)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
temp_end = temp_start + kbuf->memsz - 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure this does not conflict with any of existing
|
|
|
|
* segments
|
|
|
|
*/
|
|
|
|
if (kimage_is_destination_range(image, temp_start, temp_end)) {
|
|
|
|
temp_start = temp_start - PAGE_SIZE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2025-01-31 11:38:26 +00:00
|
|
|
/* Make sure this does not conflict with exclude range */
|
|
|
|
if (arch_check_excluded_range(image, temp_start, temp_end)) {
|
|
|
|
temp_start = temp_start - PAGE_SIZE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
/* We found a suitable memory range */
|
|
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
/* If we are here, we found a suitable memory range */
|
|
|
|
kbuf->mem = temp_start;
|
|
|
|
|
|
|
|
/* Success, stop navigating through remaining System RAM ranges */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
|
|
|
|
struct kexec_buf *kbuf)
|
|
|
|
{
|
|
|
|
struct kimage *image = kbuf->image;
|
|
|
|
unsigned long temp_start, temp_end;
|
|
|
|
|
|
|
|
temp_start = max(start, kbuf->buf_min);
|
|
|
|
|
kexec_file: allow to place kexec_buf randomly
Patch series "Support kdump with LUKS encryption by reusing LUKS volume
keys", v9.
LUKS is the standard for Linux disk encryption, widely adopted by users,
and in some cases, such as Confidential VMs, it is a requirement. With
kdump enabled, when the first kernel crashes, the system can boot into the
kdump/crash kernel to dump the memory image (i.e., /proc/vmcore) to a
specified target. However, there are two challenges when dumping vmcore
to a LUKS-encrypted device:
- Kdump kernel may not be able to decrypt the LUKS partition. For some
machines, a system administrator may not have a chance to enter the
password to decrypt the device in kdump initramfs after the 1st kernel
crashes; For cloud confidential VMs, depending on the policy the
kdump kernel may not be able to unseal the keys with TPM and the
console virtual keyboard is untrusted.
- LUKS2 by default use the memory-hard Argon2 key derivation function
which is quite memory-consuming compared to the limited memory reserved
for kdump. Take Fedora example, by default, only 256M is reserved for
systems having memory between 4G-64G. With LUKS enabled, ~1300M needs
to be reserved for kdump. Note if the memory reserved for kdump can't
be used by 1st kernel i.e. an user sees ~1300M memory missing in the
1st kernel.
Besides users (at least for Fedora) usually expect kdump to work out of
the box i.e. no manual password input or custom crashkernel value is
needed. And it doesn't make sense to derivate the keys again in kdump
kernel which seems to be redundant work.
This patchset addresses the above issues by making the LUKS volume keys
persistent for kdump kernel with the help of cryptsetup's new APIs
(--link-vk-to-keyring/--volume-key-keyring). Here is the life cycle of
the kdump copies of LUKS volume keys,
1. After the 1st kernel loads the initramfs during boot, systemd
use an user-input passphrase to de-crypt the LUKS volume keys
or TPM-sealed key and then save the volume keys to specified keyring
(using the --link-vk-to-keyring API) and the key will expire within
specified time.
2. A user space tool (kdump initramfs loader like kdump-utils) create
key items inside /sys/kernel/config/crash_dm_crypt_keys to inform
the 1st kernel which keys are needed.
3. When the kdump initramfs is loaded by the kexec_file_load
syscall, the 1st kernel will iterate created key items, save the
keys to kdump reserved memory.
4. When the 1st kernel crashes and the kdump initramfs is booted, the
kdump initramfs asks the kdump kernel to create a user key using the
key stored in kdump reserved memory by writing yes to
/sys/kernel/crash_dm_crypt_keys/restore. Then the LUKS encrypted
device is unlocked with libcryptsetup's --volume-key-keyring API.
5. The system gets rebooted to the 1st kernel after dumping vmcore to
the LUKS encrypted device is finished
After libcryptsetup saving the LUKS volume keys to specified keyring,
whoever takes this should be responsible for the safety of these copies of
keys. The keys will be saved in the memory area exclusively reserved for
kdump where even the 1st kernel has no direct access. And further more,
two additional protections are added,
- save the copy randomly in kdump reserved memory as suggested by Jan
- clear the _PAGE_PRESENT flag of the page that stores the copy as
suggested by Pingfan
This patchset only supports x86. There will be patches to support other
architectures once this patch set gets merged.
This patch (of 9):
Currently, kexec_buf is placed in order which means for the same machine,
the info in the kexec_buf is always located at the same position each time
the machine is booted. This may cause a risk for sensitive information
like LUKS volume key. Now struct kexec_buf has a new field random which
indicates it's supposed to be placed in a random position.
Note this feature is enabled only when CONFIG_CRASH_DUMP is enabled. So
it only takes effect for kdump and won't impact kexec reboot.
Link: https://lkml.kernel.org/r/20250502011246.99238-1-coxu@redhat.com
Link: https://lkml.kernel.org/r/20250502011246.99238-2-coxu@redhat.com
Signed-off-by: Coiby Xu <coxu@redhat.com>
Suggested-by: Jan Pazdziora <jpazdziora@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: "Daniel P. Berrange" <berrange@redhat.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: Liu Pingfan <kernelfans@gmail.com>
Cc: Milan Broz <gmazyland@gmail.com>
Cc: Ondrej Kozina <okozina@redhat.com>
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-05-02 01:12:35 +00:00
|
|
|
kexec_random_range_start(temp_start, end, kbuf, &temp_start);
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
do {
|
|
|
|
temp_start = ALIGN(temp_start, kbuf->buf_align);
|
|
|
|
temp_end = temp_start + kbuf->memsz - 1;
|
|
|
|
|
|
|
|
if (temp_end > end || temp_end > kbuf->buf_max)
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* Make sure this does not conflict with any of existing
|
|
|
|
* segments
|
|
|
|
*/
|
|
|
|
if (kimage_is_destination_range(image, temp_start, temp_end)) {
|
|
|
|
temp_start = temp_start + PAGE_SIZE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2025-01-31 11:38:26 +00:00
|
|
|
/* Make sure this does not conflict with exclude range */
|
|
|
|
if (arch_check_excluded_range(image, temp_start, temp_end)) {
|
|
|
|
temp_start = temp_start + PAGE_SIZE;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
/* We found a suitable memory range */
|
|
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
|
|
|
|
/* If we are here, we found a suitable memory range */
|
|
|
|
kbuf->mem = temp_start;
|
|
|
|
|
|
|
|
/* Success, stop navigating through remaining System RAM ranges */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-10-20 14:30:51 +00:00
|
|
|
static int locate_mem_hole_callback(struct resource *res, void *arg)
|
2015-09-09 22:38:51 +00:00
|
|
|
{
|
|
|
|
struct kexec_buf *kbuf = (struct kexec_buf *)arg;
|
2017-10-20 14:30:51 +00:00
|
|
|
u64 start = res->start, end = res->end;
|
2015-09-09 22:38:51 +00:00
|
|
|
unsigned long sz = end - start + 1;
|
|
|
|
|
|
|
|
/* Returning 0 will take to next memory range */
|
2020-06-04 23:48:44 +00:00
|
|
|
|
|
|
|
/* Don't use memory that will be detected and handled by a driver. */
|
2020-10-16 03:08:33 +00:00
|
|
|
if (res->flags & IORESOURCE_SYSRAM_DRIVER_MANAGED)
|
2020-06-04 23:48:44 +00:00
|
|
|
return 0;
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
if (sz < kbuf->memsz)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (end < kbuf->buf_min || start > kbuf->buf_max)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate memory top down with-in ram range. Otherwise bottom up
|
|
|
|
* allocation.
|
|
|
|
*/
|
|
|
|
if (kbuf->top_down)
|
|
|
|
return locate_mem_hole_top_down(start, end, kbuf);
|
|
|
|
return locate_mem_hole_bottom_up(start, end, kbuf);
|
|
|
|
}
|
|
|
|
|
2019-05-14 00:22:59 +00:00
|
|
|
#ifdef CONFIG_ARCH_KEEP_MEMBLOCK
|
2018-11-15 05:52:43 +00:00
|
|
|
static int kexec_walk_memblock(struct kexec_buf *kbuf,
|
|
|
|
int (*func)(struct resource *, void *))
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
u64 i;
|
|
|
|
phys_addr_t mstart, mend;
|
|
|
|
struct resource res = { };
|
|
|
|
|
2024-01-24 05:12:47 +00:00
|
|
|
#ifdef CONFIG_CRASH_DUMP
|
2018-11-15 05:52:44 +00:00
|
|
|
if (kbuf->image->type == KEXEC_TYPE_CRASH)
|
|
|
|
return func(&crashk_res, kbuf);
|
2024-01-24 05:12:47 +00:00
|
|
|
#endif
|
2018-11-15 05:52:44 +00:00
|
|
|
|
memblock: add MEMBLOCK_DRIVER_MANAGED to mimic IORESOURCE_SYSRAM_DRIVER_MANAGED
Let's add a flag that corresponds to IORESOURCE_SYSRAM_DRIVER_MANAGED,
indicating that we're dealing with a memory region that is never
indicated in the firmware-provided memory map, but always detected and
added by a driver.
Similar to MEMBLOCK_HOTPLUG, most infrastructure has to treat such
memory regions like ordinary MEMBLOCK_NONE memory regions -- for
example, when selecting memory regions to add to the vmcore for dumping
in the crashkernel via for_each_mem_range().
However, especially kexec_file is not supposed to select such memblocks
via for_each_free_mem_range() / for_each_free_mem_range_reverse() to
place kexec images, similar to how we handle
IORESOURCE_SYSRAM_DRIVER_MANAGED without CONFIG_ARCH_KEEP_MEMBLOCK.
We'll make sure that memory hotplug code sets the flag where applicable
(IORESOURCE_SYSRAM_DRIVER_MANAGED) next. This prepares architectures
that need CONFIG_ARCH_KEEP_MEMBLOCK, such as arm64, for virtio-mem
support.
Note that kexec *must not* indicate this memory to the second kernel and
*must not* place kexec-images on this memory. Let's add a comment to
kexec_walk_memblock(), documenting how we handle MEMBLOCK_DRIVER_MANAGED
now just like using IORESOURCE_SYSRAM_DRIVER_MANAGED in
locate_mem_hole_callback() for kexec_walk_resources().
Also note that MEMBLOCK_HOTPLUG cannot be reused due to different
semantics:
MEMBLOCK_HOTPLUG: memory is indicated as "System RAM" in the
firmware-provided memory map and added to the system early during
boot; kexec *has to* indicate this memory to the second kernel and
can place kexec-images on this memory. After memory hotunplug,
kexec has to be re-armed. We mostly ignore this flag when
"movable_node" is not set on the kernel command line, because
then we're told to not care about hotunpluggability of such
memory regions.
MEMBLOCK_DRIVER_MANAGED: memory is not indicated as "System RAM" in
the firmware-provided memory map; this memory is always detected
and added to the system by a driver; memory might not actually be
physically hotunpluggable. kexec *must not* indicate this memory to
the second kernel and *must not* place kexec-images on this memory.
Link: https://lkml.kernel.org/r/20211004093605.5830-5-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Mike Rapoport <rppt@linux.ibm.com>
Cc: "Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Jianyong Wu <Jianyong.Wu@arm.com>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Shahab Vahedi <shahab@synopsys.com>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Vineet Gupta <vgupta@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2021-11-05 20:44:53 +00:00
|
|
|
/*
|
|
|
|
* Using MEMBLOCK_NONE will properly skip MEMBLOCK_DRIVER_MANAGED. See
|
|
|
|
* IORESOURCE_SYSRAM_DRIVER_MANAGED handling in
|
|
|
|
* locate_mem_hole_callback().
|
|
|
|
*/
|
2018-11-15 05:52:43 +00:00
|
|
|
if (kbuf->top_down) {
|
2018-11-15 05:52:44 +00:00
|
|
|
for_each_free_mem_range_reverse(i, NUMA_NO_NODE, MEMBLOCK_NONE,
|
2018-11-15 05:52:43 +00:00
|
|
|
&mstart, &mend, NULL) {
|
|
|
|
/*
|
|
|
|
* In memblock, end points to the first byte after the
|
|
|
|
* range while in kexec, end points to the last byte
|
|
|
|
* in the range.
|
|
|
|
*/
|
|
|
|
res.start = mstart;
|
|
|
|
res.end = mend - 1;
|
|
|
|
ret = func(&res, kbuf);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2018-11-15 05:52:44 +00:00
|
|
|
for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
|
|
|
|
&mstart, &mend, NULL) {
|
2018-11-15 05:52:43 +00:00
|
|
|
/*
|
|
|
|
* In memblock, end points to the first byte after the
|
|
|
|
* range while in kexec, end points to the last byte
|
|
|
|
* in the range.
|
|
|
|
*/
|
|
|
|
res.start = mstart;
|
|
|
|
res.end = mend - 1;
|
|
|
|
ret = func(&res, kbuf);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2019-05-14 00:22:59 +00:00
|
|
|
#else
|
|
|
|
static int kexec_walk_memblock(struct kexec_buf *kbuf,
|
|
|
|
int (*func)(struct resource *, void *))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2018-11-15 05:52:43 +00:00
|
|
|
#endif
|
|
|
|
|
2016-11-29 12:45:47 +00:00
|
|
|
/**
|
2018-11-15 05:52:43 +00:00
|
|
|
* kexec_walk_resources - call func(data) on free memory regions
|
2016-11-29 12:45:47 +00:00
|
|
|
* @kbuf: Context info for the search. Also passed to @func.
|
|
|
|
* @func: Function to call for each memory region.
|
|
|
|
*
|
|
|
|
* Return: The memory walk will stop when func returns a non-zero value
|
|
|
|
* and that value will be returned. If all free regions are visited without
|
|
|
|
* func returning non-zero, then zero will be returned.
|
|
|
|
*/
|
2018-11-15 05:52:43 +00:00
|
|
|
static int kexec_walk_resources(struct kexec_buf *kbuf,
|
|
|
|
int (*func)(struct resource *, void *))
|
2016-11-29 12:45:47 +00:00
|
|
|
{
|
2024-01-24 05:12:44 +00:00
|
|
|
#ifdef CONFIG_CRASH_DUMP
|
2016-11-29 12:45:47 +00:00
|
|
|
if (kbuf->image->type == KEXEC_TYPE_CRASH)
|
|
|
|
return walk_iomem_res_desc(crashk_res.desc,
|
|
|
|
IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY,
|
|
|
|
crashk_res.start, crashk_res.end,
|
|
|
|
kbuf, func);
|
2024-01-24 05:12:44 +00:00
|
|
|
#endif
|
|
|
|
if (kbuf->top_down)
|
kexec_file: load kernel at top of system RAM if required
Patch series "kexec_file: Load kernel at top of system RAM if required".
Justification:
==============
Kexec_load interface has been doing top down searching and loading
kernel/initrd/purgtory etc to prepare for kexec reboot. In that way, the
benefits are that it avoids to consume and fragment limited low memory
which satisfy DMA buffer allocation and big chunk of continuous memory
during system init; and avoids to stir with BIOS/FW reserved or occupied
areas, or corner case handling/work around/quirk occupied areas when doing
system init. By the way, the top-down searching and loading of kexec-ed
kernel is done in user space utility code.
For kexec_file loading, even if kexec_buf.top_down is 'true', it's simply
ignored. It calls walk_system_ram_res() directly to go through all
resources of System RAM bottom up, to find an available memory region,
then call locate_mem_hole_callback() to allocate memory in that found
memory region from top to down. This is not expected and inconsistent
with kexec_load.
Implementation
===============
In patch 1, introduce a new function walk_system_ram_res_rev() which is a
variant of walk_system_ram_res(), it walks through a list of all the
resources of System RAM in reversed order, i.e., from higher to lower.
In patch 2, check if kexec_buf.top_down is 'true' in
kexec_walk_resources(), if yes, call walk_system_ram_res_rev() to find
memory region of system RAM from top to down to load kernel/initrd etc.
Background information: ======================= And I ever tried this in
the past in a different way, please see below link. In the post, I tried
to adjust struct sibling linking code, replace the the singly linked list
with list_head so that walk_system_ram_res_rev() can be implemented in a
much easier way. Finally I failed.
https://lore.kernel.org/all/20180718024944.577-4-bhe@redhat.com/
This time, I picked up the patch from AKASHI Takahiro's old post and made
some change to take as the current patch 1:
https://lists.infradead.org/pipermail/linux-arm-kernel/2017-September/531456.html
This patch (of 2):
Kexec_load interface has been doing top down searching and loading
kernel/initrd/purgtory etc to prepare for kexec reboot. In that way, the
benefits are that it avoids to consume and fragment limited low memory
which satisfy DMA buffer allocation and big chunk of continuous memory
during system init; and avoids to stir with BIOS/FW reserved or occupied
areas, or corner case handling/work around/quirk occupied areas when doing
system init. By the way, the top-down searching and loading of kexec-ed
kernel is done in user space utility code.
For kexec_file loading, even if kexec_buf.top_down is 'true', it's simply
ignored. It calls walk_system_ram_res() directly to go through all
resources of System RAM bottom up, to find an available memory region,
then call locate_mem_hole_callback() to allocate memory in that found
memory region from top to down. This is not expected and inconsistent
with kexec_load.
Here check if kexec_buf.top_down is 'true' in kexec_walk_resources(), if
yes, call the newly added walk_system_ram_res_rev() to find memory region
of system RAM from top to down to load kernel/initrd etc.
Link: https://lkml.kernel.org/r/20231114091658.228030-1-bhe@redhat.com
Link: https://lkml.kernel.org/r/20231114091658.228030-3-bhe@redhat.com
Signed-off-by: Baoquan He <bhe@redhat.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Baoquan He <bhe@redhat.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-11-14 09:16:58 +00:00
|
|
|
return walk_system_ram_res_rev(0, ULONG_MAX, kbuf, func);
|
2016-11-29 12:45:47 +00:00
|
|
|
else
|
|
|
|
return walk_system_ram_res(0, ULONG_MAX, kbuf, func);
|
|
|
|
}
|
|
|
|
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
static int kexec_alloc_contig(struct kexec_buf *kbuf)
|
|
|
|
{
|
|
|
|
size_t nr_pages = kbuf->memsz >> PAGE_SHIFT;
|
|
|
|
unsigned long mem;
|
|
|
|
struct page *p;
|
|
|
|
|
|
|
|
/* User space disabled CMA allocations, bail out. */
|
|
|
|
if (kbuf->image->no_cma)
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
/* Skip CMA logic for crash kernel */
|
|
|
|
if (kbuf->image->type == KEXEC_TYPE_CRASH)
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
p = dma_alloc_from_contiguous(NULL, nr_pages, get_order(kbuf->buf_align), true);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
pr_debug("allocated %zu DMA pages at 0x%lx", nr_pages, page_to_boot_pfn(p));
|
|
|
|
|
|
|
|
mem = page_to_boot_pfn(p) << PAGE_SHIFT;
|
|
|
|
|
|
|
|
if (kimage_is_destination_range(kbuf->image, mem, mem + kbuf->memsz)) {
|
|
|
|
/* Our region is already in use by a statically defined one. Bail out. */
|
|
|
|
pr_debug("CMA overlaps existing mem: 0x%lx+0x%lx\n", mem, kbuf->memsz);
|
|
|
|
dma_release_from_contiguous(NULL, p, nr_pages);
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
kbuf->mem = page_to_boot_pfn(p) << PAGE_SHIFT;
|
|
|
|
kbuf->cma = p;
|
|
|
|
|
|
|
|
arch_kexec_post_alloc_pages(page_address(p), (int)nr_pages, 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-29 12:45:49 +00:00
|
|
|
/**
|
|
|
|
* kexec_locate_mem_hole - find free memory for the purgatory or the next kernel
|
|
|
|
* @kbuf: Parameters for the memory search.
|
|
|
|
*
|
|
|
|
* On success, kbuf->mem will have the start address of the memory region found.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, negative errno on error.
|
|
|
|
*/
|
|
|
|
int kexec_locate_mem_hole(struct kexec_buf *kbuf)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2018-11-15 05:52:42 +00:00
|
|
|
/* Arch knows where to place */
|
|
|
|
if (kbuf->mem != KEXEC_BUF_MEM_UNKNOWN)
|
|
|
|
return 0;
|
|
|
|
|
2025-05-09 07:46:25 +00:00
|
|
|
/*
|
|
|
|
* If KHO is active, only use KHO scratch memory. All other memory
|
|
|
|
* could potentially be handed over.
|
|
|
|
*/
|
|
|
|
ret = kho_locate_mem_hole(kbuf, locate_mem_hole_callback);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
/*
|
|
|
|
* Try to find a free physically contiguous block of memory first. With that, we
|
|
|
|
* can avoid any copying at kexec time.
|
|
|
|
*/
|
|
|
|
if (!kexec_alloc_contig(kbuf))
|
|
|
|
return 0;
|
|
|
|
|
2019-05-14 00:22:59 +00:00
|
|
|
if (!IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
|
2018-11-15 05:52:43 +00:00
|
|
|
ret = kexec_walk_resources(kbuf, locate_mem_hole_callback);
|
|
|
|
else
|
|
|
|
ret = kexec_walk_memblock(kbuf, locate_mem_hole_callback);
|
2016-11-29 12:45:49 +00:00
|
|
|
|
|
|
|
return ret == 1 ? 0 : -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
2016-11-29 12:45:48 +00:00
|
|
|
/**
|
|
|
|
* kexec_add_buffer - place a buffer in a kexec segment
|
|
|
|
* @kbuf: Buffer contents and memory parameters.
|
|
|
|
*
|
2023-08-07 02:52:06 +00:00
|
|
|
* This function assumes that kexec_lock is held.
|
2016-11-29 12:45:48 +00:00
|
|
|
* On successful return, @kbuf->mem will have the physical address of
|
|
|
|
* the buffer in memory.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, negative errno on error.
|
2015-09-09 22:38:51 +00:00
|
|
|
*/
|
2016-11-29 12:45:48 +00:00
|
|
|
int kexec_add_buffer(struct kexec_buf *kbuf)
|
2015-09-09 22:38:51 +00:00
|
|
|
{
|
|
|
|
struct kexec_segment *ksegment;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Currently adding segment this way is allowed only in file mode */
|
2016-11-29 12:45:48 +00:00
|
|
|
if (!kbuf->image->file_mode)
|
2015-09-09 22:38:51 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-11-29 12:45:48 +00:00
|
|
|
if (kbuf->image->nr_segments >= KEXEC_SEGMENT_MAX)
|
2015-09-09 22:38:51 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we are not trying to add buffer after allocating
|
|
|
|
* control pages. All segments need to be placed first before
|
|
|
|
* any control pages are allocated. As control page allocation
|
|
|
|
* logic goes through list of segments to make sure there are
|
|
|
|
* no destination overlaps.
|
|
|
|
*/
|
2016-11-29 12:45:48 +00:00
|
|
|
if (!list_empty(&kbuf->image->control_pages)) {
|
2015-09-09 22:38:51 +00:00
|
|
|
WARN_ON(1);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-11-29 12:45:48 +00:00
|
|
|
/* Ensure minimum alignment needed for segments. */
|
|
|
|
kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE);
|
|
|
|
kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE);
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
kbuf->cma = NULL;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
/* Walk the RAM ranges and allocate a suitable range for the buffer */
|
2020-07-29 11:39:19 +00:00
|
|
|
ret = arch_kexec_locate_mem_hole(kbuf);
|
2016-11-29 12:45:49 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
/* Found a suitable memory range */
|
2016-11-29 12:45:48 +00:00
|
|
|
ksegment = &kbuf->image->segment[kbuf->image->nr_segments];
|
2015-09-09 22:38:51 +00:00
|
|
|
ksegment->kbuf = kbuf->buffer;
|
|
|
|
ksegment->bufsz = kbuf->bufsz;
|
|
|
|
ksegment->mem = kbuf->mem;
|
|
|
|
ksegment->memsz = kbuf->memsz;
|
kexec: enable CMA based contiguous allocation
When booting a new kernel with kexec_file, the kernel picks a target
location that the kernel should live at, then allocates random pages,
checks whether any of those patches magically happens to coincide with a
target address range and if so, uses them for that range.
For every page allocated this way, it then creates a page list that the
relocation code - code that executes while all CPUs are off and we are
just about to jump into the new kernel - copies to their final memory
location. We can not put them there before, because chances are pretty
good that at least some page in the target range is already in use by the
currently running Linux environment. Copying is happening from a single
CPU at RAM rate, which takes around 4-50 ms per 100 MiB.
All of this is inefficient and error prone.
To successfully kexec, we need to quiesce all devices of the outgoing
kernel so they don't scribble over the new kernel's memory. We have seen
cases where that does not happen properly (*cough* GIC *cough*) and hence
the new kernel was corrupted. This started a month long journey to root
cause failing kexecs to eventually see memory corruption, because the new
kernel was corrupted severely enough that it could not emit output to tell
us about the fact that it was corrupted. By allocating memory for the
next kernel from a memory range that is guaranteed scribbling free, we can
boot the next kernel up to a point where it is at least able to detect
corruption and maybe even stop it before it becomes severe. This
increases the chance for successful kexecs.
Since kexec got introduced, Linux has gained the CMA framework which can
perform physically contiguous memory mappings, while keeping that memory
available for movable memory when it is not needed for contiguous
allocations. The default CMA allocator is for DMA allocations.
This patch adds logic to the kexec file loader to attempt to place the
target payload at a location allocated from CMA. If successful, it uses
that memory range directly instead of creating copy instructions during
the hot phase. To ensure that there is a safety net in case anything goes
wrong with the CMA allocation, it also adds a flag for user space to force
disable CMA allocations.
Using CMA allocations has two advantages:
1) Faster by 4-50 ms per 100 MiB. There is no more need to copy in the
hot phase.
2) More robust. Even if by accident some page is still in use for DMA,
the new kernel image will be safe from that access because it resides
in a memory region that is considered allocated in the old kernel and
has a chance to reinitialize that component.
Link: https://lkml.kernel.org/r/20250610085327.51817-1-graf@amazon.com
Signed-off-by: Alexander Graf <graf@amazon.com>
Acked-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Zhongkun He <hezhongkun.hzk@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2025-06-10 08:53:27 +00:00
|
|
|
kbuf->image->segment_cma[kbuf->image->nr_segments] = kbuf->cma;
|
2016-11-29 12:45:48 +00:00
|
|
|
kbuf->image->nr_segments++;
|
2015-09-09 22:38:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate and store the digest of segments */
|
|
|
|
static int kexec_calculate_store_digests(struct kimage *image)
|
|
|
|
{
|
2025-06-30 16:06:37 +00:00
|
|
|
struct sha256_ctx sctx;
|
2015-09-09 22:38:51 +00:00
|
|
|
int ret = 0, i, j, zero_buf_sz, sha_region_sz;
|
2025-04-28 18:57:20 +00:00
|
|
|
size_t nullsz;
|
|
|
|
u8 digest[SHA256_DIGEST_SIZE];
|
2015-09-09 22:38:51 +00:00
|
|
|
void *zero_buf;
|
|
|
|
struct kexec_sha_region *sha_regions;
|
|
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
|
|
|
|
2023-07-12 16:15:45 +00:00
|
|
|
if (!IS_ENABLED(CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY))
|
kexec_file: make use of purgatory optional
Patch series "kexec_file, x86, powerpc: refactoring for other
architecutres", v2.
This is a preparatory patchset for adding kexec_file support on arm64.
It was originally included in a arm64 patch set[1], but Philipp is also
working on their kexec_file support on s390[2] and some changes are now
conflicting.
So these common parts were extracted and put into a separate patch set
for better integration. What's more, my original patch#4 was split into
a few small chunks for easier review after Dave's comment.
As such, the resulting code is basically identical with my original, and
the only *visible* differences are:
- renaming of _kexec_kernel_image_probe() and _kimage_file_post_load_cleanup()
- change one of types of arguments at prepare_elf64_headers()
Those, unfortunately, require a couple of trivial changes on the rest
(#1, #6 to #13) of my arm64 kexec_file patch set[1].
Patch #1 allows making a use of purgatory optional, particularly useful
for arm64.
Patch #2 commonalizes arch_kexec_kernel_{image_probe, image_load,
verify_sig}() and arch_kimage_file_post_load_cleanup() across
architectures.
Patches #3-#7 are also intended to generalize parse_elf64_headers(),
along with exclude_mem_range(), to be made best re-use of.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2018-February/561182.html
[2] http://lkml.iu.edu//hypermail/linux/kernel/1802.1/02596.html
This patch (of 7):
On arm64, crash dump kernel's usable memory is protected by *unmapping*
it from kernel virtual space unlike other architectures where the region
is just made read-only. It is highly unlikely that the region is
accidentally corrupted and this observation rationalizes that digest
check code can also be dropped from purgatory. The resulting code is so
simple as it doesn't require a bit ugly re-linking/relocation stuff,
i.e. arch_kexec_apply_relocations_add().
Please see:
http://lists.infradead.org/pipermail/linux-arm-kernel/2017-December/545428.html
All that the purgatory does is to shuffle arguments and jump into a new
kernel, while we still need to have some space for a hash value
(purgatory_sha256_digest) which is never checked against.
As such, it doesn't make sense to have trampline code between old kernel
and new kernel on arm64.
This patch introduces a new configuration, ARCH_HAS_KEXEC_PURGATORY, and
allows related code to be compiled in only if necessary.
[takahiro.akashi@linaro.org: fix trivial screwup]
Link: http://lkml.kernel.org/r/20180309093346.GF25863@linaro.org
Link: http://lkml.kernel.org/r/20180306102303.9063-2-takahiro.akashi@linaro.org
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Acked-by: Dave Young <dyoung@redhat.com>
Tested-by: Dave Young <dyoung@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-04-13 22:35:45 +00:00
|
|
|
return 0;
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT);
|
|
|
|
zero_buf_sz = PAGE_SIZE;
|
|
|
|
|
|
|
|
sha_region_sz = KEXEC_SEGMENT_MAX * sizeof(struct kexec_sha_region);
|
|
|
|
sha_regions = vzalloc(sha_region_sz);
|
2025-04-28 18:57:20 +00:00
|
|
|
if (!sha_regions)
|
|
|
|
return -ENOMEM;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2025-06-30 16:06:37 +00:00
|
|
|
sha256_init(&sctx);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
for (j = i = 0; i < image->nr_segments; i++) {
|
|
|
|
struct kexec_segment *ksegment;
|
|
|
|
|
kexec: exclude elfcorehdr from the segment digest
When a crash kernel is loaded via the kexec_file_load() syscall, the
kernel places the various segments (ie crash kernel, crash initrd,
boot_params, elfcorehdr, purgatory, etc) in memory. For those
architectures that utilize purgatory, a hash digest of the segments is
calculated for integrity checking. The digest is embedded into the
purgatory image prior to placing in memory.
Updates to the elfcorehdr in response to CPU and memory changes would
cause the purgatory integrity checking to fail (at crash time, and no
vmcore created). Therefore, the elfcorehdr segment is explicitly excluded
from the purgatory digest, enabling updates to the elfcorehdr while also
avoiding the need to recompute the hash digest and reload purgatory.
Link: https://lkml.kernel.org/r/20230814214446.6659-4-eric.devolder@oracle.com
Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
Suggested-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Acked-by: Hari Bathini <hbathini@linux.ibm.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: Akhil Raj <lf32.dev@gmail.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Borislav Petkov (AMD) <bp@alien8.de>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Mimi Zohar <zohar@linux.ibm.com>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Takashi Iwai <tiwai@suse.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Cc: Valentin Schneider <vschneid@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-08-14 21:44:41 +00:00
|
|
|
#ifdef CONFIG_CRASH_HOTPLUG
|
|
|
|
/* Exclude elfcorehdr segment to allow future changes via hotplug */
|
2024-08-05 15:07:50 +00:00
|
|
|
if (i == image->elfcorehdr_index)
|
kexec: exclude elfcorehdr from the segment digest
When a crash kernel is loaded via the kexec_file_load() syscall, the
kernel places the various segments (ie crash kernel, crash initrd,
boot_params, elfcorehdr, purgatory, etc) in memory. For those
architectures that utilize purgatory, a hash digest of the segments is
calculated for integrity checking. The digest is embedded into the
purgatory image prior to placing in memory.
Updates to the elfcorehdr in response to CPU and memory changes would
cause the purgatory integrity checking to fail (at crash time, and no
vmcore created). Therefore, the elfcorehdr segment is explicitly excluded
from the purgatory digest, enabling updates to the elfcorehdr while also
avoiding the need to recompute the hash digest and reload purgatory.
Link: https://lkml.kernel.org/r/20230814214446.6659-4-eric.devolder@oracle.com
Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
Suggested-by: Baoquan He <bhe@redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Acked-by: Hari Bathini <hbathini@linux.ibm.com>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: Akhil Raj <lf32.dev@gmail.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Borislav Petkov (AMD) <bp@alien8.de>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Mimi Zohar <zohar@linux.ibm.com>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Takashi Iwai <tiwai@suse.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Cc: Valentin Schneider <vschneid@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-08-14 21:44:41 +00:00
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
ksegment = &image->segment[i];
|
|
|
|
/*
|
|
|
|
* Skip purgatory as it will be modified once we put digest
|
|
|
|
* info in purgatory.
|
|
|
|
*/
|
|
|
|
if (ksegment->kbuf == pi->purgatory_buf)
|
|
|
|
continue;
|
|
|
|
|
2025-04-21 22:25:10 +00:00
|
|
|
/*
|
|
|
|
* Skip the segment if ima_segment_index is set and matches
|
|
|
|
* the current index
|
|
|
|
*/
|
|
|
|
if (check_ima_segment_index(image, i))
|
|
|
|
continue;
|
|
|
|
|
2025-06-30 16:06:37 +00:00
|
|
|
sha256_update(&sctx, ksegment->kbuf, ksegment->bufsz);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assume rest of the buffer is filled with zero and
|
|
|
|
* update digest accordingly.
|
|
|
|
*/
|
|
|
|
nullsz = ksegment->memsz - ksegment->bufsz;
|
|
|
|
while (nullsz) {
|
|
|
|
unsigned long bytes = nullsz;
|
|
|
|
|
|
|
|
if (bytes > zero_buf_sz)
|
|
|
|
bytes = zero_buf_sz;
|
2025-06-30 16:06:37 +00:00
|
|
|
sha256_update(&sctx, zero_buf, bytes);
|
2015-09-09 22:38:51 +00:00
|
|
|
nullsz -= bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
sha_regions[j].start = ksegment->mem;
|
|
|
|
sha_regions[j].len = ksegment->memsz;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
2025-06-30 16:06:37 +00:00
|
|
|
sha256_final(&sctx, digest);
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2025-04-28 18:57:20 +00:00
|
|
|
ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha_regions",
|
|
|
|
sha_regions, sha_region_sz, 0);
|
|
|
|
if (ret)
|
|
|
|
goto out_free_sha_regions;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2025-04-28 18:57:20 +00:00
|
|
|
ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha256_digest",
|
|
|
|
digest, SHA256_DIGEST_SIZE, 0);
|
2015-09-09 22:38:51 +00:00
|
|
|
out_free_sha_regions:
|
|
|
|
vfree(sha_regions);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-07-12 16:15:45 +00:00
|
|
|
#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY
|
2018-04-13 22:36:28 +00:00
|
|
|
/*
|
|
|
|
* kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
|
|
|
|
* @pi: Purgatory to be loaded.
|
|
|
|
* @kbuf: Buffer to setup.
|
|
|
|
*
|
|
|
|
* Allocates the memory needed for the buffer. Caller is responsible to free
|
|
|
|
* the memory after use.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, negative errno on error.
|
|
|
|
*/
|
|
|
|
static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
|
|
|
|
struct kexec_buf *kbuf)
|
2015-09-09 22:38:51 +00:00
|
|
|
{
|
2018-04-13 22:36:28 +00:00
|
|
|
const Elf_Shdr *sechdrs;
|
|
|
|
unsigned long bss_align;
|
|
|
|
unsigned long bss_sz;
|
|
|
|
unsigned long align;
|
|
|
|
int i, ret;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:28 +00:00
|
|
|
sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
|
2018-04-13 22:36:43 +00:00
|
|
|
kbuf->buf_align = bss_align = 1;
|
|
|
|
kbuf->bufsz = bss_sz = 0;
|
2018-04-13 22:36:28 +00:00
|
|
|
|
|
|
|
for (i = 0; i < pi->ehdr->e_shnum; i++) {
|
|
|
|
if (!(sechdrs[i].sh_flags & SHF_ALLOC))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
align = sechdrs[i].sh_addralign;
|
|
|
|
if (sechdrs[i].sh_type != SHT_NOBITS) {
|
|
|
|
if (kbuf->buf_align < align)
|
|
|
|
kbuf->buf_align = align;
|
|
|
|
kbuf->bufsz = ALIGN(kbuf->bufsz, align);
|
|
|
|
kbuf->bufsz += sechdrs[i].sh_size;
|
|
|
|
} else {
|
|
|
|
if (bss_align < align)
|
|
|
|
bss_align = align;
|
|
|
|
bss_sz = ALIGN(bss_sz, align);
|
|
|
|
bss_sz += sechdrs[i].sh_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kbuf->bufsz = ALIGN(kbuf->bufsz, bss_align);
|
|
|
|
kbuf->memsz = kbuf->bufsz + bss_sz;
|
|
|
|
if (kbuf->buf_align < bss_align)
|
|
|
|
kbuf->buf_align = bss_align;
|
|
|
|
|
|
|
|
kbuf->buffer = vzalloc(kbuf->bufsz);
|
|
|
|
if (!kbuf->buffer)
|
|
|
|
return -ENOMEM;
|
|
|
|
pi->purgatory_buf = kbuf->buffer;
|
|
|
|
|
|
|
|
ret = kexec_add_buffer(kbuf);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
out:
|
|
|
|
vfree(pi->purgatory_buf);
|
|
|
|
pi->purgatory_buf = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer.
|
|
|
|
* @pi: Purgatory to be loaded.
|
|
|
|
* @kbuf: Buffer prepared to store purgatory.
|
|
|
|
*
|
|
|
|
* Allocates the memory needed for the buffer. Caller is responsible to free
|
|
|
|
* the memory after use.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, negative errno on error.
|
|
|
|
*/
|
|
|
|
static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
|
|
|
|
struct kexec_buf *kbuf)
|
|
|
|
{
|
|
|
|
unsigned long bss_addr;
|
|
|
|
unsigned long offset;
|
2023-05-25 14:26:25 +00:00
|
|
|
size_t sechdrs_size;
|
2018-04-13 22:36:28 +00:00
|
|
|
Elf_Shdr *sechdrs;
|
|
|
|
int i;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:39 +00:00
|
|
|
/*
|
|
|
|
* The section headers in kexec_purgatory are read-only. In order to
|
|
|
|
* have them modifiable make a temporary copy.
|
|
|
|
*/
|
2023-05-25 14:26:25 +00:00
|
|
|
sechdrs_size = array_size(sizeof(Elf_Shdr), pi->ehdr->e_shnum);
|
|
|
|
sechdrs = vzalloc(sechdrs_size);
|
2015-09-09 22:38:51 +00:00
|
|
|
if (!sechdrs)
|
|
|
|
return -ENOMEM;
|
2023-05-25 14:26:25 +00:00
|
|
|
memcpy(sechdrs, (void *)pi->ehdr + pi->ehdr->e_shoff, sechdrs_size);
|
2018-04-13 22:36:28 +00:00
|
|
|
pi->sechdrs = sechdrs;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:35 +00:00
|
|
|
offset = 0;
|
|
|
|
bss_addr = kbuf->mem + kbuf->bufsz;
|
2018-04-13 22:36:32 +00:00
|
|
|
kbuf->image->start = pi->ehdr->e_entry;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
for (i = 0; i < pi->ehdr->e_shnum; i++) {
|
2018-04-13 22:36:28 +00:00
|
|
|
unsigned long align;
|
2018-04-13 22:36:35 +00:00
|
|
|
void *src, *dst;
|
2018-04-13 22:36:28 +00:00
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
if (!(sechdrs[i].sh_flags & SHF_ALLOC))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
align = sechdrs[i].sh_addralign;
|
2018-04-13 22:36:32 +00:00
|
|
|
if (sechdrs[i].sh_type == SHT_NOBITS) {
|
2015-09-09 22:38:51 +00:00
|
|
|
bss_addr = ALIGN(bss_addr, align);
|
|
|
|
sechdrs[i].sh_addr = bss_addr;
|
|
|
|
bss_addr += sechdrs[i].sh_size;
|
2018-04-13 22:36:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-04-13 22:36:35 +00:00
|
|
|
offset = ALIGN(offset, align);
|
2023-05-19 14:47:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the segment contains the entry point, if so,
|
|
|
|
* calculate the value of image->start based on it.
|
|
|
|
* If the compiler has produced more than one .text section
|
|
|
|
* (Eg: .text.hot), they are generally after the main .text
|
|
|
|
* section, and they shall not be used to calculate
|
|
|
|
* image->start. So do not re-calculate image->start if it
|
|
|
|
* is not set to the initial value, and warn the user so they
|
|
|
|
* have a chance to fix their purgatory's linker script.
|
|
|
|
*/
|
2018-04-13 22:36:32 +00:00
|
|
|
if (sechdrs[i].sh_flags & SHF_EXECINSTR &&
|
|
|
|
pi->ehdr->e_entry >= sechdrs[i].sh_addr &&
|
|
|
|
pi->ehdr->e_entry < (sechdrs[i].sh_addr
|
2023-05-19 14:47:36 +00:00
|
|
|
+ sechdrs[i].sh_size) &&
|
|
|
|
!WARN_ON(kbuf->image->start != pi->ehdr->e_entry)) {
|
2018-04-13 22:36:32 +00:00
|
|
|
kbuf->image->start -= sechdrs[i].sh_addr;
|
2018-04-13 22:36:35 +00:00
|
|
|
kbuf->image->start += kbuf->mem + offset;
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
2018-04-13 22:36:39 +00:00
|
|
|
src = (void *)pi->ehdr + sechdrs[i].sh_offset;
|
2018-04-13 22:36:35 +00:00
|
|
|
dst = pi->purgatory_buf + offset;
|
|
|
|
memcpy(dst, src, sechdrs[i].sh_size);
|
|
|
|
|
|
|
|
sechdrs[i].sh_addr = kbuf->mem + offset;
|
2018-04-13 22:36:39 +00:00
|
|
|
sechdrs[i].sh_offset = offset;
|
2018-04-13 22:36:35 +00:00
|
|
|
offset += sechdrs[i].sh_size;
|
2018-04-13 22:36:32 +00:00
|
|
|
}
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:28 +00:00
|
|
|
return 0;
|
2015-09-09 22:38:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int kexec_apply_relocations(struct kimage *image)
|
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
2018-04-13 22:36:24 +00:00
|
|
|
const Elf_Shdr *sechdrs;
|
|
|
|
|
|
|
|
sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
for (i = 0; i < pi->ehdr->e_shnum; i++) {
|
2018-04-13 22:36:24 +00:00
|
|
|
const Elf_Shdr *relsec;
|
|
|
|
const Elf_Shdr *symtab;
|
|
|
|
Elf_Shdr *section;
|
|
|
|
|
|
|
|
relsec = sechdrs + i;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:24 +00:00
|
|
|
if (relsec->sh_type != SHT_RELA &&
|
|
|
|
relsec->sh_type != SHT_REL)
|
2015-09-09 22:38:51 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For section of type SHT_RELA/SHT_REL,
|
|
|
|
* ->sh_link contains section header index of associated
|
|
|
|
* symbol table. And ->sh_info contains section header
|
|
|
|
* index of section to which relocations apply.
|
|
|
|
*/
|
2018-04-13 22:36:24 +00:00
|
|
|
if (relsec->sh_info >= pi->ehdr->e_shnum ||
|
|
|
|
relsec->sh_link >= pi->ehdr->e_shnum)
|
2015-09-09 22:38:51 +00:00
|
|
|
return -ENOEXEC;
|
|
|
|
|
2018-04-13 22:36:24 +00:00
|
|
|
section = pi->sechdrs + relsec->sh_info;
|
|
|
|
symtab = sechdrs + relsec->sh_link;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
if (!(section->sh_flags & SHF_ALLOC))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* symtab->sh_link contain section header index of associated
|
|
|
|
* string table.
|
|
|
|
*/
|
|
|
|
if (symtab->sh_link >= pi->ehdr->e_shnum)
|
|
|
|
/* Invalid section number? */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Respective architecture needs to provide support for applying
|
|
|
|
* relocations of type SHT_RELA/SHT_REL.
|
|
|
|
*/
|
2018-04-13 22:36:24 +00:00
|
|
|
if (relsec->sh_type == SHT_RELA)
|
|
|
|
ret = arch_kexec_apply_relocations_add(pi, section,
|
|
|
|
relsec, symtab);
|
|
|
|
else if (relsec->sh_type == SHT_REL)
|
|
|
|
ret = arch_kexec_apply_relocations(pi, section,
|
|
|
|
relsec, symtab);
|
2015-09-09 22:38:51 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-13 22:36:43 +00:00
|
|
|
/*
|
|
|
|
* kexec_load_purgatory - Load and relocate the purgatory object.
|
|
|
|
* @image: Image to add the purgatory to.
|
|
|
|
* @kbuf: Memory parameters to use.
|
|
|
|
*
|
|
|
|
* Allocates the memory needed for image->purgatory_info.sechdrs and
|
|
|
|
* image->purgatory_info.purgatory_buf/kbuf->buffer. Caller is responsible
|
|
|
|
* to free the memory after use.
|
|
|
|
*
|
|
|
|
* Return: 0 on success, negative errno on error.
|
|
|
|
*/
|
|
|
|
int kexec_load_purgatory(struct kimage *image, struct kexec_buf *kbuf)
|
2015-09-09 22:38:51 +00:00
|
|
|
{
|
|
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (kexec_purgatory_size <= 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-04-13 22:36:17 +00:00
|
|
|
pi->ehdr = (const Elf_Ehdr *)kexec_purgatory;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:43 +00:00
|
|
|
ret = kexec_purgatory_setup_kbuf(pi, kbuf);
|
2015-09-09 22:38:51 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2018-04-13 22:36:43 +00:00
|
|
|
ret = kexec_purgatory_setup_sechdrs(pi, kbuf);
|
2018-04-13 22:36:28 +00:00
|
|
|
if (ret)
|
|
|
|
goto out_free_kbuf;
|
|
|
|
|
2015-09-09 22:38:51 +00:00
|
|
|
ret = kexec_apply_relocations(image);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
out:
|
|
|
|
vfree(pi->sechdrs);
|
2016-09-01 23:14:44 +00:00
|
|
|
pi->sechdrs = NULL;
|
2018-04-13 22:36:28 +00:00
|
|
|
out_free_kbuf:
|
2015-09-09 22:38:51 +00:00
|
|
|
vfree(pi->purgatory_buf);
|
2016-09-01 23:14:44 +00:00
|
|
|
pi->purgatory_buf = NULL;
|
2015-09-09 22:38:51 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-04-13 22:36:21 +00:00
|
|
|
/*
|
|
|
|
* kexec_purgatory_find_symbol - find a symbol in the purgatory
|
|
|
|
* @pi: Purgatory to search in.
|
|
|
|
* @name: Name of the symbol.
|
|
|
|
*
|
|
|
|
* Return: pointer to symbol in read-only symtab on success, NULL on error.
|
|
|
|
*/
|
|
|
|
static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi,
|
|
|
|
const char *name)
|
2015-09-09 22:38:51 +00:00
|
|
|
{
|
2018-04-13 22:36:21 +00:00
|
|
|
const Elf_Shdr *sechdrs;
|
2018-04-13 22:36:17 +00:00
|
|
|
const Elf_Ehdr *ehdr;
|
2018-04-13 22:36:21 +00:00
|
|
|
const Elf_Sym *syms;
|
2015-09-09 22:38:51 +00:00
|
|
|
const char *strtab;
|
2018-04-13 22:36:21 +00:00
|
|
|
int i, k;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:21 +00:00
|
|
|
if (!pi->ehdr)
|
2015-09-09 22:38:51 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ehdr = pi->ehdr;
|
2018-04-13 22:36:21 +00:00
|
|
|
sechdrs = (void *)ehdr + ehdr->e_shoff;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
for (i = 0; i < ehdr->e_shnum; i++) {
|
|
|
|
if (sechdrs[i].sh_type != SHT_SYMTAB)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (sechdrs[i].sh_link >= ehdr->e_shnum)
|
|
|
|
/* Invalid strtab section number */
|
|
|
|
continue;
|
2018-04-13 22:36:21 +00:00
|
|
|
strtab = (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset;
|
|
|
|
syms = (void *)ehdr + sechdrs[i].sh_offset;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
/* Go through symbols for a match */
|
|
|
|
for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) {
|
|
|
|
if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (strcmp(strtab + syms[k].st_name, name) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (syms[k].st_shndx == SHN_UNDEF ||
|
|
|
|
syms[k].st_shndx >= ehdr->e_shnum) {
|
|
|
|
pr_debug("Symbol: %s has bad section index %d.\n",
|
|
|
|
name, syms[k].st_shndx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Found the symbol we are looking for */
|
|
|
|
return &syms[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name)
|
|
|
|
{
|
|
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
2018-04-13 22:36:21 +00:00
|
|
|
const Elf_Sym *sym;
|
2015-09-09 22:38:51 +00:00
|
|
|
Elf_Shdr *sechdr;
|
|
|
|
|
|
|
|
sym = kexec_purgatory_find_symbol(pi, name);
|
|
|
|
if (!sym)
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
|
|
sechdr = &pi->sechdrs[sym->st_shndx];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns the address where symbol will finally be loaded after
|
|
|
|
* kexec_load_segment()
|
|
|
|
*/
|
|
|
|
return (void *)(sechdr->sh_addr + sym->st_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get or set value of a symbol. If "get_value" is true, symbol value is
|
|
|
|
* returned in buf otherwise symbol value is set based on value in buf.
|
|
|
|
*/
|
|
|
|
int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name,
|
|
|
|
void *buf, unsigned int size, bool get_value)
|
|
|
|
{
|
|
|
|
struct purgatory_info *pi = &image->purgatory_info;
|
2018-04-13 22:36:21 +00:00
|
|
|
const Elf_Sym *sym;
|
|
|
|
Elf_Shdr *sec;
|
2015-09-09 22:38:51 +00:00
|
|
|
char *sym_buf;
|
|
|
|
|
|
|
|
sym = kexec_purgatory_find_symbol(pi, name);
|
|
|
|
if (!sym)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (sym->st_size != size) {
|
|
|
|
pr_err("symbol %s size mismatch: expected %lu actual %u\n",
|
|
|
|
name, (unsigned long)sym->st_size, size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-04-13 22:36:21 +00:00
|
|
|
sec = pi->sechdrs + sym->st_shndx;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
2018-04-13 22:36:21 +00:00
|
|
|
if (sec->sh_type == SHT_NOBITS) {
|
2015-09-09 22:38:51 +00:00
|
|
|
pr_err("symbol %s is in a bss section. Cannot %s\n", name,
|
|
|
|
get_value ? "get" : "set");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-04-13 22:36:39 +00:00
|
|
|
sym_buf = (char *)pi->purgatory_buf + sec->sh_offset + sym->st_value;
|
2015-09-09 22:38:51 +00:00
|
|
|
|
|
|
|
if (get_value)
|
|
|
|
memcpy((void *)buf, sym_buf, size);
|
|
|
|
else
|
|
|
|
memcpy((void *)sym_buf, buf, size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-07-12 16:15:45 +00:00
|
|
|
#endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */
|