Skip to content

Commit

Permalink
Merge tag 'x86_kdump_for_v6.0_rc1' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/tip/tip

Pull x86 kdump updates from Borislav Petkov:

 - Add the ability to pass early an RNG seed to the kernel from the boot
   loader

 - Add the ability to pass the IMA measurement of kernel and bootloader
   to the kexec-ed kernel

* tag 'x86_kdump_for_v6.0_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/setup: Use rng seeds from setup_data
  x86/kexec: Carry forward IMA measurement log on kexec
  • Loading branch information
torvalds committed Aug 1, 2022
2 parents 8b70545 + 68b8e97 commit 60ee49f
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 20 deletions.
1 change: 1 addition & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,7 @@ config KEXEC
config KEXEC_FILE
bool "kexec file based system call"
select KEXEC_CORE
select HAVE_IMA_KEXEC if IMA
depends on X86_64
depends on CRYPTO=y
depends on CRYPTO_SHA256=y
Expand Down
15 changes: 12 additions & 3 deletions arch/x86/include/uapi/asm/bootparam.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
#define SETUP_APPLE_PROPERTIES 5
#define SETUP_JAILHOUSE 6
#define SETUP_CC_BLOB 7
#define SETUP_IMA 8
#define SETUP_RNG_SEED 9
#define SETUP_ENUM_MAX SETUP_RNG_SEED

#define SETUP_INDIRECT (1<<31)

/* SETUP_INDIRECT | max(SETUP_*) */
#define SETUP_TYPE_MAX (SETUP_INDIRECT | SETUP_CC_BLOB)
#define SETUP_TYPE_MAX (SETUP_ENUM_MAX | SETUP_INDIRECT)

/* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF
Expand Down Expand Up @@ -172,6 +173,14 @@ struct jailhouse_setup_data {
} __attribute__((packed)) v2;
} __attribute__((packed));

/*
* IMA buffer setup data information from the previous kernel during kexec
*/
struct ima_setup_data {
__u64 addr;
__u64 size;
} __attribute__((packed));

/* The so-called "zeropage" */
struct boot_params {
struct screen_info screen_info; /* 0x000 */
Expand Down
6 changes: 3 additions & 3 deletions arch/x86/kernel/e820.c
Original file line number Diff line number Diff line change
Expand Up @@ -1017,10 +1017,10 @@ void __init e820__reserve_setup_data(void)
e820__range_update(pa_data, sizeof(*data)+data->len, E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);

/*
* SETUP_EFI is supplied by kexec and does not need to be
* reserved.
* SETUP_EFI and SETUP_IMA are supplied by kexec and do not need
* to be reserved.
*/
if (data->type != SETUP_EFI)
if (data->type != SETUP_EFI && data->type != SETUP_IMA)
e820__range_update_kexec(pa_data,
sizeof(*data) + data->len,
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
Expand Down
74 changes: 71 additions & 3 deletions arch/x86/kernel/kexec-bzimage64.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/efi.h>
#include <linux/verification.h>
#include <linux/random.h>

#include <asm/bootparam.h>
#include <asm/setup.h>
Expand Down Expand Up @@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params)
return 0;
}

enum { RNG_SEED_LENGTH = 32 };

static void
setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
unsigned int rng_seed_setup_data_offset)
{
struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
unsigned long setup_data_phys;

if (!rng_is_initialized())
return;

sd->type = SETUP_RNG_SEED;
sd->len = RNG_SEED_LENGTH;
get_random_bytes(sd->data, RNG_SEED_LENGTH);
setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
sd->next = params->hdr.setup_data;
params->hdr.setup_data = setup_data_phys;
}

#ifdef CONFIG_EFI
static int setup_efi_info_memmap(struct boot_params *params,
unsigned long params_load_addr,
Expand Down Expand Up @@ -186,11 +207,38 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr,
}
#endif /* CONFIG_EFI */

static void
setup_ima_state(const struct kimage *image, struct boot_params *params,
unsigned long params_load_addr,
unsigned int ima_setup_data_offset)
{
#ifdef CONFIG_IMA_KEXEC
struct setup_data *sd = (void *)params + ima_setup_data_offset;
unsigned long setup_data_phys;
struct ima_setup_data *ima;

if (!image->ima_buffer_size)
return;

sd->type = SETUP_IMA;
sd->len = sizeof(*ima);

ima = (void *)sd + sizeof(struct setup_data);
ima->addr = image->ima_buffer_addr;
ima->size = image->ima_buffer_size;

/* Add setup data */
setup_data_phys = params_load_addr + ima_setup_data_offset;
sd->next = params->hdr.setup_data;
params->hdr.setup_data = setup_data_phys;
#endif /* CONFIG_IMA_KEXEC */
}

static int
setup_boot_parameters(struct kimage *image, struct boot_params *params,
unsigned long params_load_addr,
unsigned int efi_map_offset, unsigned int efi_map_sz,
unsigned int efi_setup_data_offset)
unsigned int setup_data_offset)
{
unsigned int nr_e820_entries;
unsigned long long mem_k, start, end;
Expand Down Expand Up @@ -245,8 +293,22 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
#ifdef CONFIG_EFI
/* Setup EFI state */
setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz,
efi_setup_data_offset);
setup_data_offset);
setup_data_offset += sizeof(struct setup_data) +
sizeof(struct efi_setup_data);
#endif

if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
/* Setup IMA log buffer state */
setup_ima_state(image, params, params_load_addr,
setup_data_offset);
setup_data_offset += sizeof(struct setup_data) +
sizeof(struct ima_setup_data);
}

/* Setup RNG seed */
setup_rng_seed(params, params_load_addr, setup_data_offset);

/* Setup EDD info */
memcpy(params->eddbuf, boot_params.eddbuf,
EDDMAXNR * sizeof(struct edd_info));
Expand Down Expand Up @@ -401,7 +463,13 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
sizeof(struct setup_data) +
sizeof(struct efi_setup_data);
sizeof(struct efi_setup_data) +
sizeof(struct setup_data) +
RNG_SEED_LENGTH;

if (IS_ENABLED(CONFIG_IMA_KEXEC))
kbuf.bufsz += sizeof(struct setup_data) +
sizeof(struct ima_setup_data);

params = kzalloc(kbuf.bufsz, GFP_KERNEL);
if (!params)
Expand Down
73 changes: 73 additions & 0 deletions arch/x86/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/dma-map-ops.h>
#include <linux/dmi.h>
#include <linux/efi.h>
#include <linux/ima.h>
#include <linux/init_ohci1394_dma.h>
#include <linux/initrd.h>
#include <linux/iscsi_ibft.h>
Expand All @@ -23,6 +24,7 @@
#include <linux/usb/xhci-dbgp.h>
#include <linux/static_call.h>
#include <linux/swiotlb.h>
#include <linux/random.h>

#include <uapi/linux/mount.h>

Expand Down Expand Up @@ -140,6 +142,11 @@ __visible unsigned long mmu_cr4_features __ro_after_init;
__visible unsigned long mmu_cr4_features __ro_after_init = X86_CR4_PAE;
#endif

#ifdef CONFIG_IMA
static phys_addr_t ima_kexec_buffer_phys;
static size_t ima_kexec_buffer_size;
#endif

/* Boot loader ID and version as integers, for the benefit of proc_dointvec */
int bootloader_type, bootloader_version;

Expand Down Expand Up @@ -330,6 +337,60 @@ static void __init reserve_initrd(void)
}
#endif /* CONFIG_BLK_DEV_INITRD */

static void __init add_early_ima_buffer(u64 phys_addr)
{
#ifdef CONFIG_IMA
struct ima_setup_data *data;

data = early_memremap(phys_addr + sizeof(struct setup_data), sizeof(*data));
if (!data) {
pr_warn("setup: failed to memremap ima_setup_data entry\n");
return;
}

if (data->size) {
memblock_reserve(data->addr, data->size);
ima_kexec_buffer_phys = data->addr;
ima_kexec_buffer_size = data->size;
}

early_memunmap(data, sizeof(*data));
#else
pr_warn("Passed IMA kexec data, but CONFIG_IMA not set. Ignoring.\n");
#endif
}

#if defined(CONFIG_HAVE_IMA_KEXEC) && !defined(CONFIG_OF_FLATTREE)
int __init ima_free_kexec_buffer(void)
{
int rc;

if (!ima_kexec_buffer_size)
return -ENOENT;

rc = memblock_phys_free(ima_kexec_buffer_phys,
ima_kexec_buffer_size);
if (rc)
return rc;

ima_kexec_buffer_phys = 0;
ima_kexec_buffer_size = 0;

return 0;
}

int __init ima_get_kexec_buffer(void **addr, size_t *size)
{
if (!ima_kexec_buffer_size)
return -ENOENT;

*addr = __va(ima_kexec_buffer_phys);
*size = ima_kexec_buffer_size;

return 0;
}
#endif

static void __init parse_setup_data(void)
{
struct setup_data *data;
Expand All @@ -355,6 +416,18 @@ static void __init parse_setup_data(void)
case SETUP_EFI:
parse_efi_setup(pa_data, data_len);
break;
case SETUP_IMA:
add_early_ima_buffer(pa_data);
break;
case SETUP_RNG_SEED:
data = early_memremap(pa_data, data_len);
add_bootloader_randomness(data->data, data->len);
/* Zero seed for forward secrecy. */
memzero_explicit(data->data, data->len);
/* Zero length in case we find ourselves back here by accident. */
memzero_explicit(&data->len, sizeof(data->len));
early_memunmap(data, data_len);
break;
default:
break;
}
Expand Down
13 changes: 5 additions & 8 deletions drivers/of/kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Copyright (C) 2016 IBM Corporation
*/

#include <linux/ima.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/memblock.h>
Expand Down Expand Up @@ -115,23 +116,21 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
return 0;
}

#ifdef CONFIG_HAVE_IMA_KEXEC
/**
* ima_get_kexec_buffer - get IMA buffer from the previous kernel
* @addr: On successful return, set to point to the buffer contents.
* @size: On successful return, set to the buffer size.
*
* Return: 0 on success, negative errno on error.
*/
int ima_get_kexec_buffer(void **addr, size_t *size)
int __init ima_get_kexec_buffer(void **addr, size_t *size)
{
int ret, len;
unsigned long tmp_addr;
size_t tmp_size;
const void *prop;

if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
return -ENOTSUPP;

prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
if (!prop)
return -ENOENT;
Expand All @@ -149,16 +148,13 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
/**
* ima_free_kexec_buffer - free memory used by the IMA buffer
*/
int ima_free_kexec_buffer(void)
int __init ima_free_kexec_buffer(void)
{
int ret;
unsigned long addr;
size_t size;
struct property *prop;

if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
return -ENOTSUPP;

prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
if (!prop)
return -ENOENT;
Expand All @@ -173,6 +169,7 @@ int ima_free_kexec_buffer(void)

return memblock_phys_free(addr, size);
}
#endif

/**
* remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
Expand Down
5 changes: 5 additions & 0 deletions include/linux/ima.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ static inline int ima_measure_critical_data(const char *event_label,

#endif /* CONFIG_IMA */

#ifdef CONFIG_HAVE_IMA_KEXEC
int __init ima_free_kexec_buffer(void);
int __init ima_get_kexec_buffer(void **addr, size_t *size);
#endif

#ifdef CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
extern bool arch_ima_get_secureboot(void);
extern const char * const *arch_get_ima_policy(void);
Expand Down
2 changes: 0 additions & 2 deletions include/linux/of.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,6 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
unsigned long initrd_load_addr,
unsigned long initrd_len,
const char *cmdline, size_t extra_fdt_size);
int ima_get_kexec_buffer(void **addr, size_t *size);
int ima_free_kexec_buffer(void);
#else /* CONFIG_OF */

static inline void of_core_init(void)
Expand Down
2 changes: 1 addition & 1 deletion security/integrity/ima/ima_kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void ima_add_kexec_buffer(struct kimage *image)
/*
* Restore the measurement list from the previous kernel.
*/
void ima_load_kexec_buffer(void)
void __init ima_load_kexec_buffer(void)
{
void *kexec_buffer = NULL;
size_t kexec_buffer_size = 0;
Expand Down

0 comments on commit 60ee49f

Please sign in to comment.