8b68150883
Pull integrity updates from Mimi Zohar: "Bug fixes, code clean up, and new features: - IMA policy rules can be defined in terms of LSM labels, making the IMA policy dependent on LSM policy label changes, in particular LSM label deletions. The new environment, in which IMA-appraisal is being used, frequently updates the LSM policy and permits LSM label deletions. - Prevent an mmap'ed shared file opened for write from also being mmap'ed execute. In the long term, making this and other similar changes at the VFS layer would be preferable. - The IMA per policy rule template format support is needed for a couple of new/proposed features (eg. kexec boot command line measurement, appended signatures, and VFS provided file hashes). - Other than the "boot-aggregate" record in the IMA measuremeent list, all other measurements are of file data. Measuring and storing the kexec boot command line in the IMA measurement list is the first buffer based measurement included in the measurement list" * 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity: integrity: Introduce struct evm_xattr ima: Update MAX_TEMPLATE_NAME_LEN to fit largest reasonable definition KEXEC: Call ima_kexec_cmdline to measure the boot command line args IMA: Define a new template field buf IMA: Define a new hook to measure the kexec boot command line arguments IMA: support for per policy rule template formats integrity: Fix __integrity_init_keyring() section mismatch ima: Use designated initializers for struct ima_event_data ima: use the lsm policy update notifier LSM: switch to blocking policy update notifiers x86/ima: fix the Kconfig dependency for IMA_ARCH_POLICY ima: Make arch_policy_entry static ima: prevent a file already mmap'ed write to be mmap'ed execute x86/ima: check EFI SetupMode too
174 lines
4.0 KiB
C
174 lines
4.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2011 Intel Corporation
|
|
*
|
|
* Author:
|
|
* Dmitry Kasatkin <dmitry.kasatkin@intel.com>
|
|
*/
|
|
|
|
#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
|
|
".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, 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 __init __integrity_init_keyring(const unsigned int id,
|
|
struct key_acl *acl,
|
|
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, acl,
|
|
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;
|
|
} else {
|
|
if (id == INTEGRITY_KEYRING_PLATFORM)
|
|
set_platform_trusted_keys(keyring[id]);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int __init integrity_init_keyring(const unsigned int id)
|
|
{
|
|
struct key_restriction *restriction;
|
|
struct key_acl *acl = &internal_keyring_acl;
|
|
|
|
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;
|
|
acl = &internal_writable_keyring_acl;
|
|
|
|
out:
|
|
return __integrity_init_keyring(id, acl, restriction);
|
|
}
|
|
|
|
static int __init integrity_add_key(const unsigned int id, const void *data,
|
|
off_t size, struct key_acl *acl)
|
|
{
|
|
key_ref_t key;
|
|
int rc = 0;
|
|
|
|
if (!keyring[id])
|
|
return -EINVAL;
|
|
|
|
key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric",
|
|
NULL, data, size, acl ?: &internal_key_acl,
|
|
KEY_ALLOC_NOT_IN_QUOTA);
|
|
if (IS_ERR(key)) {
|
|
rc = PTR_ERR(key);
|
|
pr_err("Problem loading X.509 certificate %d\n", rc);
|
|
} else {
|
|
pr_notice("Loaded X.509 cert '%s'\n",
|
|
key_ref_to_ptr(key)->description);
|
|
key_ref_put(key);
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
int __init integrity_load_x509(const unsigned int id, const char *path)
|
|
{
|
|
void *data;
|
|
loff_t size;
|
|
int rc;
|
|
|
|
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;
|
|
}
|
|
|
|
pr_info("Loading X.509 certificate: %s\n", path);
|
|
rc = integrity_add_key(id, data, size, NULL);
|
|
|
|
vfree(data);
|
|
return rc;
|
|
}
|
|
|
|
int __init integrity_load_cert(const unsigned int id, const char *source,
|
|
const void *data, size_t len, struct key_acl *acl)
|
|
{
|
|
if (!data)
|
|
return -EINVAL;
|
|
|
|
pr_info("Loading X.509 certificate: %s\n", source);
|
|
return integrity_add_key(id, data, len, acl);
|
|
}
|