mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 02:39:48 +00:00
s390/kexec_file: Signature verification prototype
Add kernel signature verification to kexec_file. The verification is based on module signature verification and works with kernel images signed via scripts/sign-file. Signed-off-by: Philipp Rudo <prudo@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
653beba24d
commit
e23a8020ce
8 changed files with 95 additions and 0 deletions
|
@ -553,6 +553,17 @@ config ARCH_HAS_KEXEC_PURGATORY
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
|
|
||||||
|
config KEXEC_VERIFY_SIG
|
||||||
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
|
depends on KEXEC_FILE && SYSTEM_DATA_VERIFICATION
|
||||||
|
help
|
||||||
|
This option makes kernel signature verification mandatory for
|
||||||
|
the kexec_file_load() syscall.
|
||||||
|
|
||||||
|
In addition to that option, you need to enable signature
|
||||||
|
verification for the corresponding kernel image type being
|
||||||
|
loaded in order for this to work.
|
||||||
|
|
||||||
config ARCH_RANDOM
|
config ARCH_RANDOM
|
||||||
def_bool y
|
def_bool y
|
||||||
prompt "s390 architectural random number generation API"
|
prompt "s390 architectural random number generation API"
|
||||||
|
|
|
@ -64,6 +64,7 @@ CONFIG_NUMA=y
|
||||||
CONFIG_PREEMPT=y
|
CONFIG_PREEMPT=y
|
||||||
CONFIG_HZ_100=y
|
CONFIG_HZ_100=y
|
||||||
CONFIG_KEXEC_FILE=y
|
CONFIG_KEXEC_FILE=y
|
||||||
|
CONFIG_KEXEC_VERIFY_SIG=y
|
||||||
CONFIG_EXPOLINE=y
|
CONFIG_EXPOLINE=y
|
||||||
CONFIG_EXPOLINE_AUTO=y
|
CONFIG_EXPOLINE_AUTO=y
|
||||||
CONFIG_MEMORY_HOTPLUG=y
|
CONFIG_MEMORY_HOTPLUG=y
|
||||||
|
|
|
@ -65,6 +65,7 @@ CONFIG_NR_CPUS=512
|
||||||
CONFIG_NUMA=y
|
CONFIG_NUMA=y
|
||||||
CONFIG_HZ_100=y
|
CONFIG_HZ_100=y
|
||||||
CONFIG_KEXEC_FILE=y
|
CONFIG_KEXEC_FILE=y
|
||||||
|
CONFIG_KEXEC_VERIFY_SIG=y
|
||||||
CONFIG_EXPOLINE=y
|
CONFIG_EXPOLINE=y
|
||||||
CONFIG_EXPOLINE_AUTO=y
|
CONFIG_EXPOLINE_AUTO=y
|
||||||
CONFIG_MEMORY_HOTPLUG=y
|
CONFIG_MEMORY_HOTPLUG=y
|
||||||
|
|
|
@ -39,6 +39,7 @@ CONFIG_NR_CPUS=256
|
||||||
CONFIG_NUMA=y
|
CONFIG_NUMA=y
|
||||||
CONFIG_HZ_100=y
|
CONFIG_HZ_100=y
|
||||||
CONFIG_KEXEC_FILE=y
|
CONFIG_KEXEC_FILE=y
|
||||||
|
CONFIG_KEXEC_VERIFY_SIG=y
|
||||||
CONFIG_CRASH_DUMP=y
|
CONFIG_CRASH_DUMP=y
|
||||||
CONFIG_HIBERNATION=y
|
CONFIG_HIBERNATION=y
|
||||||
CONFIG_PM_DEBUG=y
|
CONFIG_PM_DEBUG=y
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct s390_load_data {
|
||||||
size_t memsz;
|
size_t memsz;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int s390_verify_sig(const char *kernel, unsigned long kernel_len);
|
||||||
void *kexec_file_add_components(struct kimage *image,
|
void *kexec_file_add_components(struct kimage *image,
|
||||||
int (*add_kernel)(struct kimage *image,
|
int (*add_kernel)(struct kimage *image,
|
||||||
struct s390_load_data *data));
|
struct s390_load_data *data));
|
||||||
|
|
|
@ -125,4 +125,7 @@ static int s390_elf_probe(const char *buf, unsigned long len)
|
||||||
const struct kexec_file_ops s390_kexec_elf_ops = {
|
const struct kexec_file_ops s390_kexec_elf_ops = {
|
||||||
.probe = s390_elf_probe,
|
.probe = s390_elf_probe,
|
||||||
.load = s390_elf_load,
|
.load = s390_elf_load,
|
||||||
|
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
||||||
|
.verify_sig = s390_verify_sig,
|
||||||
|
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,4 +54,7 @@ static int s390_image_probe(const char *buf, unsigned long len)
|
||||||
const struct kexec_file_ops s390_kexec_image_ops = {
|
const struct kexec_file_ops s390_kexec_image_ops = {
|
||||||
.probe = s390_image_probe,
|
.probe = s390_image_probe,
|
||||||
.load = s390_image_load,
|
.load = s390_image_load,
|
||||||
|
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
||||||
|
.verify_sig = s390_verify_sig,
|
||||||
|
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/elf.h>
|
#include <linux/elf.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/verification.h>
|
||||||
|
#include <asm/ipl.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
|
|
||||||
const struct kexec_file_ops * const kexec_file_loaders[] = {
|
const struct kexec_file_ops * const kexec_file_loaders[] = {
|
||||||
|
@ -17,6 +21,76 @@ const struct kexec_file_ops * const kexec_file_loaders[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
||||||
|
/*
|
||||||
|
* Module signature information block.
|
||||||
|
*
|
||||||
|
* The constituents of the signature section are, in order:
|
||||||
|
*
|
||||||
|
* - Signer's name
|
||||||
|
* - Key identifier
|
||||||
|
* - Signature data
|
||||||
|
* - Information block
|
||||||
|
*/
|
||||||
|
struct module_signature {
|
||||||
|
u8 algo; /* Public-key crypto algorithm [0] */
|
||||||
|
u8 hash; /* Digest algorithm [0] */
|
||||||
|
u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
||||||
|
u8 signer_len; /* Length of signer's name [0] */
|
||||||
|
u8 key_id_len; /* Length of key identifier [0] */
|
||||||
|
u8 __pad[3];
|
||||||
|
__be32 sig_len; /* Length of signature data */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PKEY_ID_PKCS7 2
|
||||||
|
|
||||||
|
int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||||
|
{
|
||||||
|
const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
|
||||||
|
struct module_signature *ms;
|
||||||
|
unsigned long sig_len;
|
||||||
|
|
||||||
|
/* Skip signature verification when not secure IPLed. */
|
||||||
|
if (!ipl_secure_flag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (marker_len > kernel_len)
|
||||||
|
return -EKEYREJECTED;
|
||||||
|
|
||||||
|
if (memcmp(kernel + kernel_len - marker_len, MODULE_SIG_STRING,
|
||||||
|
marker_len))
|
||||||
|
return -EKEYREJECTED;
|
||||||
|
kernel_len -= marker_len;
|
||||||
|
|
||||||
|
ms = (void *)kernel + kernel_len - sizeof(*ms);
|
||||||
|
kernel_len -= sizeof(*ms);
|
||||||
|
|
||||||
|
sig_len = be32_to_cpu(ms->sig_len);
|
||||||
|
if (sig_len >= kernel_len)
|
||||||
|
return -EKEYREJECTED;
|
||||||
|
kernel_len -= sig_len;
|
||||||
|
|
||||||
|
if (ms->id_type != PKEY_ID_PKCS7)
|
||||||
|
return -EKEYREJECTED;
|
||||||
|
|
||||||
|
if (ms->algo != 0 ||
|
||||||
|
ms->hash != 0 ||
|
||||||
|
ms->signer_len != 0 ||
|
||||||
|
ms->key_id_len != 0 ||
|
||||||
|
ms->__pad[0] != 0 ||
|
||||||
|
ms->__pad[1] != 0 ||
|
||||||
|
ms->__pad[2] != 0) {
|
||||||
|
return -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return verify_pkcs7_signature(kernel, kernel_len,
|
||||||
|
kernel + kernel_len, sig_len,
|
||||||
|
VERIFY_USE_PLATFORM_KEYRING,
|
||||||
|
VERIFYING_MODULE_SIGNATURE,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
||||||
|
|
||||||
static int kexec_file_update_purgatory(struct kimage *image,
|
static int kexec_file_update_purgatory(struct kimage *image,
|
||||||
struct s390_load_data *data)
|
struct s390_load_data *data)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue