diff mbox series

[v2] ima: Suspend PCR extends and log appends when rebooting

Message ID 20241112165206.756351-1-stefanb@linux.ibm.com (mailing list archive)
State Handled Elsewhere
Headers show
Series [v2] ima: Suspend PCR extends and log appends when rebooting | expand

Commit Message

Stefan Berger Nov. 12, 2024, 4:52 p.m. UTC
To avoid the following types of error messages due to a failure by the TPM
driver to use the TPM, suspend TPM PCR extensions and the appending of
entries to the IMA log once IMA's reboot notifier has been called. This
avoids trying to use the TPM after the TPM subsystem has been shut down.

[111707.685315][    T1] ima: Error Communicating to TPM chip, result: -19
[111707.685960][    T1] ima: Error Communicating to TPM chip, result: -19

This error could be observed on a ppc64 machine running SuSE Linux where
processes are still accessing files after devices have been shut down.

Suspending the IMA log and PCR extensions shortly before reboot does not
seem to open a significant measurement gap since neither TPM quoting would
work for attestation nor that new log entries could be written to anywhere
after devices have been shut down. However, there's a time window between
the invocation of the reboot notifier and the shutdown of devices in
kernel_restart_prepare() where __usermodehelper_disable() waits for all
running_helpers to exit. During this time window IMA could now miss log
entries even though attestation would still work. The reboot of the system
shortly after may make this small gap insignificant.

Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

---
 v2:
  - followed Mimi's suggestions

---
 security/integrity/ima/ima.h       |  1 +
 security/integrity/ima/ima_init.c  |  2 ++
 security/integrity/ima/ima_queue.c | 43 ++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+)

Comments

Jarkko Sakkinen Nov. 12, 2024, 5:59 p.m. UTC | #1
On Tue Nov 12, 2024 at 6:52 PM EET, Stefan Berger wrote:
> To avoid the following types of error messages due to a failure by the TPM
> driver to use the TPM, suspend TPM PCR extensions and the appending of
> entries to the IMA log once IMA's reboot notifier has been called. This
> avoids trying to use the TPM after the TPM subsystem has been shut down.
>
> [111707.685315][    T1] ima: Error Communicating to TPM chip, result: -19
> [111707.685960][    T1] ima: Error Communicating to TPM chip, result: -19
>
> This error could be observed on a ppc64 machine running SuSE Linux where
> processes are still accessing files after devices have been shut down.
>
> Suspending the IMA log and PCR extensions shortly before reboot does not
> seem to open a significant measurement gap since neither TPM quoting would
> work for attestation nor that new log entries could be written to anywhere
> after devices have been shut down. However, there's a time window between
> the invocation of the reboot notifier and the shutdown of devices in
> kernel_restart_prepare() where __usermodehelper_disable() waits for all
> running_helpers to exit. During this time window IMA could now miss log
> entries even though attestation would still work. The reboot of the system
> shortly after may make this small gap insignificant.
>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>
> ---
>  v2:
>   - followed Mimi's suggestions
>
> ---
>  security/integrity/ima/ima.h       |  1 +
>  security/integrity/ima/ima_init.c  |  2 ++
>  security/integrity/ima/ima_queue.c | 43 ++++++++++++++++++++++++++++++
>  3 files changed, 46 insertions(+)
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 3c323ca213d4..3f1a82b7cd71 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -278,6 +278,7 @@ unsigned long ima_get_binary_runtime_size(void);
>  int ima_init_template(void);
>  void ima_init_template_list(void);
>  int __init ima_init_digests(void);
> +void __init ima_init_reboot_notifier(void);
>  int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
>  			  void *lsm_data);
>  
> diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
> index 4e208239a40e..a2f34f2d8ad7 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -152,6 +152,8 @@ int __init ima_init(void)
>  
>  	ima_init_key_queue();
>  
> +	ima_init_reboot_notifier();
> +
>  	ima_measure_critical_data("kernel_info", "kernel_version",
>  				  UTS_RELEASE, strlen(UTS_RELEASE), false,
>  				  NULL, 0);
> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
> index 532da87ce519..9b3c9587313f 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -16,6 +16,7 @@
>   */
>  
>  #include <linux/rculist.h>
> +#include <linux/reboot.h>
>  #include <linux/slab.h>
>  #include "ima.h"
>  
> @@ -44,6 +45,12 @@ struct ima_h_table ima_htable = {
>   */
>  static DEFINE_MUTEX(ima_extend_list_mutex);
>  
> +/*
> + * Used internally by the kernel to suspend measurements.
> + * Protected by ima_extend_list_mutex.
> + */
> +static bool ima_measurements_suspended;
> +
>  /* lookup up the digest value in the hash table, and return the entry */
>  static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
>  						       int pcr)
> @@ -176,6 +183,17 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
>  		}
>  	}
>  
> +	/*
> +	 * ima_measurements_suspended will be set before the TPM subsystem has
> +	 * been shut down.
> +	 */
> +	if (ima_measurements_suspended) {
> +		audit_cause = "measurements_suspended";
> +		audit_info = 0;
> +		result = -ENODEV;
> +		goto out;
> +	}
> +
>  	result = ima_add_digest_entry(entry,
>  				      !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE));
>  	if (result < 0) {
> @@ -211,6 +229,31 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
>  	return result;
>  }
>  
> +static void ima_measurements_suspend(void)
> +{
> +	mutex_lock(&ima_extend_list_mutex);
> +	ima_measurements_suspended = true;
> +	mutex_unlock(&ima_extend_list_mutex);
> +}
> +
> +static int ima_reboot_notifier(struct notifier_block *nb,
> +			       unsigned long action,
> +			       void *data)
> +{
> +	ima_measurements_suspend();
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block ima_reboot_nb = {
> +	.notifier_call = ima_reboot_notifier,
> +};
> +
> +void __init ima_init_reboot_notifier(void)
> +{
> +	register_reboot_notifier(&ima_reboot_nb);
> +}
> +
>  int __init ima_init_digests(void)
>  {
>  	u16 digest_size;


Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>

BR, Jarkko
Mimi Zohar Nov. 12, 2024, 11:42 p.m. UTC | #2
On Tue, 2024-11-12 at 11:52 -0500, Stefan Berger wrote:
> To avoid the following types of error messages due to a failure by the TPM
> driver to use the TPM, suspend TPM PCR extensions and the appending of
> entries to the IMA log once IMA's reboot notifier has been called. This
> avoids trying to use the TPM after the TPM subsystem has been shut down.
> 
> [111707.685315][    T1] ima: Error Communicating to TPM chip, result: -19
> [111707.685960][    T1] ima: Error Communicating to TPM chip, result: -19
> 
> This error could be observed on a ppc64 machine running SuSE Linux where
> processes are still accessing files after devices have been shut down.
> 
> Suspending the IMA log and PCR extensions shortly before reboot does not
> seem to open a significant measurement gap since neither TPM quoting would
> work for attestation nor that new log entries could be written to anywhere
> after devices have been shut down. However, there's a time window between
> the invocation of the reboot notifier and the shutdown of devices in
> kernel_restart_prepare() where __usermodehelper_disable() waits for all
> running_helpers to exit. During this time window IMA could now miss log
> entries even though attestation would still work. The reboot of the system
> shortly after may make this small gap insignificant.
> 
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

Thanks, Stefan.  The patch looks good.  Based on the updated patch description,
I'm wondering if we should be testing the "system_state" instead of registering
a reboot notifier?

> 
> ---
>  v2:
>   - followed Mimi's suggestions
> 
> ---
>  security/integrity/ima/ima.h       |  1 +
>  security/integrity/ima/ima_init.c  |  2 ++
>  security/integrity/ima/ima_queue.c | 43 ++++++++++++++++++++++++++++++
>  3 files changed, 46 insertions(+)
> 
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 3c323ca213d4..3f1a82b7cd71 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -278,6 +278,7 @@ unsigned long ima_get_binary_runtime_size(void);
>  int ima_init_template(void);
>  void ima_init_template_list(void);
>  int __init ima_init_digests(void);
> +void __init ima_init_reboot_notifier(void);
>  int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
>  			  void *lsm_data);
>  
> diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
> index 4e208239a40e..a2f34f2d8ad7 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -152,6 +152,8 @@ int __init ima_init(void)
>  
>  	ima_init_key_queue();
>  
> +	ima_init_reboot_notifier();
> +
>  	ima_measure_critical_data("kernel_info", "kernel_version",
>  				  UTS_RELEASE, strlen(UTS_RELEASE), false,
>  				  NULL, 0);
> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
> index 532da87ce519..9b3c9587313f 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -16,6 +16,7 @@
>   */
>  
>  #include <linux/rculist.h>
> +#include <linux/reboot.h>
>  #include <linux/slab.h>
>  #include "ima.h"
>  
> @@ -44,6 +45,12 @@ struct ima_h_table ima_htable = {
>   */
>  static DEFINE_MUTEX(ima_extend_list_mutex);
>  
> +/*
> + * Used internally by the kernel to suspend measurements.
> + * Protected by ima_extend_list_mutex.
> + */
> +static bool ima_measurements_suspended;
> +
>  /* lookup up the digest value in the hash table, and return the entry */
>  static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
>  						       int pcr)
> @@ -176,6 +183,17 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
>  		}
>  	}
>  
> +	/*
> +	 * ima_measurements_suspended will be set before the TPM subsystem has
> +	 * been shut down.
> +	 */

The comment should indicate that the system itself is being shut down/rebooted
as well.

Mimi

> +	if (ima_measurements_suspended) {
> +		audit_cause = "measurements_suspended";
> +		audit_info = 0;
> +		result = -ENODEV;
> +		goto out;
> +	}
> +
>  	result = ima_add_digest_entry(entry,
>  				      !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE));
>  	if (result < 0) {
> @@ -211,6 +229,31 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
>  	return result;
>  }
>  
> +static void ima_measurements_suspend(void)
> +{
> +	mutex_lock(&ima_extend_list_mutex);
> +	ima_measurements_suspended = true;
> +	mutex_unlock(&ima_extend_list_mutex);
> +}
> +
> +static int ima_reboot_notifier(struct notifier_block *nb,
> +			       unsigned long action,
> +			       void *data)
> +{
> +	ima_measurements_suspend();
> +
> +	return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block ima_reboot_nb = {
> +	.notifier_call = ima_reboot_notifier,
> +};
> +
> +void __init ima_init_reboot_notifier(void)
> +{
> +	register_reboot_notifier(&ima_reboot_nb);
> +}
> +
>  int __init ima_init_digests(void)
>  {
>  	u16 digest_size;
Stefan Berger Nov. 13, 2024, 2:28 a.m. UTC | #3
On 11/12/24 6:42 PM, Mimi Zohar wrote:
> On Tue, 2024-11-12 at 11:52 -0500, Stefan Berger wrote:
>> To avoid the following types of error messages due to a failure by the TPM
>> driver to use the TPM, suspend TPM PCR extensions and the appending of
>> entries to the IMA log once IMA's reboot notifier has been called. This
>> avoids trying to use the TPM after the TPM subsystem has been shut down.
>>
>> [111707.685315][    T1] ima: Error Communicating to TPM chip, result: -19
>> [111707.685960][    T1] ima: Error Communicating to TPM chip, result: -19
>>
>> This error could be observed on a ppc64 machine running SuSE Linux where
>> processes are still accessing files after devices have been shut down.
>>
>> Suspending the IMA log and PCR extensions shortly before reboot does not
>> seem to open a significant measurement gap since neither TPM quoting would
>> work for attestation nor that new log entries could be written to anywhere
>> after devices have been shut down. However, there's a time window between
>> the invocation of the reboot notifier and the shutdown of devices in
>> kernel_restart_prepare() where __usermodehelper_disable() waits for all
>> running_helpers to exit. During this time window IMA could now miss log
>> entries even though attestation would still work. The reboot of the system
>> shortly after may make this small gap insignificant.
>>
>> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
> 
> Thanks, Stefan.  The patch looks good.  Based on the updated patch description,
> I'm wondering if we should be testing the "system_state" instead of registering
> a reboot notifier?

That's a possibility and would definitely be less code. I don't see why 
not...
Stefan Berger Nov. 13, 2024, 12:33 p.m. UTC | #4
On 11/12/24 9:28 PM, Stefan Berger wrote:
> 
> 
> On 11/12/24 6:42 PM, Mimi Zohar wrote:
>> On Tue, 2024-11-12 at 11:52 -0500, Stefan Berger wrote:
>>> To avoid the following types of error messages due to a failure by 
>>> the TPM
>>> driver to use the TPM, suspend TPM PCR extensions and the appending of
>>> entries to the IMA log once IMA's reboot notifier has been called. This
>>> avoids trying to use the TPM after the TPM subsystem has been shut down.
>>>
>>> [111707.685315][    T1] ima: Error Communicating to TPM chip, result: 
>>> -19
>>> [111707.685960][    T1] ima: Error Communicating to TPM chip, result: 
>>> -19
>>>
>>> This error could be observed on a ppc64 machine running SuSE Linux where
>>> processes are still accessing files after devices have been shut down.
>>>
>>> Suspending the IMA log and PCR extensions shortly before reboot does not
>>> seem to open a significant measurement gap since neither TPM quoting 
>>> would
>>> work for attestation nor that new log entries could be written to 
>>> anywhere
>>> after devices have been shut down. However, there's a time window 
>>> between
>>> the invocation of the reboot notifier and the shutdown of devices in
>>> kernel_restart_prepare() where __usermodehelper_disable() waits for all
>>> running_helpers to exit. During this time window IMA could now miss log
>>> entries even though attestation would still work. The reboot of the 
>>> system
>>> shortly after may make this small gap insignificant.
>>>
>>> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
>>> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
>>
>> Thanks, Stefan.  The patch looks good.  Based on the updated patch 
>> description,
>> I'm wondering if we should be testing the "system_state" instead of 
>> registering
>> a reboot notifier?
> 
> That's a possibility and would definitely be less code. I don't see why 
> not...
> 
... the missing synchronization with the mutex speaks against it. If we 
don't have it we could try to use the TPM subsystem after it's been shut 
down.
diff mbox series

Patch

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 3c323ca213d4..3f1a82b7cd71 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -278,6 +278,7 @@  unsigned long ima_get_binary_runtime_size(void);
 int ima_init_template(void);
 void ima_init_template_list(void);
 int __init ima_init_digests(void);
+void __init ima_init_reboot_notifier(void);
 int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event,
 			  void *lsm_data);
 
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 4e208239a40e..a2f34f2d8ad7 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -152,6 +152,8 @@  int __init ima_init(void)
 
 	ima_init_key_queue();
 
+	ima_init_reboot_notifier();
+
 	ima_measure_critical_data("kernel_info", "kernel_version",
 				  UTS_RELEASE, strlen(UTS_RELEASE), false,
 				  NULL, 0);
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 532da87ce519..9b3c9587313f 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -16,6 +16,7 @@ 
  */
 
 #include <linux/rculist.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include "ima.h"
 
@@ -44,6 +45,12 @@  struct ima_h_table ima_htable = {
  */
 static DEFINE_MUTEX(ima_extend_list_mutex);
 
+/*
+ * Used internally by the kernel to suspend measurements.
+ * Protected by ima_extend_list_mutex.
+ */
+static bool ima_measurements_suspended;
+
 /* lookup up the digest value in the hash table, and return the entry */
 static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
 						       int pcr)
@@ -176,6 +183,17 @@  int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 		}
 	}
 
+	/*
+	 * ima_measurements_suspended will be set before the TPM subsystem has
+	 * been shut down.
+	 */
+	if (ima_measurements_suspended) {
+		audit_cause = "measurements_suspended";
+		audit_info = 0;
+		result = -ENODEV;
+		goto out;
+	}
+
 	result = ima_add_digest_entry(entry,
 				      !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE));
 	if (result < 0) {
@@ -211,6 +229,31 @@  int ima_restore_measurement_entry(struct ima_template_entry *entry)
 	return result;
 }
 
+static void ima_measurements_suspend(void)
+{
+	mutex_lock(&ima_extend_list_mutex);
+	ima_measurements_suspended = true;
+	mutex_unlock(&ima_extend_list_mutex);
+}
+
+static int ima_reboot_notifier(struct notifier_block *nb,
+			       unsigned long action,
+			       void *data)
+{
+	ima_measurements_suspend();
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ima_reboot_nb = {
+	.notifier_call = ima_reboot_notifier,
+};
+
+void __init ima_init_reboot_notifier(void)
+{
+	register_reboot_notifier(&ima_reboot_nb);
+}
+
 int __init ima_init_digests(void)
 {
 	u16 digest_size;