This commit is contained in:
Mark Brown
2026-07-31 15:26:30 +01:00
10 changed files with 170 additions and 10 deletions
+2
View File
@@ -167,6 +167,7 @@ enum lsm_order {
* @initcall_fs: LSM callback for fs_initcall setup, optional
* @initcall_device: LSM callback for device_initcall() setup, optional
* @initcall_late: LSM callback for late_initcall() setup, optional
* @initcall_late_sync: LSM callback for late_initcall_sync() setup, optional
*/
struct lsm_info {
const struct lsm_id *id;
@@ -182,6 +183,7 @@ struct lsm_info {
int (*initcall_fs)(void);
int (*initcall_device)(void);
int (*initcall_late)(void);
int (*initcall_late_sync)(void);
};
#define DEFINE_LSM(lsm) \
+10
View File
@@ -347,4 +347,14 @@ config IMA_STAGING
On kexec, staging is aborted and any staged measurement records are
copied to the secondary kernel.
config IMA_INIT_LATE_SYNC
bool "Initialise IMA at late_initcall_sync"
default n
help
This option initialises IMA at late_initcall_sync for platforms
where TPM device probing is deferred.
When this option is enabled, modules that access files in the
initramfs through usermode helper calls such as request_module()
during initcall must not be built-in. Otherwise, IMA may miss
file measurements for them.
endif
+5
View File
@@ -55,6 +55,8 @@ enum binary_lists {
/* current content of the policy */
extern int ima_policy_flag;
extern struct mutex ima_write_mutex;
/* bitset of digests algorithms allowed in the setxattr hook */
extern atomic_t ima_setxattr_allowed_hash_algorithms;
@@ -75,6 +77,7 @@ extern struct ima_algo_desc *ima_algo_array __ro_after_init;
extern int ima_appraise;
extern struct tpm_chip *ima_tpm_chip;
extern const char boot_aggregate_name[];
extern const char boot_aggregate_late_name[];
/* IMA event related data */
struct ima_event_data {
@@ -466,6 +469,8 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos);
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
void ima_policy_stop(struct seq_file *m, void *v);
int ima_policy_show(struct seq_file *m, void *v);
void ima_measure_loaded_policy(void);
int ima_measure_raw_policy(const char *buf, size_t buf_len);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
+2
View File
@@ -17,6 +17,8 @@ static const char * const sb_arch_rules[] = {
#endif
#if IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && IS_ENABLED(CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY)
"appraise func=POLICY_CHECK appraise_type=imasig",
#else
"measure func=CRITICAL_DATA label=ima_policy",
#endif
"measure func=MODULE_CHECK",
NULL
+8 -1
View File
@@ -32,7 +32,9 @@
*/
#define STAGED_REQ_LENGTH 21
static DEFINE_MUTEX(ima_write_mutex);
/* lock for protecting concurrent IMA policy updates */
DEFINE_MUTEX(ima_write_mutex);
static DEFINE_MUTEX(ima_measure_mutex);
static long ima_measure_users;
static struct task_struct *measure_writer;
@@ -596,6 +598,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
1, 0);
result = -EACCES;
} else {
ima_measure_raw_policy(data, datalen);
result = ima_parse_add_rule(data);
}
mutex_unlock(&ima_write_mutex);
@@ -752,6 +755,10 @@ static int ima_release_policy(struct inode *inode, struct file *file)
}
ima_update_policy();
mutex_lock(&ima_write_mutex);
ima_measure_loaded_policy();
mutex_unlock(&ima_write_mutex);
#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
securityfs_remove(file->f_path.dentry);
#elif defined(CONFIG_IMA_WRITE_POLICY)
+11 -4
View File
@@ -22,6 +22,7 @@
/* name for boot aggregate entry */
const char boot_aggregate_name[] = "boot_aggregate";
const char boot_aggregate_late_name[] = "boot_aggregate_late";
struct tpm_chip *ima_tpm_chip;
/* Add the boot aggregate to the IMA measurement list and extend
@@ -45,11 +46,11 @@ static int __init ima_add_boot_aggregate(void)
const char *audit_cause = "ENOMEM";
struct ima_template_entry *entry;
struct ima_iint_cache tmp_iint, *iint = &tmp_iint;
struct ima_event_data event_data = { .iint = iint,
.filename = boot_aggregate_name };
struct ima_event_data event_data = { .iint = iint };
struct ima_max_digest_data hash;
struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
struct ima_digest_data, hdr);
const char *filename;
int result = -ENOMEM;
int violation = 0;
@@ -59,6 +60,12 @@ static int __init ima_add_boot_aggregate(void)
iint->ima_hash->algo = ima_hash_algo;
iint->ima_hash->length = hash_digest_size[ima_hash_algo];
if (IS_ENABLED(CONFIG_IMA_INIT_LATE_SYNC))
filename = boot_aggregate_late_name;
else
filename = boot_aggregate_name;
event_data.filename = filename;
/*
* With TPM 2.0 hash agility, TPM chips could support multiple TPM
* PCR banks, allowing firmware to configure and enable different
@@ -86,7 +93,7 @@ static int __init ima_add_boot_aggregate(void)
}
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name,
filename,
CONFIG_IMA_MEASURE_PCR_IDX);
if (result < 0) {
ima_free_template_entry(entry);
@@ -95,7 +102,7 @@ static int __init ima_add_boot_aggregate(void)
}
return 0;
err_out:
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, filename, op,
audit_cause, result, 0);
return result;
}
+26
View File
@@ -1221,6 +1221,28 @@ int ima_measure_critical_data(const char *event_label,
}
EXPORT_SYMBOL_GPL(ima_measure_critical_data);
/**
* ima_measure_raw_policy - Measure the raw policy write buffer
* @buf: pointer to the buffer containing the raw policy data
* @buf_len: size of the buffer
*
* Measure the raw policy buffer sent to the IMA policy securityfs file. The
* buffer is written from userspace, and the measurement is performed before
* parsing it. This measurement includes any data written on the policy file
* such as malformed policy rules and comments.
*
* Return 0 on success, a negative value otherwise.
*/
int ima_measure_raw_policy(const char *buf, size_t buf_len)
{
if (!buf || !buf_len)
return -EINVAL;
return process_buffer_measurement(&nop_mnt_idmap, NULL, buf, buf_len,
"ima_policy_written", POLICY_CHECK,
0, NULL, false, NULL, 0);
}
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
/**
@@ -1337,5 +1359,9 @@ DEFINE_LSM(ima) = {
.order = LSM_ORDER_LAST,
.blobs = &ima_blob_sizes,
/* Start IMA after the TPM is available */
#ifndef CONFIG_IMA_INIT_LATE_SYNC
.initcall_late = init_ima,
#else
.initcall_late_sync = init_ima,
#endif
};
+93 -2
View File
@@ -53,6 +53,8 @@
#define INVALID_PCR(a) (((a) < 0) || \
(a) >= (sizeof_field(struct ima_iint_cache, measured_pcrs) * 8))
static size_t max_rule_len;
int ima_policy_flag;
static int temp_ima_appraise;
static int build_ima_appraise __ro_after_init;
@@ -540,6 +542,8 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule,
opt_list = rule->label;
break;
case POLICY_CHECK:
return true;
default:
return false;
}
@@ -586,6 +590,10 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
return false;
switch (func) {
case POLICY_CHECK:
if (inode)
break;
fallthrough;
case KEY_CHECK:
case CRITICAL_DATA:
return ((rule->func == func) &&
@@ -955,6 +963,8 @@ void __init ima_init_policy(void)
{
int build_appraise_entries, arch_entries;
max_rule_len = 255;
/* if !ima_policy, we load NO default rules */
if (ima_policy)
add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules),
@@ -1994,6 +2004,9 @@ ssize_t ima_parse_add_rule(char *rule)
list_add_tail(&entry->list, &ima_temp_rules);
if (len > max_rule_len)
max_rule_len = len;
return len;
}
@@ -2021,7 +2034,6 @@ const char *const func_tokens[] = {
__ima_hooks(__ima_hook_stringify)
};
#ifdef CONFIG_IMA_READ_POLICY
enum {
mask_exec = 0, mask_write, mask_read, mask_append
};
@@ -2323,7 +2335,6 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, "\n");
return 0;
}
#endif /* CONFIG_IMA_READ_POLICY */
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
/*
@@ -2380,3 +2391,83 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
return found;
}
#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
/**
* ima_measure_loaded_policy - measure the active IMA policy ruleset
*
* Must be called with ima_write_mutex held, as it performs two
* separate RCU read passes over ima_rules and relies on the mutex
* to prevent concurrent policy updates between them.
*/
void ima_measure_loaded_policy(void)
{
const char *event_name = "ima_policy_loaded";
const char *op = "measure_loaded_ima_policy";
size_t rule_len = max_rule_len + 2;
struct ima_rule_entry *rule_entry;
struct list_head *ima_rules_tmp;
struct seq_file file = { 0 };
int result = -ENOMEM;
size_t file_len = 0;
char *rule;
lockdep_assert_held(&ima_write_mutex);
rule = kmalloc(rule_len, GFP_KERNEL);
if (!rule) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, event_name,
op, "ENOMEM", result, 0);
return;
}
/* calculate IMA policy rules memory size */
file.buf = rule;
file.read_pos = 0;
file.size = rule_len;
file.count = 0;
rcu_read_lock();
ima_rules_tmp = rcu_dereference(ima_rules);
list_for_each_entry_rcu(rule_entry, ima_rules_tmp, list) {
ima_policy_show(&file, rule_entry);
if (seq_has_overflowed(&file)) {
result = -E2BIG;
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL,
event_name, op, "rule_length",
result, 0);
rcu_read_unlock();
goto free_rule;
}
file_len += file.count;
file.count = 0;
}
rcu_read_unlock();
/* copy IMA policy rules to a buffer for measuring */
file.buf = kmalloc(file_len, GFP_KERNEL);
if (!file.buf) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, event_name,
op, "ENOMEM", result, 0);
goto free_rule;
}
file.read_pos = 0;
file.size = file_len;
file.count = 0;
rcu_read_lock();
ima_rules_tmp = rcu_dereference(ima_rules);
list_for_each_entry_rcu(rule_entry, ima_rules_tmp, list) {
ima_policy_show(&file, rule_entry);
}
rcu_read_unlock();
ima_measure_critical_data("ima_policy", event_name, file.buf,
file.count, false, NULL, 0);
kfree(file.buf);
free_rule:
kfree(rule);
}
+2 -1
View File
@@ -363,7 +363,8 @@ int ima_eventdigest_init(struct ima_event_data *event_data,
goto out;
}
if ((const char *)event_data->filename == boot_aggregate_name) {
if ((const char *)event_data->filename == boot_aggregate_name ||
(const char *)event_data->filename == boot_aggregate_late_name) {
if (ima_tpm_chip) {
hash.hdr.algo = HASH_ALGO_SHA1;
result = ima_calc_boot_aggregate(hash_hdr);
+11 -2
View File
@@ -556,13 +556,22 @@ device_initcall(security_initcall_device);
* security_initcall_late - Run the LSM late initcalls
*/
static int __init security_initcall_late(void)
{
return lsm_initcall(late);
}
late_initcall(security_initcall_late);
/**
* security_initcall_late_sync - Run the LSM late initcalls sync
*/
static int __init security_initcall_late_sync(void)
{
int rc;
rc = lsm_initcall(late);
rc = lsm_initcall(late_sync);
lsm_pr_dbg("all enabled LSMs fully activated\n");
call_blocking_lsm_notifier(LSM_STARTED_ALL, NULL);
return rc;
}
late_initcall(security_initcall_late);
late_initcall_sync(security_initcall_late_sync);