mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
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:
@@ -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
|
||||
=== ==================================================
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,8 +58,7 @@ 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();
|
||||
set_module_sig_enforced();
|
||||
|
||||
if (is_ppc_trustedboot_enabled())
|
||||
return secure_and_trusted_rules;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
23
include/linux/secure_boot.h
Normal file
23
include/linux/secure_boot.h
Normal 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 */
|
||||
@@ -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/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
56
security/integrity/efi_secureboot.c
Normal file
56
security/integrity/efi_secureboot.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user