[PATCH v4 09/13] ima: Add support for staging measurements with prompt

steven chen chenste at linux.microsoft.com
Wed Apr 1 17:52:32 UTC 2026


On 3/27/2026 9:45 AM, Roberto Sassu wrote:
> On Thu, 2026-03-26 at 15:44 -0700, steven chen wrote:
>> On 3/26/2026 10:30 AM, Roberto Sassu wrote:
>>> From: Roberto Sassu <roberto.sassu at huawei.com>
>>>
>>> Introduce the ability of staging the IMA measurement list and deleting them
>>> with a prompt.
>>>
>>> Staging means moving the current content of the measurement list to a
>>> separate location, and allowing users to read and delete it. This causes
>>> the measurement list to be atomically truncated before new measurements can
>>> be added. Staging can be done only once at a time. In the event of kexec(),
>>> staging is reverted and staged entries will be carried over to the new
>>> kernel.
>>>
>>> Introduce ascii_runtime_measurements_<algo>_staged and
>>> binary_runtime_measurements_<algo>_staged interfaces to stage and delete
>>> the measurements. Use 'echo A > <IMA interface>' and
>>> 'echo D > <IMA interface>' to respectively stage and delete the entire
>>> measurements list. Locking of these interfaces is also mediated with a call
>>> to _ima_measurements_open() and with ima_measurements_release().
>>>
>>> Implement the staging functionality by introducing the new global
>>> measurements list ima_measurements_staged, and ima_queue_stage() and
>>> ima_queue_delete_staged_all() to respectively move measurements from the
>>> current measurements list to the staged one, and to move staged
>>> measurements to the ima_measurements_trim list for deletion. Introduce
>>> ima_queue_delete() to delete the measurements.
>>>
>>> Finally, introduce the BINARY_STAGED AND BINARY_FULL binary measurements
>>> list types, to maintain the counters and the binary size of staged
>>> measurements and the full measurements list (including entries that were
>>> staged). BINARY still represents the current binary measurements list.
>>>
>>> Use the binary size for the BINARY + BINARY_STAGED types in
>>> ima_add_kexec_buffer(), since both measurements list types are copied to
>>> the secondary kernel during kexec. Use BINARY_FULL in
>>> ima_measure_kexec_event(), to generate a critical data record.
>>>
>>> It should be noted that the BINARY_FULL counter is not passed through
>>> kexec. Thus, the number of entries included in the kexec critical data
>>> records refers to the entries since the previous kexec records.
>>>
>>> Note: This code derives from the Alt-IMA Huawei project, whose license is
>>>         GPL-2.0 OR MIT.
>>>
>>> Link: https://github.com/linux-integrity/linux/issues/1
>>> Suggested-by: Gregory Lumen <gregorylumen at linux.microsoft.com> (staging revert)
>>> Signed-off-by: Roberto Sassu <roberto.sassu at huawei.com>
>>> ---
>>>    security/integrity/ima/Kconfig     |  13 +++
>>>    security/integrity/ima/ima.h       |   8 +-
>>>    security/integrity/ima/ima_fs.c    | 167 ++++++++++++++++++++++++++---
>>>    security/integrity/ima/ima_kexec.c |  22 +++-
>>>    security/integrity/ima/ima_queue.c |  97 ++++++++++++++++-
>>>    5 files changed, 286 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
>>> index 976e75f9b9ba..e714726f3384 100644
>>> --- a/security/integrity/ima/Kconfig
>>> +++ b/security/integrity/ima/Kconfig
>>> @@ -332,4 +332,17 @@ config IMA_KEXEC_EXTRA_MEMORY_KB
>>>    	  If set to the default value of 0, an extra half page of memory for those
>>>    	  additional measurements will be allocated.
>>>    
>>> +config IMA_STAGING
>>> +	bool "Support for staging the measurements list"
>>> +	default y
>>> +	help
>>> +	  Add support for staging the measurements list.
>>> +
>>> +	  It allows user space to stage the measurements list for deletion and
>>> +	  to delete the staged measurements after confirmation.
>>> +
>>> +	  On kexec, staging is reverted and staged measurements are prepended
>>> +	  to the current measurements list when measurements are copied to the
>>> +	  secondary kernel.
>>> +
>>>    endif
>>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>>> index 97b7d6024b5d..65db152a0a24 100644
>>> --- a/security/integrity/ima/ima.h
>>> +++ b/security/integrity/ima/ima.h
>>> @@ -30,9 +30,11 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8, TPM_PCR10 = 10 };
>>>    
>>>    /*
>>>     * BINARY: current binary measurements list
>>> + * BINARY_STAGED: staged binary measurements list
>>> + * BINARY_FULL: binary measurements list since IMA init (lost after kexec)
>>>     */
>>>    enum binary_lists {
>>> -	BINARY, BINARY__LAST
>>> +	BINARY, BINARY_STAGED, BINARY_FULL, BINARY__LAST
>>>    };
>>>    
>>>    /* digest size for IMA, fits SHA1 or MD5 */
>>> @@ -125,6 +127,7 @@ struct ima_queue_entry {
>>>    	struct ima_template_entry *entry;
>>>    };
>>>    extern struct list_head ima_measurements;	/* list of all measurements */
>>> +extern struct list_head ima_measurements_staged; /* list of staged meas. */
>>>    
>>>    /* Some details preceding the binary serialized measurement list */
>>>    struct ima_kexec_hdr {
>>> @@ -314,6 +317,8 @@ struct ima_template_desc *ima_template_desc_current(void);
>>>    struct ima_template_desc *ima_template_desc_buf(void);
>>>    struct ima_template_desc *lookup_template_desc(const char *name);
>>>    bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
>>> +int ima_queue_stage(void);
>>> +int ima_queue_staged_delete_all(void);
>>>    int ima_restore_measurement_entry(struct ima_template_entry *entry);
>>>    int ima_restore_measurement_list(loff_t bufsize, void *buf);
>>>    int ima_measurements_show(struct seq_file *m, void *v);
>>> @@ -334,6 +339,7 @@ extern spinlock_t ima_queue_lock;
>>>    extern atomic_long_t ima_num_entries[BINARY__LAST];
>>>    extern atomic_long_t ima_num_violations;
>>>    extern struct hlist_head __rcu *ima_htable;
>>> +extern struct mutex ima_extend_list_mutex;
>>>    
>>>    static inline unsigned int ima_hash_key(u8 *digest)
>>>    {
>>> diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
>>> index 7709a4576322..39d9128e9f22 100644
>>> --- a/security/integrity/ima/ima_fs.c
>>> +++ b/security/integrity/ima/ima_fs.c
>>> @@ -24,6 +24,13 @@
>>>    
>>>    #include "ima.h"
>>>    
>>> +/*
>>> + * Requests:
>>> + * 'A\n': stage the entire measurements list
>>> + * 'D\n': delete all staged measurements
>>> + */
>>> +#define STAGED_REQ_LENGTH 21
>>> +
>>>    static DEFINE_MUTEX(ima_write_mutex);
>>>    static DEFINE_MUTEX(ima_measure_mutex);
>>>    static long ima_measure_users;
>>> @@ -97,6 +104,11 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
>>>    	return _ima_measurements_start(m, pos, &ima_measurements);
>>>    }
>>>    
>>> +static void *ima_measurements_staged_start(struct seq_file *m, loff_t *pos)
>>> +{
>>> +	return _ima_measurements_start(m, pos, &ima_measurements_staged);
>>> +}
>>> +
>>>    static void *_ima_measurements_next(struct seq_file *m, void *v, loff_t *pos,
>>>    				    struct list_head *head)
>>>    {
>>> @@ -118,6 +130,12 @@ static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
>>>    	return _ima_measurements_next(m, v, pos, &ima_measurements);
>>>    }
>>>    
>>> +static void *ima_measurements_staged_next(struct seq_file *m, void *v,
>>> +					  loff_t *pos)
>>> +{
>>> +	return _ima_measurements_next(m, v, pos, &ima_measurements_staged);
>>> +}
>>> +
>>>    static void ima_measurements_stop(struct seq_file *m, void *v)
>>>    {
>>>    }
>>> @@ -283,6 +301,68 @@ static const struct file_operations ima_measurements_ops = {
>>>    	.release = ima_measurements_release,
>>>    };
>>>    
>>> +static const struct seq_operations ima_measurments_staged_seqops = {
>>> +	.start = ima_measurements_staged_start,
>>> +	.next = ima_measurements_staged_next,
>>> +	.stop = ima_measurements_stop,
>>> +	.show = ima_measurements_show
>>> +};
>>> +
>>> +static int ima_measurements_staged_open(struct inode *inode, struct file *file)
>>> +{
>>> +	return _ima_measurements_open(inode, file,
>>> +				      &ima_measurments_staged_seqops);
>>> +}
>>> +
>>> +static ssize_t ima_measurements_staged_write(struct file *file,
>>> +					     const char __user *buf,
>>> +					     size_t datalen, loff_t *ppos)
>>> +{
>>> +	char req[STAGED_REQ_LENGTH];
>>> +	int ret;
>>> +
>>> +	if (*ppos > 0 || datalen < 2 || datalen > STAGED_REQ_LENGTH)
>>> +		return -EINVAL;
>>> +
>>> +	if (copy_from_user(req, buf, datalen) != 0)
>>> +		return -EFAULT;
>>> +
>>> +	if (req[datalen - 1] != '\n')
>>> +		return -EINVAL;
>>> +
>>> +	req[datalen - 1] = '\0';
>>> +
>>> +	switch (req[0]) {
>>> +	case 'A':
>>> +		if (datalen != 2)
>>> +			return -EINVAL;
>>> +
>>> +		ret = ima_queue_stage();
>>> +		break;
>>> +	case 'D':
>>> +		if (datalen != 2)
>>> +			return -EINVAL;
>>> +
>>> +		ret = ima_queue_staged_delete_all();
>>> +		break;
>> I think the following two steps may not work because of race condition:
>>
>> step1: ret = ima_queue_stage(); //this will put all logs in active list into staged list;
>> step2: ret = ima_queue_staged_delete_all(); //this will delete all logs in staged list;
>>
>> The following is the step of race condition:
>>       1. current active log list LA1;
>>       2. user agent read the TPM quote QA1 match list LA1;
>>       3. new event NewLog is added into active log list LA1+NewLog
>>       4. user agent call ima_queue_stage() and generated staged list
>>          including LA1+NewLog.
>>       5. user agent call ima_queue_staged_delete_all();
>>          The new log NewLog in step 3 is also deleted
> Please refer to the documentation patch which explains the intended
> workflow of this approach (Remote Attestation Agent Workflow).
>
> Roberto
So the user agent needs to deeply involve measurement list management:
in user space, user agent need to maintain two lists
user agent is more complicated in this case

Steven

>> Next time the attestation will fail if using the active log list in the
>> kernel.
>>
>> Thanks,
>>
>> Steven
>>
>>> +	default:
>>> +		ret = -EINVAL;
>>> +	}
>>> +
>>> +	if (ret < 0)
>>> +		return ret;
>>> +
>>> +	return datalen;
>>> +}
>>> +
>>> +static const struct file_operations ima_measurements_staged_ops = {
>>> +	.open = ima_measurements_staged_open,
>>> +	.read = seq_read,
>>> +	.write = ima_measurements_staged_write,
>>> +	.llseek = seq_lseek,
>>> +	.release = ima_measurements_release,
>>> +};
>>> +
>>>    void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
>>>    {
>>>    	u32 i;
>>> @@ -356,6 +436,28 @@ static const struct file_operations ima_ascii_measurements_ops = {
>>>    	.release = ima_measurements_release,
>>>    };
>>>    
>>> +static const struct seq_operations ima_ascii_measurements_staged_seqops = {
>>> +	.start = ima_measurements_staged_start,
>>> +	.next = ima_measurements_staged_next,
>>> +	.stop = ima_measurements_stop,
>>> +	.show = ima_ascii_measurements_show
>>> +};
>>> +
>>> +static int ima_ascii_measurements_staged_open(struct inode *inode,
>>> +					      struct file *file)
>>> +{
>>> +	return _ima_measurements_open(inode, file,
>>> +				      &ima_ascii_measurements_staged_seqops);
>>> +}
>>> +
>>> +static const struct file_operations ima_ascii_measurements_staged_ops = {
>>> +	.open = ima_ascii_measurements_staged_open,
>>> +	.read = seq_read,
>>> +	.write = ima_measurements_staged_write,
>>> +	.llseek = seq_lseek,
>>> +	.release = ima_measurements_release,
>>> +};
>>> +
>>>    static ssize_t ima_read_policy(char *path)
>>>    {
>>>    	void *data = NULL;
>>> @@ -459,10 +561,21 @@ static const struct seq_operations ima_policy_seqops = {
>>>    };
>>>    #endif
>>>    
>>> -static int __init create_securityfs_measurement_lists(void)
>>> +static int __init create_securityfs_measurement_lists(bool staging)
>>>    {
>>> +	const struct file_operations *ascii_ops = &ima_ascii_measurements_ops;
>>> +	const struct file_operations *binary_ops = &ima_measurements_ops;
>>> +	mode_t permissions = S_IRUSR | S_IRGRP;
>>> +	const char *file_suffix = "";
>>>    	int count = NR_BANKS(ima_tpm_chip);
>>>    
>>> +	if (staging) {
>>> +		ascii_ops = &ima_ascii_measurements_staged_ops;
>>> +		binary_ops = &ima_measurements_staged_ops;
>>> +		file_suffix = "_staged";
>>> +		permissions |= (S_IWUSR | S_IWGRP);
>>> +	}
>>> +
>>>    	if (ima_sha1_idx >= NR_BANKS(ima_tpm_chip))
>>>    		count++;
>>>    
>>> @@ -473,29 +586,32 @@ static int __init create_securityfs_measurement_lists(void)
>>>    
>>>    		if (algo == HASH_ALGO__LAST)
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "ascii_runtime_measurements_tpm_alg_%x",
>>> -				 ima_tpm_chip->allocated_banks[i].alg_id);
>>> +				 "ascii_runtime_measurements_tpm_alg_%x%s",
>>> +				 ima_tpm_chip->allocated_banks[i].alg_id,
>>> +				 file_suffix);
>>>    		else
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "ascii_runtime_measurements_%s",
>>> -				 hash_algo_name[algo]);
>>> -		dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
>>> +				 "ascii_runtime_measurements_%s%s",
>>> +				 hash_algo_name[algo], file_suffix);
>>> +		dentry = securityfs_create_file(file_name, permissions,
>>>    						ima_dir, (void *)(uintptr_t)i,
>>> -						&ima_ascii_measurements_ops);
>>> +						ascii_ops);
>>>    		if (IS_ERR(dentry))
>>>    			return PTR_ERR(dentry);
>>>    
>>>    		if (algo == HASH_ALGO__LAST)
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "binary_runtime_measurements_tpm_alg_%x",
>>> -				 ima_tpm_chip->allocated_banks[i].alg_id);
>>> +				 "binary_runtime_measurements_tpm_alg_%x%s",
>>> +				 ima_tpm_chip->allocated_banks[i].alg_id,
>>> +				 file_suffix);
>>>    		else
>>>    			snprintf(file_name, sizeof(file_name),
>>> -				 "binary_runtime_measurements_%s",
>>> -				 hash_algo_name[algo]);
>>> -		dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
>>> +				 "binary_runtime_measurements_%s%s",
>>> +				 hash_algo_name[algo], file_suffix);
>>> +
>>> +		dentry = securityfs_create_file(file_name, permissions,
>>>    						ima_dir, (void *)(uintptr_t)i,
>>> -						&ima_measurements_ops);
>>> +						binary_ops);
>>>    		if (IS_ERR(dentry))
>>>    			return PTR_ERR(dentry);
>>>    	}
>>> @@ -503,6 +619,23 @@ static int __init create_securityfs_measurement_lists(void)
>>>    	return 0;
>>>    }
>>>    
>>> +static int __init create_securityfs_staging_links(void)
>>> +{
>>> +	struct dentry *dentry;
>>> +
>>> +	dentry = securityfs_create_symlink("binary_runtime_measurements_staged",
>>> +		ima_dir, "binary_runtime_measurements_sha1_staged", NULL);
>>> +	if (IS_ERR(dentry))
>>> +		return PTR_ERR(dentry);
>>> +
>>> +	dentry = securityfs_create_symlink("ascii_runtime_measurements_staged",
>>> +		ima_dir, "ascii_runtime_measurements_sha1_staged", NULL);
>>> +	if (IS_ERR(dentry))
>>> +		return PTR_ERR(dentry);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>    /*
>>>     * ima_open_policy: sequentialize access to the policy file
>>>     */
>>> @@ -595,7 +728,13 @@ int __init ima_fs_init(void)
>>>    		goto out;
>>>    	}
>>>    
>>> -	ret = create_securityfs_measurement_lists();
>>> +	ret = create_securityfs_measurement_lists(false);
>>> +	if (ret == 0 && IS_ENABLED(CONFIG_IMA_STAGING)) {
>>> +		ret = create_securityfs_measurement_lists(true);
>>> +		if (ret == 0)
>>> +			ret = create_securityfs_staging_links();
>>> +	}
>>> +
>>>    	if (ret != 0)
>>>    		goto out;
>>>    
>>> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
>>> index d7d0fb639d99..d5503dd5cc9b 100644
>>> --- a/security/integrity/ima/ima_kexec.c
>>> +++ b/security/integrity/ima/ima_kexec.c
>>> @@ -42,8 +42,8 @@ void ima_measure_kexec_event(const char *event_name)
>>>    	long len;
>>>    	int n;
>>>    
>>> -	buf_size = ima_get_binary_runtime_size(BINARY);
>>> -	len = atomic_long_read(&ima_num_entries[BINARY]);
>>> +	buf_size = ima_get_binary_runtime_size(BINARY_FULL);
>>> +	len = atomic_long_read(&ima_num_entries[BINARY_FULL]);
>>>    
>>>    	n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
>>>    		      "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;"
>>> @@ -106,13 +106,26 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>>>    
>>>    	memset(&khdr, 0, sizeof(khdr));
>>>    	khdr.version = 1;
>>> -	/* This is an append-only list, no need to hold the RCU read lock */
>>> -	list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
>>> +	/* It can race with ima_queue_stage() and ima_queue_delete_staged(). */
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +
>>> +	list_for_each_entry_rcu(qe, &ima_measurements_staged, later,
>>> +				lockdep_is_held(&ima_extend_list_mutex)) {
>>>    		ret = ima_dump_measurement(&khdr, qe);
>>>    		if (ret < 0)
>>>    			break;
>>>    	}
>>>    
>>> +	list_for_each_entry_rcu(qe, &ima_measurements, later,
>>> +				lockdep_is_held(&ima_extend_list_mutex)) {
>>> +		if (!ret)
>>> +			ret = ima_dump_measurement(&khdr, qe);
>>> +		if (ret < 0)
>>> +			break;
>>> +	}
>>> +
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +
>>>    	/*
>>>    	 * fill in reserved space with some buffer details
>>>    	 * (eg. version, buffer size, number of measurements)
>>> @@ -167,6 +180,7 @@ void ima_add_kexec_buffer(struct kimage *image)
>>>    		extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
>>>    
>>>    	binary_runtime_size = ima_get_binary_runtime_size(BINARY) +
>>> +			      ima_get_binary_runtime_size(BINARY_STAGED) +
>>>    			      extra_memory;
>>>    
>>>    	if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
>>> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
>>> index b6d10dceb669..50519ed837d4 100644
>>> --- a/security/integrity/ima/ima_queue.c
>>> +++ b/security/integrity/ima/ima_queue.c
>>> @@ -26,6 +26,7 @@
>>>    static struct tpm_digest *digests;
>>>    
>>>    LIST_HEAD(ima_measurements);	/* list of all measurements */
>>> +LIST_HEAD(ima_measurements_staged); /* list of staged measurements */
>>>    #ifdef CONFIG_IMA_KEXEC
>>>    static unsigned long binary_runtime_size[BINARY__LAST];
>>>    #else
>>> @@ -45,11 +46,11 @@ atomic_long_t ima_num_violations = ATOMIC_LONG_INIT(0);
>>>    /* key: inode (before secure-hashing a file) */
>>>    struct hlist_head __rcu *ima_htable;
>>>    
>>> -/* mutex protects atomicity of extending measurement list
>>> +/* mutex protects atomicity of extending and staging measurement list
>>>     * and extending the TPM PCR aggregate. Since tpm_extend can take
>>>     * long (and the tpm driver uses a mutex), we can't use the spinlock.
>>>     */
>>> -static DEFINE_MUTEX(ima_extend_list_mutex);
>>> +DEFINE_MUTEX(ima_extend_list_mutex);
>>>    
>>>    /*
>>>     * Used internally by the kernel to suspend measurements.
>>> @@ -174,12 +175,16 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
>>>    				lockdep_is_held(&ima_extend_list_mutex));
>>>    
>>>    	atomic_long_inc(&ima_num_entries[BINARY]);
>>> +	atomic_long_inc(&ima_num_entries[BINARY_FULL]);
>>> +
>>>    	if (update_htable) {
>>>    		key = ima_hash_key(entry->digests[ima_hash_algo_idx].digest);
>>>    		hlist_add_head_rcu(&qe->hnext, &htable[key]);
>>>    	}
>>>    
>>>    	ima_update_binary_runtime_size(entry, BINARY);
>>> +	ima_update_binary_runtime_size(entry, BINARY_FULL);
>>> +
>>>    	return 0;
>>>    }
>>>    
>>> @@ -280,6 +285,94 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
>>>    	return result;
>>>    }
>>>    
>>> +int ima_queue_stage(void)
>>> +{
>>> +	int ret = 0;
>>> +
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +	if (!list_empty(&ima_measurements_staged)) {
>>> +		ret = -EEXIST;
>>> +		goto out_unlock;
>>> +	}
>>> +
>>> +	if (list_empty(&ima_measurements)) {
>>> +		ret = -ENOENT;
>>> +		goto out_unlock;
>>> +	}
>>> +
>>> +	list_replace(&ima_measurements, &ima_measurements_staged);
>>> +	INIT_LIST_HEAD(&ima_measurements);
>>> +
>>> +	atomic_long_set(&ima_num_entries[BINARY_STAGED],
>>> +			atomic_long_read(&ima_num_entries[BINARY]));
>>> +	atomic_long_set(&ima_num_entries[BINARY], 0);
>>> +
>>> +	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
>>> +		binary_runtime_size[BINARY_STAGED] =
>>> +					binary_runtime_size[BINARY];
>>> +		binary_runtime_size[BINARY] = 0;
>>> +	}
>>> +out_unlock:
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +	return ret;
>>> +}
>>> +
>>> +static void ima_queue_delete(struct list_head *head);
>>> +
>>> +int ima_queue_staged_delete_all(void)
>>> +{
>>> +	LIST_HEAD(ima_measurements_trim);
>>> +
>>> +	mutex_lock(&ima_extend_list_mutex);
>>> +	if (list_empty(&ima_measurements_staged)) {
>>> +		mutex_unlock(&ima_extend_list_mutex);
>>> +		return -ENOENT;
>>> +	}
>>> +
>>> +	list_replace(&ima_measurements_staged, &ima_measurements_trim);
>>> +	INIT_LIST_HEAD(&ima_measurements_staged);
>>> +
>>> +	atomic_long_set(&ima_num_entries[BINARY_STAGED], 0);
>>> +
>>> +	if (IS_ENABLED(CONFIG_IMA_KEXEC))
>>> +		binary_runtime_size[BINARY_STAGED] = 0;
>>> +
>>> +	mutex_unlock(&ima_extend_list_mutex);
>>> +
>>> +	ima_queue_delete(&ima_measurements_trim);
>>> +	return 0;
>>> +}
>>> +
>>> +static void ima_queue_delete(struct list_head *head)
>>> +{
>>> +	struct ima_queue_entry *qe, *qe_tmp;
>>> +	unsigned int i;
>>> +
>>> +	list_for_each_entry_safe(qe, qe_tmp, head, later) {
>>> +		/*
>>> +		 * Safe to free template_data here without synchronize_rcu()
>>> +		 * because the only htable reader, ima_lookup_digest_entry(),
>>> +		 * accesses only entry->digests, not template_data. If new
>>> +		 * htable readers are added that access template_data, a
>>> +		 * synchronize_rcu() is required here.
>>> +		 */
>>> +		for (i = 0; i < qe->entry->template_desc->num_fields; i++) {
>>> +			kfree(qe->entry->template_data[i].data);
>>> +			qe->entry->template_data[i].data = NULL;
>>> +			qe->entry->template_data[i].len = 0;
>>> +		}
>>> +
>>> +		list_del(&qe->later);
>>> +
>>> +		/* No leak if condition is false, referenced by ima_htable. */
>>> +		if (IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)) {
>>> +			kfree(qe->entry->digests);
>>> +			kfree(qe->entry);
>>> +			kfree(qe);
>>> +		}
>>> +	}
>>> +}
>>> +
>>>    int ima_restore_measurement_entry(struct ima_template_entry *entry)
>>>    {
>>>    	int result = 0;





More information about the Linux-security-module-archive mailing list