Merge tag 'integrity-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity

Pull integrity updates from Mimi Zohar:
 "There are two main changes, one feature removal, some code cleanup,
  and a number of bug fixes.

  Main changes:
   - Detecting secure boot mode was limited to IMA. Make detecting
     secure boot mode accessible to EVM and other LSMs
   - IMA sigv3 support was limited to fsverity. Add IMA sigv3 support
     for IMA regular file hashes and EVM portable signatures

  Remove:
   - Remove IMA support for asychronous hash calculation originally
     added for hardware acceleration

  Cleanup:
   - Remove unnecessary Kconfig CONFIG_MODULE_SIG and CONFIG_KEXEC_SIG
     tests
   - Add descriptions of the IMA atomic flags

  Bug fixes:
   - Like IMA, properly limit EVM "fix" mode
   - Define and call evm_fix_hmac() to update security.evm
   - Fallback to using i_version to detect file change for filesystems
     that do not support STATX_CHANGE_COOKIE
   - Address missing kernel support for configured (new) TPM hash
     algorithms
   - Add missing crypto_shash_final() return value"

* tag 'integrity-v7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  evm: Enforce signatures version 3 with new EVM policy 'bit 3'
  integrity: Allow sigv3 verification on EVM_XATTR_PORTABLE_DIGSIG
  ima: add support to require IMA sigv3 signatures
  ima: add regular file data hash signature version 3 support
  ima: Define asymmetric_verify_v3() to verify IMA sigv3 signatures
  ima: remove buggy support for asynchronous hashes
  integrity: Eliminate weak definition of arch_get_secureboot()
  ima: Add code comments to explain IMA iint cache atomic_flags
  ima_fs: Correctly create securityfs files for unsupported hash algos
  ima: check return value of crypto_shash_final() in boot aggregate
  ima: Define and use a digest_size field in the ima_algo_desc structure
  powerpc/ima: Drop unnecessary check for CONFIG_MODULE_SIG
  ima: efi: Drop unnecessary check for CONFIG_MODULE_SIG/CONFIG_KEXEC_SIG
  ima: fallback to using i_version to detect file change
  evm: fix security.evm for a file with IMA signature
  s390: Drop unnecessary CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
  evm: Don't enable fix mode when secure boot is enabled
  integrity: Make arch_ima_get_secureboot integrity-wide
This commit is contained in:
Linus Torvalds
2026-04-17 15:42:01 -07:00
33 changed files with 400 additions and 588 deletions

View File

@@ -18,6 +18,7 @@ integrity-$(CONFIG_LOAD_IPL_KEYS) += platform_certs/load_ipl_s390.o
integrity-$(CONFIG_LOAD_PPC_KEYS) += platform_certs/efi_parser.o \
platform_certs/load_powerpc.o \
platform_certs/keyring_handler.o
integrity-$(CONFIG_EFI) += efi_secureboot.o
# The relative order of the 'ima' and 'evm' LSMs depends on the order below.
obj-$(CONFIG_IMA) += ima/
obj-$(CONFIG_EVM) += evm/

View File

@@ -59,7 +59,7 @@ static struct key *integrity_keyring_from_id(const unsigned int id)
}
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen)
const char *digest, int digestlen, u8 algo)
{
struct key *keyring;
@@ -76,9 +76,11 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return digsig_verify(keyring, sig + 1, siglen - 1, digest,
digestlen);
case 2: /* regular file data hash based signature */
case 3: /* struct ima_file_id data based signature */
return asymmetric_verify(keyring, sig, siglen, digest,
digestlen);
digestlen);
case 3: /* struct ima_file_id data based signature */
return asymmetric_verify_v3(keyring, sig, siglen, digest,
digestlen, algo);
}
return -EOPNOTSUPP;

View File

@@ -131,3 +131,62 @@ out:
pr_debug("%s() = %d\n", __func__, ret);
return ret;
}
/*
* calc_file_id_hash - calculate the hash of the ima_file_id struct data
* @type: xattr type [enum evm_ima_xattr_type]
* @algo: hash algorithm [enum hash_algo]
* @digest: pointer to the digest to be hashed
* @hash: (out) pointer to the hash
*
* IMA signature version 3 disambiguates the data that is signed by
* indirectly signing the hash of the ima_file_id structure data.
*
* Return 0 on success, error code otherwise.
*/
static int calc_file_id_hash(enum evm_ima_xattr_type type,
enum hash_algo algo, const u8 *digest,
struct ima_max_digest_data *hash)
{
struct ima_file_id file_id = {.hash_type = type, .hash_algorithm = algo};
size_t digest_size = hash_digest_size[algo];
struct crypto_shash *tfm;
size_t file_id_size;
int rc;
if (type != IMA_VERITY_DIGSIG && type != EVM_IMA_XATTR_DIGSIG &&
type != EVM_XATTR_PORTABLE_DIGSIG)
return -EINVAL;
tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
memcpy(file_id.hash, digest, digest_size);
/* Calculate the ima_file_id struct hash on the portion used. */
file_id_size = sizeof(file_id) - (HASH_MAX_DIGESTSIZE - digest_size);
hash->hdr.algo = algo;
hash->hdr.length = digest_size;
rc = crypto_shash_tfm_digest(tfm, (const u8 *)&file_id, file_id_size,
hash->digest);
crypto_free_shash(tfm);
return rc;
}
int asymmetric_verify_v3(struct key *keyring, const char *sig, int siglen,
const char *data, int datalen, u8 algo)
{
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
struct ima_max_digest_data hash;
int rc;
rc = calc_file_id_hash(hdr->type, algo, data, &hash);
if (rc)
return -EINVAL;
return asymmetric_verify(keyring, sig, siglen, hash.digest,
hash.hdr.length);
}

View File

@@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-1.0+
/*
* Copyright (C) 2018 IBM Corporation
*/
#include <linux/efi.h>
#include <linux/secure_boot.h>
#include <asm/efi.h>
#ifndef arch_efi_boot_mode
#define arch_efi_boot_mode efi_secureboot_mode_unset
#endif
static enum efi_secureboot_mode get_sb_mode(void)
{
enum efi_secureboot_mode mode;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
pr_info("integrity: secureboot mode unknown, no efi\n");
return efi_secureboot_mode_unknown;
}
mode = efi_get_secureboot_mode(efi.get_variable);
if (mode == efi_secureboot_mode_disabled)
pr_info("integrity: secureboot mode disabled\n");
else if (mode == efi_secureboot_mode_unknown)
pr_info("integrity: secureboot mode unknown\n");
else
pr_info("integrity: secureboot mode enabled\n");
return mode;
}
/*
* Query secure boot status
*
* Note don't call this function too early e.g. in __setup hook otherwise the
* kernel may hang when calling efi_get_secureboot_mode.
*
*/
bool arch_get_secureboot(void)
{
static enum efi_secureboot_mode sb_mode;
static bool initialized;
if (!initialized && efi_enabled(EFI_BOOT)) {
sb_mode = arch_efi_boot_mode;
if (sb_mode == efi_secureboot_mode_unset)
sb_mode = get_sb_mode();
initialized = true;
}
if (sb_mode == efi_secureboot_mode_enabled)
return true;
else
return false;
}

View File

@@ -20,11 +20,12 @@
#define EVM_INIT_HMAC 0x0001
#define EVM_INIT_X509 0x0002
#define EVM_ALLOW_METADATA_WRITES 0x0004
#define EVM_SIGV3_REQUIRED 0x0008
#define EVM_SETUP_COMPLETE 0x80000000 /* userland has signaled key load */
#define EVM_KEY_MASK (EVM_INIT_HMAC | EVM_INIT_X509)
#define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP_COMPLETE | \
EVM_ALLOW_METADATA_WRITES)
EVM_ALLOW_METADATA_WRITES | EVM_SIGV3_REQUIRED)
struct xattr_list {
struct list_head list;

View File

@@ -72,17 +72,25 @@ static struct xattr_list evm_config_default_xattrnames[] = {
LIST_HEAD(evm_config_xattrnames);
static int evm_fixmode __ro_after_init;
static int __init evm_set_fixmode(char *str)
{
if (strncmp(str, "fix", 3) == 0)
evm_fixmode = 1;
else
pr_err("invalid \"%s\" mode", str);
static char *evm_cmdline __initdata;
core_param(evm, evm_cmdline, charp, 0);
return 1;
static int evm_fixmode __ro_after_init;
static void __init evm_set_fixmode(void)
{
if (!evm_cmdline)
return;
if (strncmp(evm_cmdline, "fix", 3) == 0) {
if (arch_get_secureboot()) {
pr_info("Secure boot enabled: ignoring evm=fix");
return;
}
evm_fixmode = 1;
} else {
pr_err("invalid \"%s\" mode", evm_cmdline);
}
}
__setup("evm=", evm_set_fixmode);
static void __init evm_init_config(void)
{
@@ -128,6 +136,14 @@ static bool evm_hmac_disabled(void)
return true;
}
static bool evm_sigv3_required(void)
{
if (evm_initialized & EVM_SIGV3_REQUIRED)
return true;
return false;
}
static int evm_find_protected_xattrs(struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
@@ -250,6 +266,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
}
hdr = (struct signature_v2_hdr *)xattr_data;
if (evm_sigv3_required() && hdr->version != 3) {
evm_status = INTEGRITY_FAIL;
goto out;
}
digest.hdr.algo = hdr->hash_algo;
rc = evm_calc_hash(dentry, xattr_name, xattr_value,
xattr_value_len, xattr_data->type, &digest,
@@ -258,7 +280,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
break;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
(const char *)xattr_data, xattr_len,
digest.digest, digest.hdr.length);
digest.digest, digest.hdr.length,
digest.hdr.algo);
if (!rc) {
if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) {
if (iint)
@@ -787,6 +810,34 @@ bool evm_revalidate_status(const char *xattr_name)
return true;
}
/**
* evm_fix_hmac - Calculate the HMAC and add it to security.evm for fix mode
* @dentry: pointer to the affected dentry which doesn't yet have security.evm
* xattr
* @xattr_name: pointer to the affected extended attribute name
* @xattr_value: pointer to the new extended attribute value
* @xattr_value_len: pointer to the new extended attribute value length
*
* Expects to be called with i_mutex locked.
*
* Return: 0 on success, -EPERM/-ENOMEM/-EOPNOTSUPP on failure
*/
int evm_fix_hmac(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
if (!evm_fixmode || !evm_revalidate_status((xattr_name)))
return -EPERM;
if (!(evm_initialized & EVM_INIT_HMAC))
return -EPERM;
if (is_unsupported_hmac_fs(dentry))
return -EOPNOTSUPP;
return evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
}
/**
* evm_inode_post_setxattr - update 'security.evm' to reflect the changes
* @dentry: pointer to the affected dentry
@@ -1119,6 +1170,8 @@ static int __init init_evm(void)
evm_init_config();
evm_set_fixmode();
error = integrity_init_keyring(INTEGRITY_KEYRING_EVM);
if (error)
goto error;

View File

@@ -53,6 +53,7 @@ extern atomic_t ima_setxattr_allowed_hash_algorithms;
struct ima_algo_desc {
struct crypto_shash *tfm;
enum hash_algo algo;
unsigned int digest_size;
};
/* set during initialization */
@@ -144,6 +145,7 @@ struct ima_kexec_hdr {
#define IMA_DIGSIG_REQUIRED 0x01000000
#define IMA_PERMIT_DIRECTIO 0x02000000
#define IMA_NEW_FILE 0x04000000
#define IMA_SIGV3_REQUIRED 0x08000000
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
#define IMA_MODSIG_ALLOWED 0x20000000
#define IMA_CHECK_BLACKLIST 0x40000000
@@ -176,7 +178,32 @@ struct ima_kexec_hdr {
IMA_BPRM_APPRAISED | IMA_READ_APPRAISED | \
IMA_CREDS_APPRAISED)
/* IMA iint cache atomic_flags */
/*
* IMA iint cache atomic_flags
*
* IMA_CHANGE_ATTR - indicates that chATTR() was called (chmod, chown, chgrp)
* and file attributes have changed. On file open, it causes IMA to clear
* iint->flags to re-evaluate policy and perform IMA functions again.
*
* IMA_CHANGE_XATTR - indicates that setxattr or removexattr was called and
* extended attributes have changed. On file open, it causes IMA to clear
* iint->flags IMA_DONE_MASK to re-appraise.
*
* IMA_UPDATE_XATTR - indicates that security.ima needs to be updated. It is
* cleared if file policy changes and no update is needed.
*
* IMA_DIGSIG - indicates that file security.ima has signature and file
* security.ima must not update on file close.
*
* IMA_MAY_EMIT_TOMTOU - indicates to add Time-of-Measure-Time-of-Use (ToMToU)
* integrity violation (a file that is already opened for read is opened for
* write) to the measurement list and to also emit an audit message.
*
* IMA_EMITTED_OPENWRITERS - indicates to add open-writers integrity violation
* (a file that is already opened for write is opened for read) to the
* measurement list and to also emit an audit message.
*
*/
#define IMA_CHANGE_XATTR 0
#define IMA_UPDATE_XATTR 1
#define IMA_CHANGE_ATTR 2

View File

@@ -269,15 +269,20 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
goto out;
/*
* Detecting file change is based on i_version. On filesystems
* which do not support i_version, support was originally limited
* to an initial measurement/appraisal/audit, but was modified to
* assume the file changed.
* Detect file change based on STATX_CHANGE_COOKIE, when supported,
* and fallback to detecting file change based on i_version.
*
* On filesystems which did not support i_version, support was
* originally limited to an initial measurement/appraisal/audit,
* but was later modified to assume the file changed.
*/
result = vfs_getattr_nosec(&file->f_path, &stat, STATX_CHANGE_COOKIE,
AT_STATX_SYNC_AS_STAT);
if (!result && (stat.result_mask & STATX_CHANGE_COOKIE))
i_version = stat.change_cookie;
else if (IS_I_VERSION(real_inode))
i_version = inode_peek_iversion(real_inode);
hash.hdr.algo = algo;
hash.hdr.length = hash_digest_size[algo];

View File

@@ -27,7 +27,7 @@ core_param(ima_appraise, ima_appraise_cmdline_default, charp, 0);
void __init ima_appraise_parse_cmdline(void)
{
const char *str = ima_appraise_cmdline_default;
bool sb_state = arch_ima_get_secureboot();
bool sb_state = arch_get_secureboot();
int appraisal_state = ima_appraise;
if (!str)
@@ -234,40 +234,6 @@ int ima_read_xattr(struct dentry *dentry,
return ret;
}
/*
* calc_file_id_hash - calculate the hash of the ima_file_id struct data
* @type: xattr type [enum evm_ima_xattr_type]
* @algo: hash algorithm [enum hash_algo]
* @digest: pointer to the digest to be hashed
* @hash: (out) pointer to the hash
*
* IMA signature version 3 disambiguates the data that is signed by
* indirectly signing the hash of the ima_file_id structure data.
*
* Signing the ima_file_id struct is currently only supported for
* IMA_VERITY_DIGSIG type xattrs.
*
* Return 0 on success, error code otherwise.
*/
static int calc_file_id_hash(enum evm_ima_xattr_type type,
enum hash_algo algo, const u8 *digest,
struct ima_digest_data *hash)
{
struct ima_file_id file_id = {
.hash_type = IMA_VERITY_DIGSIG, .hash_algorithm = algo};
unsigned int unused = HASH_MAX_DIGESTSIZE - hash_digest_size[algo];
if (type != IMA_VERITY_DIGSIG)
return -EINVAL;
memcpy(file_id.hash, digest, hash_digest_size[algo]);
hash->algo = algo;
hash->length = hash_digest_size[algo];
return ima_calc_buffer_hash(&file_id, sizeof(file_id) - unused, hash);
}
/*
* xattr_verify - verify xattr digest or signature
*
@@ -279,7 +245,6 @@ static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
struct evm_ima_xattr_data *xattr_value, int xattr_len,
enum integrity_status *status, const char **cause)
{
struct ima_max_digest_data hash;
struct signature_v2_hdr *sig;
int rc = -EINVAL, hash_start = 0;
int mask;
@@ -332,16 +297,24 @@ static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
}
sig = (typeof(sig))xattr_value;
if (sig->version >= 3) {
if (sig->version > 3) {
*cause = "invalid-signature-version";
*status = INTEGRITY_FAIL;
break;
}
if ((iint->flags & IMA_SIGV3_REQUIRED) && sig->version != 3) {
*cause = "IMA-sigv3-required";
*status = INTEGRITY_FAIL;
break;
}
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
iint->ima_hash->length,
iint->ima_hash->algo);
if (rc == -EOPNOTSUPP) {
*status = INTEGRITY_UNKNOWN;
break;
@@ -352,7 +325,9 @@ static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
(const char *)xattr_value,
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length);
iint->ima_hash->length,
iint->ima_hash->algo);
if (rc) {
*cause = "invalid-signature";
*status = INTEGRITY_FAIL;
@@ -378,21 +353,16 @@ static int xattr_verify(enum ima_hooks func, struct ima_iint_cache *iint,
break;
}
rc = calc_file_id_hash(IMA_VERITY_DIGSIG, iint->ima_hash->algo,
iint->ima_hash->digest,
container_of(&hash.hdr,
struct ima_digest_data, hdr));
if (rc) {
*cause = "sigv3-hashing-error";
*status = INTEGRITY_FAIL;
break;
}
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value,
xattr_len, hash.digest,
hash.hdr.length);
if (rc) {
xattr_len,
iint->ima_hash->digest,
iint->ima_hash->length,
iint->ima_hash->algo);
if (rc == -EOPNOTSUPP) {
*status = INTEGRITY_UNKNOWN;
break;
} else if (rc) {
*cause = "invalid-verity-signature";
*status = INTEGRITY_FAIL;
} else {
@@ -591,6 +561,11 @@ out:
xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
if (!ima_fix_xattr(dentry, iint))
status = INTEGRITY_PASS;
} else if (status == INTEGRITY_NOLABEL) {
if (!evm_fix_hmac(dentry, XATTR_NAME_IMA,
(const char *)xattr_value,
xattr_len))
status = INTEGRITY_PASS;
}
/*

View File

@@ -11,51 +11,15 @@
*/
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/ratelimit.h>
#include <linux/file.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <crypto/hash.h>
#include "ima.h"
/* minimum file size for ahash use */
static unsigned long ima_ahash_minsize;
module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644);
MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use");
/* default is 0 - 1 page. */
static int ima_maxorder;
static unsigned int ima_bufsize = PAGE_SIZE;
static int param_set_bufsize(const char *val, const struct kernel_param *kp)
{
unsigned long long size;
int order;
size = memparse(val, NULL);
order = get_order(size);
if (order > MAX_PAGE_ORDER)
return -EINVAL;
ima_maxorder = order;
ima_bufsize = PAGE_SIZE << order;
return 0;
}
static const struct kernel_param_ops param_ops_bufsize = {
.set = param_set_bufsize,
.get = param_get_uint,
};
#define param_check_bufsize(name, p) __param_check(name, p, unsigned int)
module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644);
MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
static struct crypto_shash *ima_shash_tfm;
static struct crypto_ahash *ima_ahash_tfm;
int ima_sha1_idx __ro_after_init;
int ima_hash_algo_idx __ro_after_init;
@@ -109,6 +73,7 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
int __init ima_init_crypto(void)
{
unsigned int digest_size;
enum hash_algo algo;
long rc;
int i;
@@ -147,7 +112,9 @@ int __init ima_init_crypto(void)
for (i = 0; i < NR_BANKS(ima_tpm_chip); i++) {
algo = ima_tpm_chip->allocated_banks[i].crypto_id;
digest_size = ima_tpm_chip->allocated_banks[i].digest_size;
ima_algo_array[i].algo = algo;
ima_algo_array[i].digest_size = digest_size;
/* unknown TPM algorithm */
if (algo == HASH_ALGO__LAST)
@@ -183,12 +150,15 @@ int __init ima_init_crypto(void)
}
ima_algo_array[ima_sha1_idx].algo = HASH_ALGO_SHA1;
ima_algo_array[ima_sha1_idx].digest_size = SHA1_DIGEST_SIZE;
}
if (ima_hash_algo_idx >= NR_BANKS(ima_tpm_chip) &&
ima_hash_algo_idx != ima_sha1_idx) {
digest_size = hash_digest_size[ima_hash_algo];
ima_algo_array[ima_hash_algo_idx].tfm = ima_shash_tfm;
ima_algo_array[ima_hash_algo_idx].algo = ima_hash_algo;
ima_algo_array[ima_hash_algo_idx].digest_size = digest_size;
}
return 0;
@@ -220,234 +190,6 @@ static void ima_free_tfm(struct crypto_shash *tfm)
crypto_free_shash(tfm);
}
/**
* ima_alloc_pages() - Allocate contiguous pages.
* @max_size: Maximum amount of memory to allocate.
* @allocated_size: Returned size of actual allocation.
* @last_warn: Should the min_size allocation warn or not.
*
* Tries to do opportunistic allocation for memory first trying to allocate
* max_size amount of memory and then splitting that until zero order is
* reached. Allocation is tried without generating allocation warnings unless
* last_warn is set. Last_warn set affects only last allocation of zero order.
*
* By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL)
*
* Return pointer to allocated memory, or NULL on failure.
*/
static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size,
int last_warn)
{
void *ptr;
int order = ima_maxorder;
gfp_t gfp_mask = __GFP_RECLAIM | __GFP_NOWARN | __GFP_NORETRY;
if (order)
order = min(get_order(max_size), order);
for (; order; order--) {
ptr = (void *)__get_free_pages(gfp_mask, order);
if (ptr) {
*allocated_size = PAGE_SIZE << order;
return ptr;
}
}
/* order is zero - one page */
gfp_mask = GFP_KERNEL;
if (!last_warn)
gfp_mask |= __GFP_NOWARN;
ptr = (void *)__get_free_pages(gfp_mask, 0);
if (ptr) {
*allocated_size = PAGE_SIZE;
return ptr;
}
*allocated_size = 0;
return NULL;
}
/**
* ima_free_pages() - Free pages allocated by ima_alloc_pages().
* @ptr: Pointer to allocated pages.
* @size: Size of allocated buffer.
*/
static void ima_free_pages(void *ptr, size_t size)
{
if (!ptr)
return;
free_pages((unsigned long)ptr, get_order(size));
}
static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
{
struct crypto_ahash *tfm = ima_ahash_tfm;
int rc;
if (algo < 0 || algo >= HASH_ALGO__LAST)
algo = ima_hash_algo;
if (algo != ima_hash_algo || !tfm) {
tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
if (!IS_ERR(tfm)) {
if (algo == ima_hash_algo)
ima_ahash_tfm = tfm;
} else {
rc = PTR_ERR(tfm);
pr_err("Can not allocate %s (reason: %d)\n",
hash_algo_name[algo], rc);
}
}
return tfm;
}
static void ima_free_atfm(struct crypto_ahash *tfm)
{
if (tfm != ima_ahash_tfm)
crypto_free_ahash(tfm);
}
static inline int ahash_wait(int err, struct crypto_wait *wait)
{
err = crypto_wait_req(err, wait);
if (err)
pr_crit_ratelimited("ahash calculation failed: err: %d\n", err);
return err;
}
static int ima_calc_file_hash_atfm(struct file *file,
struct ima_digest_data *hash,
struct crypto_ahash *tfm)
{
loff_t i_size, offset;
char *rbuf[2] = { NULL, };
int rc, rbuf_len, active = 0, ahash_rc = 0;
struct ahash_request *req;
struct scatterlist sg[1];
struct crypto_wait wait;
size_t rbuf_size[2];
hash->length = crypto_ahash_digestsize(tfm);
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req)
return -ENOMEM;
crypto_init_wait(&wait);
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait);
rc = ahash_wait(crypto_ahash_init(req), &wait);
if (rc)
goto out1;
i_size = i_size_read(file_inode(file));
if (i_size == 0)
goto out2;
/*
* Try to allocate maximum size of memory.
* Fail if even a single page cannot be allocated.
*/
rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1);
if (!rbuf[0]) {
rc = -ENOMEM;
goto out1;
}
/* Only allocate one buffer if that is enough. */
if (i_size > rbuf_size[0]) {
/*
* Try to allocate secondary buffer. If that fails fallback to
* using single buffering. Use previous memory allocation size
* as baseline for possible allocation size.
*/
rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0],
&rbuf_size[1], 0);
}
for (offset = 0; offset < i_size; offset += rbuf_len) {
if (!rbuf[1] && offset) {
/* Not using two buffers, and it is not the first
* read/request, wait for the completion of the
* previous ahash_update() request.
*/
rc = ahash_wait(ahash_rc, &wait);
if (rc)
goto out3;
}
/* read buffer */
rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
rc = integrity_kernel_read(file, offset, rbuf[active],
rbuf_len);
if (rc != rbuf_len) {
if (rc >= 0)
rc = -EINVAL;
/*
* Forward current rc, do not overwrite with return value
* from ahash_wait()
*/
ahash_wait(ahash_rc, &wait);
goto out3;
}
if (rbuf[1] && offset) {
/* Using two buffers, and it is not the first
* read/request, wait for the completion of the
* previous ahash_update() request.
*/
rc = ahash_wait(ahash_rc, &wait);
if (rc)
goto out3;
}
sg_init_one(&sg[0], rbuf[active], rbuf_len);
ahash_request_set_crypt(req, sg, NULL, rbuf_len);
ahash_rc = crypto_ahash_update(req);
if (rbuf[1])
active = !active; /* swap buffers, if we use two */
}
/* wait for the last update request to complete */
rc = ahash_wait(ahash_rc, &wait);
out3:
ima_free_pages(rbuf[0], rbuf_size[0]);
ima_free_pages(rbuf[1], rbuf_size[1]);
out2:
if (!rc) {
ahash_request_set_crypt(req, NULL, hash->digest, 0);
rc = ahash_wait(crypto_ahash_final(req), &wait);
}
out1:
ahash_request_free(req);
return rc;
}
static int ima_calc_file_ahash(struct file *file, struct ima_digest_data *hash)
{
struct crypto_ahash *tfm;
int rc;
tfm = ima_alloc_atfm(hash->algo);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
rc = ima_calc_file_hash_atfm(file, hash, tfm);
ima_free_atfm(tfm);
return rc;
}
static int ima_calc_file_hash_tfm(struct file *file,
struct ima_digest_data *hash,
struct crypto_shash *tfm)
@@ -499,41 +241,15 @@ out:
return rc;
}
static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash)
{
struct crypto_shash *tfm;
int rc;
tfm = ima_alloc_tfm(hash->algo);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
rc = ima_calc_file_hash_tfm(file, hash, tfm);
ima_free_tfm(tfm);
return rc;
}
/*
* ima_calc_file_hash - calculate file hash
*
* Asynchronous hash (ahash) allows using HW acceleration for calculating
* a hash. ahash performance varies for different data sizes on different
* crypto accelerators. shash performance might be better for smaller files.
* The 'ima.ahash_minsize' module parameter allows specifying the best
* minimum file size for using ahash on the system.
*
* If the ima.ahash_minsize parameter is not specified, this function uses
* shash for the hash calculation. If ahash fails, it falls back to using
* shash.
*/
int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
{
loff_t i_size;
int rc;
struct file *f = file;
bool new_file_instance = false;
struct crypto_shash *tfm;
/*
* For consistency, fail file's opened with the O_DIRECT flag on
@@ -557,16 +273,13 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
new_file_instance = true;
}
i_size = i_size_read(file_inode(f));
if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
rc = ima_calc_file_ahash(f, hash);
if (!rc)
goto out;
tfm = ima_alloc_tfm(hash->algo);
if (IS_ERR(tfm)) {
rc = PTR_ERR(tfm);
} else {
rc = ima_calc_file_hash_tfm(f, hash, tfm);
ima_free_tfm(tfm);
}
rc = ima_calc_file_shash(f, hash);
out:
if (new_file_instance)
fput(f);
return rc;
@@ -655,63 +368,6 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
return rc;
}
static int calc_buffer_ahash_atfm(const void *buf, loff_t len,
struct ima_digest_data *hash,
struct crypto_ahash *tfm)
{
struct ahash_request *req;
struct scatterlist sg;
struct crypto_wait wait;
int rc, ahash_rc = 0;
hash->length = crypto_ahash_digestsize(tfm);
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req)
return -ENOMEM;
crypto_init_wait(&wait);
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait);
rc = ahash_wait(crypto_ahash_init(req), &wait);
if (rc)
goto out;
sg_init_one(&sg, buf, len);
ahash_request_set_crypt(req, &sg, NULL, len);
ahash_rc = crypto_ahash_update(req);
/* wait for the update request to complete */
rc = ahash_wait(ahash_rc, &wait);
if (!rc) {
ahash_request_set_crypt(req, NULL, hash->digest, 0);
rc = ahash_wait(crypto_ahash_final(req), &wait);
}
out:
ahash_request_free(req);
return rc;
}
static int calc_buffer_ahash(const void *buf, loff_t len,
struct ima_digest_data *hash)
{
struct crypto_ahash *tfm;
int rc;
tfm = ima_alloc_atfm(hash->algo);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
rc = calc_buffer_ahash_atfm(buf, len, hash, tfm);
ima_free_atfm(tfm);
return rc;
}
static int calc_buffer_shash_tfm(const void *buf, loff_t size,
struct ima_digest_data *hash,
struct crypto_shash *tfm)
@@ -742,8 +398,8 @@ static int calc_buffer_shash_tfm(const void *buf, loff_t size,
return rc;
}
static int calc_buffer_shash(const void *buf, loff_t len,
struct ima_digest_data *hash)
int ima_calc_buffer_hash(const void *buf, loff_t len,
struct ima_digest_data *hash)
{
struct crypto_shash *tfm;
int rc;
@@ -758,20 +414,6 @@ static int calc_buffer_shash(const void *buf, loff_t len,
return rc;
}
int ima_calc_buffer_hash(const void *buf, loff_t len,
struct ima_digest_data *hash)
{
int rc;
if (ima_ahash_minsize && len >= ima_ahash_minsize) {
rc = calc_buffer_ahash(buf, len, hash);
if (!rc)
return 0;
}
return calc_buffer_shash(buf, len, hash);
}
static void ima_pcrread(u32 idx, struct tpm_digest *d)
{
if (!ima_tpm_chip)
@@ -832,7 +474,7 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
}
}
if (!rc)
crypto_shash_final(shash, digest);
rc = crypto_shash_final(shash, digest);
return rc;
}

View File

@@ -2,52 +2,9 @@
/*
* Copyright (C) 2018 IBM Corporation
*/
#include <linux/efi.h>
#include <linux/module.h>
#include <linux/ima.h>
#include <asm/efi.h>
#ifndef arch_ima_efi_boot_mode
#define arch_ima_efi_boot_mode efi_secureboot_mode_unset
#endif
static enum efi_secureboot_mode get_sb_mode(void)
{
enum efi_secureboot_mode mode;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
pr_info("ima: secureboot mode unknown, no efi\n");
return efi_secureboot_mode_unknown;
}
mode = efi_get_secureboot_mode(efi.get_variable);
if (mode == efi_secureboot_mode_disabled)
pr_info("ima: secureboot mode disabled\n");
else if (mode == efi_secureboot_mode_unknown)
pr_info("ima: secureboot mode unknown\n");
else
pr_info("ima: secureboot mode enabled\n");
return mode;
}
bool arch_ima_get_secureboot(void)
{
static enum efi_secureboot_mode sb_mode;
static bool initialized;
if (!initialized && efi_enabled(EFI_BOOT)) {
sb_mode = arch_ima_efi_boot_mode;
if (sb_mode == efi_secureboot_mode_unset)
sb_mode = get_sb_mode();
initialized = true;
}
if (sb_mode == efi_secureboot_mode_enabled)
return true;
else
return false;
}
#include <linux/secure_boot.h>
/* secureboot arch rules */
static const char * const sb_arch_rules[] = {
@@ -67,11 +24,9 @@ static const char * const sb_arch_rules[] = {
const char * const *arch_get_ima_policy(void)
{
if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
if (IS_ENABLED(CONFIG_MODULE_SIG))
set_module_sig_enforced();
if (IS_ENABLED(CONFIG_KEXEC_SIG))
set_kexec_sig_enforced();
if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_get_secureboot()) {
set_module_sig_enforced();
set_kexec_sig_enforced();
return sb_arch_rules;
}
return NULL;

View File

@@ -132,16 +132,12 @@ int ima_measurements_show(struct seq_file *m, void *v)
char *template_name;
u32 pcr, namelen, template_data_len; /* temporary fields */
bool is_ima_template = false;
enum hash_algo algo;
int i, algo_idx;
algo_idx = ima_sha1_idx;
algo = HASH_ALGO_SHA1;
if (m->file != NULL) {
if (m->file != NULL)
algo_idx = (unsigned long)file_inode(m->file)->i_private;
algo = ima_algo_array[algo_idx].algo;
}
/* get entry */
e = qe->entry;
@@ -160,7 +156,8 @@ int ima_measurements_show(struct seq_file *m, void *v)
ima_putc(m, &pcr, sizeof(e->pcr));
/* 2nd: template digest */
ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
ima_putc(m, e->digests[algo_idx].digest,
ima_algo_array[algo_idx].digest_size);
/* 3rd: template name size */
namelen = !ima_canonical_fmt ? strlen(template_name) :
@@ -229,16 +226,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
struct ima_queue_entry *qe = v;
struct ima_template_entry *e;
char *template_name;
enum hash_algo algo;
int i, algo_idx;
algo_idx = ima_sha1_idx;
algo = HASH_ALGO_SHA1;
if (m->file != NULL) {
if (m->file != NULL)
algo_idx = (unsigned long)file_inode(m->file)->i_private;
algo = ima_algo_array[algo_idx].algo;
}
/* get entry */
e = qe->entry;
@@ -252,7 +245,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
seq_printf(m, "%2d ", e->pcr);
/* 2nd: template hash */
ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
ima_print_digest(m, e->digests[algo_idx].digest,
ima_algo_array[algo_idx].digest_size);
/* 3th: template name */
seq_printf(m, " %s", template_name);
@@ -404,16 +398,24 @@ static int __init create_securityfs_measurement_lists(void)
char file_name[NAME_MAX + 1];
struct dentry *dentry;
sprintf(file_name, "ascii_runtime_measurements_%s",
hash_algo_name[algo]);
if (algo == HASH_ALGO__LAST)
sprintf(file_name, "ascii_runtime_measurements_tpm_alg_%x",
ima_tpm_chip->allocated_banks[i].alg_id);
else
sprintf(file_name, "ascii_runtime_measurements_%s",
hash_algo_name[algo]);
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
ima_dir, (void *)(uintptr_t)i,
&ima_ascii_measurements_ops);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
sprintf(file_name, "binary_runtime_measurements_%s",
hash_algo_name[algo]);
if (algo == HASH_ALGO__LAST)
sprintf(file_name, "binary_runtime_measurements_tpm_alg_%x",
ima_tpm_chip->allocated_banks[i].alg_id);
else
sprintf(file_name, "binary_runtime_measurements_%s",
hash_algo_name[algo]);
dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
ima_dir, (void *)(uintptr_t)i,
&ima_measurements_ops);

View File

@@ -180,6 +180,29 @@ static void ima_rdwr_violation_check(struct file *file,
"invalid_pcr", "open_writers");
}
/*
* Detect file change based on STATX_CHANGE_COOKIE, when supported, and
* fallback to detecting file change based on i_version. On filesystems
* which do not support either, assume the file changed.
*/
static bool ima_detect_file_change(struct ima_iint_cache *iint,
struct inode *inode, struct file *file)
{
struct kstat stat;
int result;
result = vfs_getattr_nosec(&file->f_path, &stat, STATX_CHANGE_COOKIE,
AT_STATX_SYNC_AS_STAT);
if (!result && stat.result_mask & STATX_CHANGE_COOKIE)
return stat.change_cookie != iint->real_inode.version;
if (IS_I_VERSION(inode))
return !inode_eq_iversion(inode, iint->real_inode.version);
return true;
}
static void ima_check_last_writer(struct ima_iint_cache *iint,
struct inode *inode, struct file *file)
{
@@ -191,18 +214,13 @@ static void ima_check_last_writer(struct ima_iint_cache *iint,
mutex_lock(&iint->mutex);
if (atomic_read(&inode->i_writecount) == 1) {
struct kstat stat;
clear_bit(IMA_EMITTED_OPENWRITERS, &iint->atomic_flags);
update = test_and_clear_bit(IMA_UPDATE_XATTR,
&iint->atomic_flags);
if ((iint->flags & IMA_NEW_FILE) ||
vfs_getattr_nosec(&file->f_path, &stat,
STATX_CHANGE_COOKIE,
AT_STATX_SYNC_AS_STAT) ||
!(stat.result_mask & STATX_CHANGE_COOKIE) ||
stat.change_cookie != iint->real_inode.version) {
if (iint->flags & IMA_NEW_FILE ||
ima_detect_file_change(iint, inode, file)) {
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
iint->measured_pcrs = 0;
if (update)
@@ -953,8 +971,7 @@ static int ima_load_data(enum kernel_load_data_id id, bool contents)
switch (id) {
case LOADING_KEXEC_IMAGE:
if (IS_ENABLED(CONFIG_KEXEC_SIG)
&& arch_ima_get_secureboot()) {
if (IS_ENABLED(CONFIG_KEXEC_SIG) && arch_get_secureboot()) {
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
return -EACCES;
}

View File

@@ -1298,7 +1298,8 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
IMA_GID | IMA_EGID |
IMA_FGROUP | IMA_DIGSIG_REQUIRED |
IMA_PERMIT_DIRECTIO | IMA_VALIDATE_ALGOS |
IMA_CHECK_BLACKLIST | IMA_VERITY_REQUIRED))
IMA_CHECK_BLACKLIST | IMA_VERITY_REQUIRED |
IMA_SIGV3_REQUIRED))
return false;
break;
@@ -1833,9 +1834,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
break;
case Opt_digest_type:
ima_log_string(ab, "digest_type", args[0].from);
if (entry->flags & IMA_DIGSIG_REQUIRED)
result = -EINVAL;
else if ((strcmp(args[0].from, "verity")) == 0)
if ((strcmp(args[0].from, "verity")) == 0)
entry->flags |= IMA_VERITY_REQUIRED;
else
result = -EINVAL;
@@ -1849,14 +1848,13 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
else
entry->flags |= IMA_DIGSIG_REQUIRED | IMA_CHECK_BLACKLIST;
} else if (strcmp(args[0].from, "sigv3") == 0) {
/* Only fsverity supports sigv3 for now */
if (entry->flags & IMA_VERITY_REQUIRED)
entry->flags |= IMA_DIGSIG_REQUIRED | IMA_CHECK_BLACKLIST;
else
result = -EINVAL;
entry->flags |= IMA_SIGV3_REQUIRED |
IMA_DIGSIG_REQUIRED |
IMA_CHECK_BLACKLIST;
} else if (IS_ENABLED(CONFIG_IMA_APPRAISE_MODSIG) &&
strcmp(args[0].from, "imasig|modsig") == 0) {
if (entry->flags & IMA_VERITY_REQUIRED)
if ((entry->flags & IMA_VERITY_REQUIRED) ||
(entry->flags & IMA_SIGV3_REQUIRED))
result = -EINVAL;
else
entry->flags |= IMA_DIGSIG_REQUIRED |
@@ -1941,7 +1939,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
/* d-ngv2 template field recommended for unsigned fs-verity digests */
if (!result && entry->action == MEASURE &&
entry->flags & IMA_VERITY_REQUIRED) {
(entry->flags & IMA_VERITY_REQUIRED)) {
template_desc = entry->template ? entry->template :
ima_template_desc_current();
check_template_field(template_desc, "d-ngv2",
@@ -2309,7 +2307,7 @@ int ima_policy_show(struct seq_file *m, void *v)
if (entry->template)
seq_printf(m, "template=%s ", entry->template->name);
if (entry->flags & IMA_DIGSIG_REQUIRED) {
if (entry->flags & IMA_VERITY_REQUIRED)
if (entry->flags & IMA_SIGV3_REQUIRED)
seq_puts(m, "appraise_type=sigv3 ");
else if (entry->flags & IMA_MODSIG_ALLOWED)
seq_puts(m, "appraise_type=imasig|modsig ");

View File

@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/integrity.h>
#include <linux/secure_boot.h>
#include <crypto/sha1.h>
#include <crypto/hash.h>
#include <linux/key.h>
@@ -130,7 +131,7 @@ struct modsig;
#ifdef CONFIG_INTEGRITY_SIGNATURE
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen);
const char *digest, int digestlen, u8 algo);
int integrity_modsig_verify(unsigned int id, const struct modsig *modsig);
int __init integrity_init_keyring(const unsigned int id);
@@ -141,7 +142,8 @@ int __init integrity_load_cert(const unsigned int id, const char *source,
static inline int integrity_digsig_verify(const unsigned int id,
const char *sig, int siglen,
const char *digest, int digestlen)
const char *digest, int digestlen,
u8 algo)
{
return -EOPNOTSUPP;
}
@@ -169,12 +171,21 @@ static inline int __init integrity_load_cert(const unsigned int id,
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
int asymmetric_verify(struct key *keyring, const char *sig,
int siglen, const char *data, int datalen);
int asymmetric_verify_v3(struct key *keyring, const char *sig,
int siglen, const char *data, int datalen, u8 algo);
#else
static inline int asymmetric_verify(struct key *keyring, const char *sig,
int siglen, const char *data, int datalen)
{
return -EOPNOTSUPP;
}
static inline int asymmetric_verify_v3(struct key *keyring,
const char *sig, int siglen,
const char *data, int datalen, u8 algo)
{
return -EOPNOTSUPP;
}
#endif
#ifdef CONFIG_IMA_APPRAISE_MODSIG

View File

@@ -212,7 +212,7 @@ static int __init load_uefi_certs(void)
}
/* the MOK/MOKx can not be trusted when secure boot is disabled */
if (!arch_ima_get_secureboot())
if (!arch_get_secureboot())
return 0;
mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &status);