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

@@ -26,6 +26,7 @@ Description:
2 Permit modification of EVM-protected metadata at
runtime. Not supported if HMAC validation and
creation is enabled (deprecated).
3 Require asymmetric signatures to be version 3
31 Disable further runtime modification of EVM policy
=== ==================================================

View File

@@ -53,10 +53,7 @@ Description:
where 'imasig' is the original or the signature
format v2.
where 'modsig' is an appended signature,
where 'sigv3' is the signature format v3. (Currently
limited to fsverity digest based signatures
stored in security.ima xattr. Requires
specifying "digest_type=verity" first.)
where 'sigv3' is the signature format v3.
appraise_flag:= [check_blacklist] (deprecated)
Setting the check_blacklist flag is no longer necessary.
@@ -186,6 +183,11 @@ Description:
appraise func=BPRM_CHECK digest_type=verity \
appraise_type=sigv3
Example of a regular IMA file hash 'appraise' rule requiring
signature version 3 format stored in security.ima xattr.
appraise func=BPRM_CHECK appraise_type=sigv3
All of these policy rules could, for example, be constrained
either based on a filesystem's UUID (fsuuid) or based on LSM
labels.

View File

@@ -2410,23 +2410,6 @@ Kernel parameters
[IMA] Define a custom template format.
Format: { "field1|...|fieldN" }
ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage
Format: <min_file_size>
Set the minimal file size for using asynchronous hash.
If left unspecified, ahash usage is disabled.
ahash performance varies for different data sizes on
different crypto accelerators. This option can be used
to achieve the best performance for a particular HW.
ima.ahash_bufsize= [IMA] Asynchronous hash buffer size
Format: <bufsize>
Set hashing buffer size. Default: 4k.
ahash performance varies for different chunk sizes on
different crypto accelerators. This option can be used
to achieve best performance for particular HW.
ima= [IMA] Enable or disable IMA
Format: { "off" | "on" }
Default: "on"

View File

@@ -12732,6 +12732,7 @@ R: Eric Snowberg <eric.snowberg@oracle.com>
L: linux-integrity@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git
F: include/linux/secure_boot.h
F: security/integrity/
F: security/integrity/ima/

View File

@@ -1839,4 +1839,7 @@ config ARCH_WANTS_PRE_LINK_VMLINUX
config ARCH_HAS_CPU_ATTACK_VECTORS
bool
config HAVE_ARCH_GET_SECUREBOOT
def_bool EFI
endmenu

View File

@@ -1058,6 +1058,7 @@ config PPC_SECURE_BOOT
depends on IMA_ARCH_POLICY
imply IMA_SECURE_AND_OR_TRUSTED_BOOT
select PSERIES_PLPKS if PPC_PSERIES
select HAVE_ARCH_GET_SECUREBOOT
help
Systems with firmware secure boot enabled need to define security
policies to extend secure boot to the OS. This config allows a user

View File

@@ -7,11 +7,6 @@
#include <linux/ima.h>
#include <asm/secure_boot.h>
bool arch_ima_get_secureboot(void)
{
return is_ppc_secureboot_enabled();
}
/*
* The "secure_rules" are enabled only on "secureboot" enabled systems.
* These rules verify the file signatures against known good values.
@@ -63,7 +58,6 @@ static const char *const secure_and_trusted_rules[] = {
const char *const *arch_get_ima_policy(void)
{
if (is_ppc_secureboot_enabled()) {
if (IS_ENABLED(CONFIG_MODULE_SIG))
set_module_sig_enforced();
if (is_ppc_trustedboot_enabled())

View File

@@ -5,6 +5,7 @@
*/
#include <linux/types.h>
#include <linux/of.h>
#include <linux/secure_boot.h>
#include <linux/string_choices.h>
#include <asm/secure_boot.h>
@@ -44,6 +45,11 @@ out:
return enabled;
}
bool arch_get_secureboot(void)
{
return is_ppc_secureboot_enabled();
}
bool is_ppc_trustedboot_enabled(void)
{
struct device_node *node;

View File

@@ -80,7 +80,6 @@ config S390
#
# Note: keep this list sorted alphabetically
#
imply IMA_SECURE_AND_OR_TRUSTED_BOOT
select ALTERNATE_USER_ADDRESS_SPACE
select ARCH_32BIT_USTAT_F_TINODE
select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
@@ -181,6 +180,7 @@ config S390
select GENERIC_IOREMAP if PCI
select HAVE_ALIGNED_STRUCT_PAGE
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_GET_SECUREBOOT
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_JUMP_LABEL_RELATIVE
select HAVE_ARCH_KASAN

View File

@@ -71,7 +71,6 @@ obj-$(CONFIG_STACKPROTECTOR) += stackprotector.o
obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o
obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o
obj-$(CONFIG_CERT_STORE) += cert_store.o
obj-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_arch.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf.o perf_cpum_sf.o

View File

@@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/ima.h>
#include <asm/boot_data.h>
bool arch_ima_get_secureboot(void)
{
return ipl_secure_flag;
}
const char * const *arch_get_ima_policy(void)
{
return NULL;
}

View File

@@ -21,6 +21,7 @@
#include <linux/crash_dump.h>
#include <linux/debug_locks.h>
#include <linux/vmalloc.h>
#include <linux/secure_boot.h>
#include <asm/asm-extable.h>
#include <asm/machine.h>
#include <asm/diag.h>
@@ -2387,6 +2388,11 @@ void __no_stack_protector s390_reset_system(void)
diag_amode31_ops.diag308_reset();
}
bool arch_get_secureboot(void)
{
return ipl_secure_flag;
}
#ifdef CONFIG_KEXEC_FILE
int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,

View File

@@ -401,9 +401,9 @@ extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
void *buf, struct efi_mem_range *mem);
extern enum efi_secureboot_mode __x86_ima_efi_boot_mode(void);
enum efi_secureboot_mode __x86_efi_boot_mode(void);
#define arch_ima_efi_boot_mode __x86_ima_efi_boot_mode()
#define arch_efi_boot_mode __x86_efi_boot_mode()
#ifdef CONFIG_EFI_RUNTIME_MAP
int efi_get_runtime_map_size(void);

View File

@@ -920,7 +920,7 @@ umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
return attr->mode;
}
enum efi_secureboot_mode __x86_ima_efi_boot_mode(void)
enum efi_secureboot_mode __x86_efi_boot_mode(void)
{
return boot_params.secure_boot;
}

View File

@@ -18,6 +18,8 @@ extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
void *xattr_value,
size_t xattr_value_len);
int evm_fix_hmac(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len);
int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, struct xattr *xattrs,
int *xattr_count);
@@ -51,6 +53,12 @@ static inline enum integrity_status evm_verifyxattr(struct dentry *dentry,
{
return INTEGRITY_UNKNOWN;
}
static inline int evm_fix_hmac(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
return -EOPNOTSUPP;
}
#endif
static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,

View File

@@ -11,6 +11,7 @@
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/kexec.h>
#include <linux/secure_boot.h>
#include <crypto/hash_info.h>
struct linux_binprm;
@@ -73,14 +74,8 @@ int ima_validate_range(phys_addr_t phys, size_t size);
#endif
#ifdef CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
extern bool arch_ima_get_secureboot(void);
extern const char * const *arch_get_ima_policy(void);
#else
static inline bool arch_ima_get_secureboot(void)
{
return false;
}
static inline const char * const *arch_get_ima_policy(void)
{
return NULL;

View File

@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2026 Red Hat, Inc. All Rights Reserved.
*
* Author: Coiby Xu <coxu@redhat.com>
*/
#ifndef _LINUX_SECURE_BOOT_H
#define _LINUX_SECURE_BOOT_H
#include <linux/types.h>
#ifdef CONFIG_HAVE_ARCH_GET_SECUREBOOT
/*
* Returns true if the platform secure boot is enabled.
* Returns false if disabled or not supported.
*/
bool arch_get_secureboot(void);
#else
static inline bool arch_get_secureboot(void) { return false; }
#endif
#endif /* _LINUX_SECURE_BOOT_H */

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);
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,7 +398,7 @@ 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,
int ima_calc_buffer_hash(const void *buf, loff_t len,
struct ima_digest_data *hash)
{
struct crypto_shash *tfm;
@@ -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,10 +24,8 @@ 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))
if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_get_secureboot()) {
set_module_sig_enforced();
if (IS_ENABLED(CONFIG_KEXEC_SIG))
set_kexec_sig_enforced();
return sb_arch_rules;
}

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,6 +398,10 @@ static int __init create_securityfs_measurement_lists(void)
char file_name[NAME_MAX + 1];
struct dentry *dentry;
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,
@@ -412,6 +410,10 @@ static int __init create_securityfs_measurement_lists(void)
if (IS_ERR(dentry))
return PTR_ERR(dentry);
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,

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);