diff mbox series

efi_loader: allow disabling EFI secure boot in User Mode

Message ID 20201130145839.31620-1-pc@cjr.nz
State Rejected, archived
Delegated to: Heinrich Schuchardt
Headers show
Series efi_loader: allow disabling EFI secure boot in User Mode | expand

Commit Message

Paulo Alcantara Nov. 30, 2020, 2:58 p.m. UTC
Introduce a new config option CONFIG_EFI_SECURE_BOOT_VAR_DISABLE to
allow disabling EFI secure boot when the platform is operating in User
Mode and there is an NV+BS EFI variable called "SecureBootDisable".
Otherwise, keep it enabled by default.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
---
 lib/efi_loader/Kconfig          | 13 +++++++++
 lib/efi_loader/efi_var_common.c | 48 ++++++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 1 deletion(-)

Comments

Heinrich Schuchardt Nov. 30, 2020, 4:36 p.m. UTC | #1
On 11/30/20 3:58 PM, Paulo Alcantara wrote:
> Introduce a new config option CONFIG_EFI_SECURE_BOOT_VAR_DISABLE to
> allow disabling EFI secure boot when the platform is operating in User
> Mode and there is an NV+BS EFI variable called "SecureBootDisable".
> Otherwise, keep it enabled by default.

Hello Paulo,

could you, please, explain why this is needed.

You can simply delete PK if you want to disable secure boot.

Best regards

Heinrich

>
> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
> ---
>   lib/efi_loader/Kconfig          | 13 +++++++++
>   lib/efi_loader/efi_var_common.c | 48 ++++++++++++++++++++++++++++++++-
>   2 files changed, 60 insertions(+), 1 deletion(-)
>
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index 29ea14b2ee2a..d453905c7666 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -224,5 +224,18 @@ config EFI_SECURE_BOOT
>   	  Once SecureBoot mode is enforced, any EFI binary can run only if
>   	  it is signed with a trusted key. To do that, you need to install,
>   	  at least, PK, KEK and db.
> +	  Note that SecureBoot mode may no longer be enforced when
> +	  EFI_SECURE_BOOT_VAR_DISABLE option is enabled.
> +
> +config EFI_SECURE_BOOT_VAR_DISABLE
> +	bool "Permit to disable EFI secure boot when in User Mode"
> +	depends on EFI_SECURE_BOOT
> +	default n
> +	help
> +	  Select this option to allow disabling EFI secure boot when
> +	  the platform is operating in User Mode (e.g. PK is enrolled)
> +	  and there is an NV+BS EFI variable called
> +	  "SecureBootDisable". A platform reset is also required to
> +	  actually disable it.
>
>   endif
> diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
> index 1c7459266a38..89aa944180a4 100644
> --- a/lib/efi_loader/efi_var_common.c
> +++ b/lib/efi_loader/efi_var_common.c
> @@ -241,6 +241,48 @@ err:
>   	return ret;
>   }
>
> +
> +#ifdef CONFIG_EFI_SECURE_BOOT_VAR_DISABLE
> +/**
> + * efi_secure_boot_in_user_mode - check if secure boot enabled in User Mode
> + *
> + * @enabled: true if enabled, false if disabled
> + *
> + * Return: status code
> + */
> +static efi_status_t efi_secure_boot_in_user_mode(u8 *enabled)
> +{
> +	efi_status_t ret;
> +	efi_uintn_t size = 0;
> +	u32 attributes;
> +	u32 mask = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS;
> +
> +	ret = efi_get_variable_int(L"SecureBootDisable",
> +				   &efi_global_variable_guid,
> +				   &attributes, &size, NULL, NULL);
> +	if (ret == EFI_BUFFER_TOO_SMALL) {
> +		if (attributes ^ mask) {
> +			log_err("Unable to disable secure boot. Required attributes for SecureBootDisable variable: NV+BS\n");
> +			*enabled = 1;
> +		} else {
> +			EFI_PRINT("Disabling secure boot due to existing SecureBootDisable variable\n");
> +			*enabled = 0;
> +		}
> +		ret = EFI_SUCCESS;
> +	} else if (ret == EFI_NOT_FOUND) {
> +		*enabled = 1;
> +		ret = EFI_SUCCESS;
> +	}
> +	return ret;
> +}
> +#else
> +static efi_status_t efi_secure_boot_in_user_mode(u8 *enabled)
> +{
> +	*enabled = 1;
> +	return EFI_SUCCESS;
> +}
> +#endif
> +
>   /**
>    * efi_transfer_secure_state - handle a secure boot state transition
>    * @mode:	new state
> @@ -274,7 +316,11 @@ static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
>   		if (ret != EFI_SUCCESS)
>   			goto err;
>   	} else if (mode == EFI_MODE_USER) {
> -		ret = efi_set_secure_state(1, 0, 0, 0);
> +		u8 secure_boot;
> +		ret = efi_secure_boot_in_user_mode(&secure_boot);
> +		if (ret != EFI_SUCCESS)
> +			goto err;
> +		ret = efi_set_secure_state(secure_boot, 0, 0, 0);
>   		if (ret != EFI_SUCCESS)
>   			goto err;
>   	} else if (mode == EFI_MODE_SETUP) {
>
Paulo Alcantara Nov. 30, 2020, 6:22 p.m. UTC | #2
Hi Heinrich,

Heinrich Schuchardt <xypron.glpk@gmx.de> writes:

> On 11/30/20 3:58 PM, Paulo Alcantara wrote:
>> Introduce a new config option CONFIG_EFI_SECURE_BOOT_VAR_DISABLE to
>> allow disabling EFI secure boot when the platform is operating in User
>> Mode and there is an NV+BS EFI variable called "SecureBootDisable".
>> Otherwise, keep it enabled by default.
>
> could you, please, explain why this is needed.

I was just looking for an easier way to disable it without having to
mess with the secure boot variables and possibly breaking secure boot
altogether.  Of course, we could do the same by creating such
SecureBootDisable variable and forgetting about it.  Since we're gonna
provide u-boot package with the secure boot keys (PK, KEK, db, dbx)
enrolled in (ESP)/ubootefi.var (generated by efivar.py script), and
those certificates are only provided at build time, that would be tricky
to get it enabled or disabled by removing and inserting the PK, finding
the appropriate certificate depending on whether it is openSUSE or SLES.

For instance, OVMF does have something like that [1].

[1]
https://github.com/tianocore/edk2/blob/master/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c#L682

Thanks.
Heinrich Schuchardt Dec. 4, 2020, 2:23 a.m. UTC | #3
On 11/30/20 7:22 PM, Paulo Alcantara wrote:
> Hi Heinrich,
>
> Heinrich Schuchardt <xypron.glpk@gmx.de> writes:
>
>> On 11/30/20 3:58 PM, Paulo Alcantara wrote:
>>> Introduce a new config option CONFIG_EFI_SECURE_BOOT_VAR_DISABLE to
>>> allow disabling EFI secure boot when the platform is operating in User
>>> Mode and there is an NV+BS EFI variable called "SecureBootDisable".
>>> Otherwise, keep it enabled by default.
>>
>> could you, please, explain why this is needed.
>
> I was just looking for an easier way to disable it without having to
> mess with the secure boot variables and possibly breaking secure boot
> altogether.  Of course, we could do the same by creating such
> SecureBootDisable variable and forgetting about it.  Since we're gonna
> provide u-boot package with the secure boot keys (PK, KEK, db, dbx)
> enrolled in (ESP)/ubootefi.var (generated by efivar.py script), and
> those certificates are only provided at build time, that would be tricky
> to get it enabled or disabled by removing and inserting the PK, finding
> the appropriate certificate depending on whether it is openSUSE or SLES.
>
> For instance, OVMF does have something like that [1].
>
> [1]
> https://github.com/tianocore/edk2/blob/master/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c#L682
>
> Thanks.
>

Hello Paulo,

how would you stop an attacker from disabling secure boot on your device
and tempering with it if this configuration were enabled?

Best regard

Heinrich
Paulo Alcantara Dec. 4, 2020, 6 p.m. UTC | #4
Hi Heinrich,

Heinrich Schuchardt <xypron.glpk@gmx.de> writes:

> On 11/30/20 7:22 PM, Paulo Alcantara wrote:
>> Heinrich Schuchardt <xypron.glpk@gmx.de> writes:
>>
>>> On 11/30/20 3:58 PM, Paulo Alcantara wrote:
>>>> Introduce a new config option CONFIG_EFI_SECURE_BOOT_VAR_DISABLE to
>>>> allow disabling EFI secure boot when the platform is operating in User
>>>> Mode and there is an NV+BS EFI variable called "SecureBootDisable".
>>>> Otherwise, keep it enabled by default.
>>>
>>> could you, please, explain why this is needed.
>>
>> I was just looking for an easier way to disable it without having to
>> mess with the secure boot variables and possibly breaking secure boot
>> altogether.  Of course, we could do the same by creating such
>> SecureBootDisable variable and forgetting about it.  Since we're gonna
>> provide u-boot package with the secure boot keys (PK, KEK, db, dbx)
>> enrolled in (ESP)/ubootefi.var (generated by efivar.py script), and
>> those certificates are only provided at build time, that would be tricky
>> to get it enabled or disabled by removing and inserting the PK, finding
>> the appropriate certificate depending on whether it is openSUSE or SLES.
>>
>> For instance, OVMF does have something like that [1].
>>
>> [1]
>> https://github.com/tianocore/edk2/blob/master/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c#L682
>>
>> Thanks.
>>
> how would you stop an attacker from disabling secure boot on your device
> and tempering with it if this configuration were enabled?

Yep.  There isn't much we can do, and it is even unauthenticated.

Please ignore this patch.  Thanks!
diff mbox series

Patch

diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 29ea14b2ee2a..d453905c7666 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -224,5 +224,18 @@  config EFI_SECURE_BOOT
 	  Once SecureBoot mode is enforced, any EFI binary can run only if
 	  it is signed with a trusted key. To do that, you need to install,
 	  at least, PK, KEK and db.
+	  Note that SecureBoot mode may no longer be enforced when
+	  EFI_SECURE_BOOT_VAR_DISABLE option is enabled.
+
+config EFI_SECURE_BOOT_VAR_DISABLE
+	bool "Permit to disable EFI secure boot when in User Mode"
+	depends on EFI_SECURE_BOOT
+	default n
+	help
+	  Select this option to allow disabling EFI secure boot when
+	  the platform is operating in User Mode (e.g. PK is enrolled)
+	  and there is an NV+BS EFI variable called
+	  "SecureBootDisable". A platform reset is also required to
+	  actually disable it.
 
 endif
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
index 1c7459266a38..89aa944180a4 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -241,6 +241,48 @@  err:
 	return ret;
 }
 
+
+#ifdef CONFIG_EFI_SECURE_BOOT_VAR_DISABLE
+/**
+ * efi_secure_boot_in_user_mode - check if secure boot enabled in User Mode
+ *
+ * @enabled: true if enabled, false if disabled
+ *
+ * Return: status code
+ */
+static efi_status_t efi_secure_boot_in_user_mode(u8 *enabled)
+{
+	efi_status_t ret;
+	efi_uintn_t size = 0;
+	u32 attributes;
+	u32 mask = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS;
+
+	ret = efi_get_variable_int(L"SecureBootDisable",
+				   &efi_global_variable_guid,
+				   &attributes, &size, NULL, NULL);
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		if (attributes ^ mask) {
+			log_err("Unable to disable secure boot. Required attributes for SecureBootDisable variable: NV+BS\n");
+			*enabled = 1;
+		} else {
+			EFI_PRINT("Disabling secure boot due to existing SecureBootDisable variable\n");
+			*enabled = 0;
+		}
+		ret = EFI_SUCCESS;
+	} else if (ret == EFI_NOT_FOUND) {
+		*enabled = 1;
+		ret = EFI_SUCCESS;
+	}
+	return ret;
+}
+#else
+static efi_status_t efi_secure_boot_in_user_mode(u8 *enabled)
+{
+	*enabled = 1;
+	return EFI_SUCCESS;
+}
+#endif
+
 /**
  * efi_transfer_secure_state - handle a secure boot state transition
  * @mode:	new state
@@ -274,7 +316,11 @@  static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode)
 		if (ret != EFI_SUCCESS)
 			goto err;
 	} else if (mode == EFI_MODE_USER) {
-		ret = efi_set_secure_state(1, 0, 0, 0);
+		u8 secure_boot;
+		ret = efi_secure_boot_in_user_mode(&secure_boot);
+		if (ret != EFI_SUCCESS)
+			goto err;
+		ret = efi_set_secure_state(secure_boot, 0, 0, 0);
 		if (ret != EFI_SUCCESS)
 			goto err;
 	} else if (mode == EFI_MODE_SETUP) {