mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
9dc92c4517
On secure boot enabled systems, a verified kernel may need to kexec additional kernels. For example, it may be used as a bootloader needing to kexec a target kernel or it may need to kexec a crashdump kernel. In such cases, it may want to verify the signature of the next kernel image. It is further possible that the kernel image is signed with third party keys which are stored as platform or firmware keys in the 'db' variable. The kernel, however, can not directly verify these platform keys, and an administrator may therefore not want to trust them for arbitrary usage. In order to differentiate platform keys from other keys and provide the necessary separation of trust, the kernel needs an additional keyring to store platform keys. This patch creates the new keyring called ".platform" to isolate keys provided by platform from keys by kernel. These keys are used to facilitate signature verification during kexec. Since the scope of this keyring is only the platform/firmware keys, it cannot be updated from userspace. This keyring can be enabled by setting CONFIG_INTEGRITY_PLATFORM_KEYRING. Signed-off-by: Nayna Jain <nayna@linux.ibm.com> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com> Acked-by: Serge Hallyn <serge@hallyn.com> Reviewed-by: James Morris <james.morris@microsoft.com> Reviewed-by: Thiago Jung Bauermann <bauerman@linux.ibm.com> Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
161 lines
3.7 KiB
C
161 lines
3.7 KiB
C
/*
|
|
* Copyright (C) 2011 Intel Corporation
|
|
*
|
|
* Author:
|
|
* Dmitry Kasatkin <dmitry.kasatkin@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 2 of the License.
|
|
*
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/cred.h>
|
|
#include <linux/key-type.h>
|
|
#include <linux/digsig.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <crypto/public_key.h>
|
|
#include <keys/system_keyring.h>
|
|
|
|
#include "integrity.h"
|
|
|
|
static struct key *keyring[INTEGRITY_KEYRING_MAX];
|
|
|
|
static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
|
|
#ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING
|
|
"_evm",
|
|
"_ima",
|
|
#else
|
|
".evm",
|
|
".ima",
|
|
#endif
|
|
"_module",
|
|
".platform",
|
|
};
|
|
|
|
#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
|
|
#define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted
|
|
#else
|
|
#define restrict_link_to_ima restrict_link_by_builtin_trusted
|
|
#endif
|
|
|
|
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
|
const char *digest, int digestlen)
|
|
{
|
|
if (id >= INTEGRITY_KEYRING_MAX || siglen < 2)
|
|
return -EINVAL;
|
|
|
|
if (!keyring[id]) {
|
|
keyring[id] =
|
|
request_key(&key_type_keyring, keyring_name[id], NULL);
|
|
if (IS_ERR(keyring[id])) {
|
|
int err = PTR_ERR(keyring[id]);
|
|
pr_err("no %s keyring: %d\n", keyring_name[id], err);
|
|
keyring[id] = NULL;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
switch (sig[1]) {
|
|
case 1:
|
|
/* v1 API expect signature without xattr type */
|
|
return digsig_verify(keyring[id], sig + 1, siglen - 1,
|
|
digest, digestlen);
|
|
case 2:
|
|
return asymmetric_verify(keyring[id], sig, siglen,
|
|
digest, digestlen);
|
|
}
|
|
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static int __integrity_init_keyring(const unsigned int id, key_perm_t perm,
|
|
struct key_restriction *restriction)
|
|
{
|
|
const struct cred *cred = current_cred();
|
|
int err = 0;
|
|
|
|
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
|
|
KGIDT_INIT(0), cred, perm,
|
|
KEY_ALLOC_NOT_IN_QUOTA,
|
|
restriction, NULL);
|
|
if (IS_ERR(keyring[id])) {
|
|
err = PTR_ERR(keyring[id]);
|
|
pr_info("Can't allocate %s keyring (%d)\n",
|
|
keyring_name[id], err);
|
|
keyring[id] = NULL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int __init integrity_init_keyring(const unsigned int id)
|
|
{
|
|
struct key_restriction *restriction;
|
|
key_perm_t perm;
|
|
|
|
perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW
|
|
| KEY_USR_READ | KEY_USR_SEARCH;
|
|
|
|
if (id == INTEGRITY_KEYRING_PLATFORM) {
|
|
restriction = NULL;
|
|
goto out;
|
|
}
|
|
|
|
if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING))
|
|
return 0;
|
|
|
|
restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
|
|
if (!restriction)
|
|
return -ENOMEM;
|
|
|
|
restriction->check = restrict_link_to_ima;
|
|
perm |= KEY_USR_WRITE;
|
|
|
|
out:
|
|
return __integrity_init_keyring(id, perm, restriction);
|
|
}
|
|
|
|
int __init integrity_load_x509(const unsigned int id, const char *path)
|
|
{
|
|
key_ref_t key;
|
|
void *data;
|
|
loff_t size;
|
|
int rc;
|
|
|
|
if (!keyring[id])
|
|
return -EINVAL;
|
|
|
|
rc = kernel_read_file_from_path(path, &data, &size, 0,
|
|
READING_X509_CERTIFICATE);
|
|
if (rc < 0) {
|
|
pr_err("Unable to open file: %s (%d)", path, rc);
|
|
return rc;
|
|
}
|
|
|
|
key = key_create_or_update(make_key_ref(keyring[id], 1),
|
|
"asymmetric",
|
|
NULL,
|
|
data,
|
|
size,
|
|
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
|
KEY_USR_VIEW | KEY_USR_READ),
|
|
KEY_ALLOC_NOT_IN_QUOTA);
|
|
if (IS_ERR(key)) {
|
|
rc = PTR_ERR(key);
|
|
pr_err("Problem loading X.509 certificate (%d): %s\n",
|
|
rc, path);
|
|
} else {
|
|
pr_notice("Loaded X.509 cert '%s': %s\n",
|
|
key_ref_to_ptr(key)->description, path);
|
|
key_ref_put(key);
|
|
}
|
|
vfree(data);
|
|
return 0;
|
|
}
|