Commit 60ee49fa authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_kdump_for_v6.0_rc1' of git://git.kernel.org/pub/scm/linux/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
parents 8b705452 68b8e971
...@@ -2010,6 +2010,7 @@ config KEXEC ...@@ -2010,6 +2010,7 @@ config KEXEC
config KEXEC_FILE config KEXEC_FILE
bool "kexec file based system call" bool "kexec file based system call"
select KEXEC_CORE select KEXEC_CORE
select HAVE_IMA_KEXEC if IMA
depends on X86_64 depends on X86_64
depends on CRYPTO=y depends on CRYPTO=y
depends on CRYPTO_SHA256=y depends on CRYPTO_SHA256=y
......
...@@ -11,11 +11,12 @@ ...@@ -11,11 +11,12 @@
#define SETUP_APPLE_PROPERTIES 5 #define SETUP_APPLE_PROPERTIES 5
#define SETUP_JAILHOUSE 6 #define SETUP_JAILHOUSE 6
#define SETUP_CC_BLOB 7 #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) #define SETUP_INDIRECT (1<<31)
#define SETUP_TYPE_MAX (SETUP_ENUM_MAX | SETUP_INDIRECT)
/* SETUP_INDIRECT | max(SETUP_*) */
#define SETUP_TYPE_MAX (SETUP_INDIRECT | SETUP_CC_BLOB)
/* ram_size flags */ /* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_IMAGE_START_MASK 0x07FF
...@@ -172,6 +173,14 @@ struct jailhouse_setup_data { ...@@ -172,6 +173,14 @@ struct jailhouse_setup_data {
} __attribute__((packed)) v2; } __attribute__((packed)) v2;
} __attribute__((packed)); } __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" */ /* The so-called "zeropage" */
struct boot_params { struct boot_params {
struct screen_info screen_info; /* 0x000 */ struct screen_info screen_info; /* 0x000 */
......
...@@ -1017,10 +1017,10 @@ void __init e820__reserve_setup_data(void) ...@@ -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); 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 * SETUP_EFI and SETUP_IMA are supplied by kexec and do not need
* reserved. * to be reserved.
*/ */
if (data->type != SETUP_EFI) if (data->type != SETUP_EFI && data->type != SETUP_IMA)
e820__range_update_kexec(pa_data, e820__range_update_kexec(pa_data,
sizeof(*data) + data->len, sizeof(*data) + data->len,
E820_TYPE_RAM, E820_TYPE_RESERVED_KERN); E820_TYPE_RAM, E820_TYPE_RESERVED_KERN);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/verification.h> #include <linux/verification.h>
#include <linux/random.h>
#include <asm/bootparam.h> #include <asm/bootparam.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params) ...@@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params)
return 0; 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 #ifdef CONFIG_EFI
static int setup_efi_info_memmap(struct boot_params *params, static int setup_efi_info_memmap(struct boot_params *params,
unsigned long params_load_addr, unsigned long params_load_addr,
...@@ -186,11 +207,38 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr, ...@@ -186,11 +207,38 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr,
} }
#endif /* CONFIG_EFI */ #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 static int
setup_boot_parameters(struct kimage *image, struct boot_params *params, setup_boot_parameters(struct kimage *image, struct boot_params *params,
unsigned long params_load_addr, unsigned long params_load_addr,
unsigned int efi_map_offset, unsigned int efi_map_sz, 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 int nr_e820_entries;
unsigned long long mem_k, start, end; unsigned long long mem_k, start, end;
...@@ -245,8 +293,22 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, ...@@ -245,8 +293,22 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
#ifdef CONFIG_EFI #ifdef CONFIG_EFI
/* Setup EFI state */ /* Setup EFI state */
setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz, 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 #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 */ /* Setup EDD info */
memcpy(params->eddbuf, boot_params.eddbuf, memcpy(params->eddbuf, boot_params.eddbuf,
EDDMAXNR * sizeof(struct edd_info)); EDDMAXNR * sizeof(struct edd_info));
...@@ -401,7 +463,13 @@ static void *bzImage64_load(struct kimage *image, char *kernel, ...@@ -401,7 +463,13 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
params_cmdline_sz = ALIGN(params_cmdline_sz, 16); params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) + kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
sizeof(struct setup_data) + 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); params = kzalloc(kbuf.bufsz, GFP_KERNEL);
if (!params) if (!params)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/dma-map-ops.h> #include <linux/dma-map-ops.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/ima.h>
#include <linux/init_ohci1394_dma.h> #include <linux/init_ohci1394_dma.h>
#include <linux/initrd.h> #include <linux/initrd.h>
#include <linux/iscsi_ibft.h> #include <linux/iscsi_ibft.h>
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#include <linux/usb/xhci-dbgp.h> #include <linux/usb/xhci-dbgp.h>
#include <linux/static_call.h> #include <linux/static_call.h>
#include <linux/swiotlb.h> #include <linux/swiotlb.h>
#include <linux/random.h>
#include <uapi/linux/mount.h> #include <uapi/linux/mount.h>
...@@ -140,6 +142,11 @@ __visible unsigned long mmu_cr4_features __ro_after_init; ...@@ -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; __visible unsigned long mmu_cr4_features __ro_after_init = X86_CR4_PAE;
#endif #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 */ /* Boot loader ID and version as integers, for the benefit of proc_dointvec */
int bootloader_type, bootloader_version; int bootloader_type, bootloader_version;
...@@ -330,6 +337,60 @@ static void __init reserve_initrd(void) ...@@ -330,6 +337,60 @@ static void __init reserve_initrd(void)
} }
#endif /* CONFIG_BLK_DEV_INITRD */ #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) static void __init parse_setup_data(void)
{ {
struct setup_data *data; struct setup_data *data;
...@@ -355,6 +416,18 @@ static void __init parse_setup_data(void) ...@@ -355,6 +416,18 @@ static void __init parse_setup_data(void)
case SETUP_EFI: case SETUP_EFI:
parse_efi_setup(pa_data, data_len); parse_efi_setup(pa_data, data_len);
break; 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: default:
break; break;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* Copyright (C) 2016 IBM Corporation * Copyright (C) 2016 IBM Corporation
*/ */
#include <linux/ima.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/memblock.h> #include <linux/memblock.h>
...@@ -115,6 +116,7 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, ...@@ -115,6 +116,7 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
return 0; return 0;
} }
#ifdef CONFIG_HAVE_IMA_KEXEC
/** /**
* ima_get_kexec_buffer - get IMA buffer from the previous kernel * ima_get_kexec_buffer - get IMA buffer from the previous kernel
* @addr: On successful return, set to point to the buffer contents. * @addr: On successful return, set to point to the buffer contents.
...@@ -122,16 +124,13 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, ...@@ -122,16 +124,13 @@ static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
* *
* Return: 0 on success, negative errno on error. * 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; int ret, len;
unsigned long tmp_addr; unsigned long tmp_addr;
size_t tmp_size; size_t tmp_size;
const void *prop; const void *prop;
if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
return -ENOTSUPP;
prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len); prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
if (!prop) if (!prop)
return -ENOENT; return -ENOENT;
...@@ -149,16 +148,13 @@ int ima_get_kexec_buffer(void **addr, size_t *size) ...@@ -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 * 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; int ret;
unsigned long addr; unsigned long addr;
size_t size; size_t size;
struct property *prop; struct property *prop;
if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC))
return -ENOTSUPP;
prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL); prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
if (!prop) if (!prop)
return -ENOENT; return -ENOENT;
...@@ -173,6 +169,7 @@ int ima_free_kexec_buffer(void) ...@@ -173,6 +169,7 @@ int ima_free_kexec_buffer(void)
return memblock_phys_free(addr, size); return memblock_phys_free(addr, size);
} }
#endif
/** /**
* remove_ima_buffer - remove the IMA buffer property and reservation from @fdt * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
......
...@@ -140,6 +140,11 @@ static inline int ima_measure_critical_data(const char *event_label, ...@@ -140,6 +140,11 @@ static inline int ima_measure_critical_data(const char *event_label,
#endif /* CONFIG_IMA */ #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 #ifdef CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
extern bool arch_ima_get_secureboot(void); extern bool arch_ima_get_secureboot(void);
extern const char * const *arch_get_ima_policy(void); extern const char * const *arch_get_ima_policy(void);
......
...@@ -441,8 +441,6 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image, ...@@ -441,8 +441,6 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
unsigned long initrd_load_addr, unsigned long initrd_load_addr,
unsigned long initrd_len, unsigned long initrd_len,
const char *cmdline, size_t extra_fdt_size); 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 */ #else /* CONFIG_OF */
static inline void of_core_init(void) static inline void of_core_init(void)
......
...@@ -137,7 +137,7 @@ void ima_add_kexec_buffer(struct kimage *image) ...@@ -137,7 +137,7 @@ void ima_add_kexec_buffer(struct kimage *image)
/* /*
* Restore the measurement list from the previous kernel. * 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; void *kexec_buffer = NULL;
size_t kexec_buffer_size = 0; size_t kexec_buffer_size = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment