public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 1/1] SecurityPkg/DxeImageVerificationLib: Check result of GetEfiGlobalVariable2
@ 2023-02-27 12:55 Gerd Hoffmann
  2023-02-27 15:53 ` Marvin Häuser
  0 siblings, 1 reply; 4+ messages in thread
From: Gerd Hoffmann @ 2023-02-27 12:55 UTC (permalink / raw)
  To: devel
  Cc: Pawel Polawski, Jiewen Yao, Marvin Häuser, jmaloy, Min Xu,
	Jian J Wang, Oliver Steffen, Gerd Hoffmann

Call gRT->GetVariable() directly to read the SecureBoot variable.  It is
one byte in size so we can easily place it on the stack instead of
having GetEfiGlobalVariable2() allocate it for us, which avoids a few
possible error cases.

Skip secure boot checks if (and only if):

 (a) the SecureBoot variable is not present (EFI_NOT_FOUND) according to
     the return value, or
 (b) the SecureBoot variable was read successfully and is set to
     SECURE_BOOT_MODE_DISABLE.

Previously the code skipped the secure boot checks on *any*
gRT->GetVariable() error (GetEfiGlobalVariable2 sets the variable
value to NULL in that case) and also on memory allocation failures.

Fixes: CVE-2019-14560
Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=2167
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 .../DxeImageVerificationLib.c                      | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
index 66e2f5eaa3c0..f29a27e5a053 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -1671,7 +1671,8 @@ DxeImageVerificationHandler (
   EFI_IMAGE_EXECUTION_ACTION    Action;
   WIN_CERTIFICATE               *WinCertificate;
   UINT32                        Policy;
-  UINT8                         *SecureBoot;
+  UINT8                         SecureBoot;
+  UINTN                         SecureBootSize;
   PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
   UINT32                        NumberOfRvaAndSizes;
   WIN_CERTIFICATE_EFI_PKCS      *PkcsCertData;
@@ -1686,6 +1687,7 @@ DxeImageVerificationHandler (
   RETURN_STATUS                 PeCoffStatus;
   EFI_STATUS                    HashStatus;
   EFI_STATUS                    DbStatus;
+  EFI_STATUS                    VarStatus;
   BOOLEAN                       IsFound;
 
   SignatureList     = NULL;
@@ -1742,24 +1744,22 @@ DxeImageVerificationHandler (
     CpuDeadLoop ();
   }
 
-  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);
+  SecureBootSize = sizeof (SecureBoot);
+  VarStatus      = gRT->GetVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, NULL, &SecureBootSize, &SecureBoot);
   //
   // Skip verification if SecureBoot variable doesn't exist.
   //
-  if (SecureBoot == NULL) {
+  if (VarStatus == EFI_NOT_FOUND) {
     return EFI_SUCCESS;
   }
 
   //
   // Skip verification if SecureBoot is disabled but not AuditMode
   //
-  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
-    FreePool (SecureBoot);
+  if ((VarStatus == EFI_SUCCESS) && (SecureBoot == SECURE_BOOT_MODE_DISABLE)) {
     return EFI_SUCCESS;
   }
 
-  FreePool (SecureBoot);
-
   //
   // Read the Dos header.
   //
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/1] SecurityPkg/DxeImageVerificationLib: Check result of GetEfiGlobalVariable2
  2023-02-27 12:55 [PATCH 1/1] SecurityPkg/DxeImageVerificationLib: Check result of GetEfiGlobalVariable2 Gerd Hoffmann
@ 2023-02-27 15:53 ` Marvin Häuser
  2023-02-28  6:12   ` Gerd Hoffmann
  0 siblings, 1 reply; 4+ messages in thread
From: Marvin Häuser @ 2023-02-27 15:53 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: edk2-devel-groups-io, Pawel Polawski, Jiewen Yao, jmaloy, Min Xu,
	Jian J Wang, Oliver Steffen

*Thanks*, Gerd!

Two comments inline.

> On 27. Feb 2023, at 13:55, Gerd Hoffmann <kraxel@redhat.com> wrote:
> 
> Call gRT->GetVariable() directly to read the SecureBoot variable.  It is
> one byte in size so we can easily place it on the stack instead of
> having GetEfiGlobalVariable2() allocate it for us, which avoids a few
> possible error cases.
> 
> Skip secure boot checks if (and only if):
> 
> (a) the SecureBoot variable is not present (EFI_NOT_FOUND) according to
>     the return value, or

@Maintainers Would there be any objection to drop this and skip the SB checks only when explicitly disabled?
Please explicitly respond even if not, so we don't end up with everyone silently agreeing, but forgetting about the patch after. Thanks! :)

> (b) the SecureBoot variable was read successfully and is set to
>     SECURE_BOOT_MODE_DISABLE.
> 
> Previously the code skipped the secure boot checks on *any*
> gRT->GetVariable() error (GetEfiGlobalVariable2 sets the variable
> value to NULL in that case) and also on memory allocation failures.
> 
> Fixes: CVE-2019-14560
> Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=2167
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> .../DxeImageVerificationLib.c                      | 14 +++++++-------
> 1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
> index 66e2f5eaa3c0..f29a27e5a053 100644
> --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
> +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
> @@ -1671,7 +1671,8 @@ DxeImageVerificationHandler (
>   EFI_IMAGE_EXECUTION_ACTION    Action;
>   WIN_CERTIFICATE               *WinCertificate;
>   UINT32                        Policy;
> -  UINT8                         *SecureBoot;
> +  UINT8                         SecureBoot;
> +  UINTN                         SecureBootSize;
>   PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
>   UINT32                        NumberOfRvaAndSizes;
>   WIN_CERTIFICATE_EFI_PKCS      *PkcsCertData;
> @@ -1686,6 +1687,7 @@ DxeImageVerificationHandler (
>   RETURN_STATUS                 PeCoffStatus;
>   EFI_STATUS                    HashStatus;
>   EFI_STATUS                    DbStatus;
> +  EFI_STATUS                    VarStatus;
>   BOOLEAN                       IsFound;
> 
>   SignatureList     = NULL;
> @@ -1742,24 +1744,22 @@ DxeImageVerificationHandler (
>     CpuDeadLoop ();
>   }
> 
> -  GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);
> +  SecureBootSize = sizeof (SecureBoot);
> +  VarStatus      = gRT->GetVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, NULL, &SecureBootSize, &SecureBoot);
>   //
>   // Skip verification if SecureBoot variable doesn't exist.
>   //
> -  if (SecureBoot == NULL) {
> +  if (VarStatus == EFI_NOT_FOUND) {
>     return EFI_SUCCESS;
>   }
> 
>   //
>   // Skip verification if SecureBoot is disabled but not AuditMode
>   //
> -  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
> -    FreePool (SecureBoot);
> +  if ((VarStatus == EFI_SUCCESS) && (SecureBoot == SECURE_BOOT_MODE_DISABLE)) {

I would check the attributes here as well. They should be BS | RT, but explicitly not NV. This would force the SB checks in case a malicious actor somehow managed to store a persistent disable-value variable (be that a bug, physical access, or other means).

Best regards,
Marvin

>     return EFI_SUCCESS;
>   }
> 
> -  FreePool (SecureBoot);
> -
>   //
>   // Read the Dos header.
>   //
> -- 
> 2.39.2
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/1] SecurityPkg/DxeImageVerificationLib: Check result of GetEfiGlobalVariable2
  2023-02-27 15:53 ` Marvin Häuser
@ 2023-02-28  6:12   ` Gerd Hoffmann
  2023-02-28  8:47     ` Marvin Häuser
  0 siblings, 1 reply; 4+ messages in thread
From: Gerd Hoffmann @ 2023-02-28  6:12 UTC (permalink / raw)
  To: Marvin Häuser
  Cc: edk2-devel-groups-io, Pawel Polawski, Jiewen Yao, jmaloy, Min Xu,
	Jian J Wang, Oliver Steffen

  Hi,

> > (a) the SecureBoot variable is not present (EFI_NOT_FOUND) according to
> >     the return value, or
> 
> @Maintainers Would there be any objection to drop this and skip the SB checks only when explicitly disabled?
> Please explicitly respond even if not, so we don't end up with everyone silently agreeing, but forgetting about the patch after. Thanks! :)

I hold back v2, waiting for an answer here.

> > -  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
> > -    FreePool (SecureBoot);
> > +  if ((VarStatus == EFI_SUCCESS) && (SecureBoot == SECURE_BOOT_MODE_DISABLE)) {
> 
> I would check the attributes here as well. They should be BS | RT, but
> explicitly not NV. This would force the SB checks in case a malicious
> actor somehow managed to store a persistent disable-value variable (be
> that a bug, physical access, or other means).

Like this (incremental fixup)?

Do we have macros for variable attribute checking?
Havn't seen anything while skimming variable-related headers ...

take care,
  Gerd

diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
index f29a27e5a053..79c784f77ac8 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -1688,6 +1688,7 @@ DxeImageVerificationHandler (
   EFI_STATUS                    HashStatus;
   EFI_STATUS                    DbStatus;
   EFI_STATUS                    VarStatus;
+  UINT32                        VarAttr;
   BOOLEAN                       IsFound;
 
   SignatureList     = NULL;
@@ -1745,7 +1746,7 @@ DxeImageVerificationHandler (
   }
 
   SecureBootSize = sizeof (SecureBoot);
-  VarStatus      = gRT->GetVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, NULL, &SecureBootSize, &SecureBoot);
+  VarStatus      = gRT->GetVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &VarAttr, &SecureBootSize, &SecureBoot);
   //
   // Skip verification if SecureBoot variable doesn't exist.
   //
@@ -1756,7 +1757,12 @@ DxeImageVerificationHandler (
   //
   // Skip verification if SecureBoot is disabled but not AuditMode
   //
-  if ((VarStatus == EFI_SUCCESS) && (SecureBoot == SECURE_BOOT_MODE_DISABLE)) {
+  if ((VarStatus == EFI_SUCCESS) &&
+      !(VarAttr & EFI_VARIABLE_NON_VOLATILE) &&
+      (VarAttr & EFI_VARIABLE_BOOTSERVICE_ACCESS) &&
+      (VarAttr & EFI_VARIABLE_RUNTIME_ACCESS) &&
+      (SecureBoot == SECURE_BOOT_MODE_DISABLE))
+  {
     return EFI_SUCCESS;
   }
 


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/1] SecurityPkg/DxeImageVerificationLib: Check result of GetEfiGlobalVariable2
  2023-02-28  6:12   ` Gerd Hoffmann
@ 2023-02-28  8:47     ` Marvin Häuser
  0 siblings, 0 replies; 4+ messages in thread
From: Marvin Häuser @ 2023-02-28  8:47 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: edk2-devel-groups-io, Pawel Polawski, Jiewen Yao, jmaloy, Min Xu,
	Jian J Wang, Oliver Steffen

[-- Attachment #1: Type: text/plain, Size: 3541 bytes --]


> On 28. Feb 2023, at 07:12, Gerd Hoffmann <kraxel@redhat.com> wrote:
> 
>   Hi,
> 
>>> (a) the SecureBoot variable is not present (EFI_NOT_FOUND) according to
>>>    the return value, or
>> 
>> @Maintainers Would there be any objection to drop this and skip the SB checks only when explicitly disabled?
>> Please explicitly respond even if not, so we don't end up with everyone silently agreeing, but forgetting about the patch after. Thanks! :)
> 
> I hold back v2, waiting for an answer here.
> 
>>> -  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
>>> -    FreePool (SecureBoot);
>>> +  if ((VarStatus == EFI_SUCCESS) && (SecureBoot == SECURE_BOOT_MODE_DISABLE)) {
>> 
>> I would check the attributes here as well. They should be BS | RT, but
>> explicitly not NV. This would force the SB checks in case a malicious
>> actor somehow managed to store a persistent disable-value variable (be
>> that a bug, physical access, or other means).
> 
> Like this (incremental fixup)?

Sorry, I formulated it a bit vague - what I meant is that the attributes should be exactly BS | RT (i.e., equal to), but I see how adding it must not be NV sounds like it should be just those three Bits checked. Otherwise, yes, thanks a lot!

It’s a read-only status reporting variable, so even with future changes, setting any of the other attributes wouldn’t make much sense. BS | RT is what the spec currently dictates (there is a table here: https://uefi.org/specs/UEFI/2.10/03_Boot_Manager.html).

> 
> Do we have macros for variable attribute checking?
> Havn't seen anything while skimming variable-related headers ...

Don’t think so. Not sure there is much attribute-checking done to begin with outside VarCheckLib. The only stack I’ve seen doing this extensively is recent-years Mac EFI.

Best regards,
Marvin

> 
> take care,
>  Gerd
> 
> diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
> index f29a27e5a053..79c784f77ac8 100644
> --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
> +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
> @@ -1688,6 +1688,7 @@ DxeImageVerificationHandler (
>   EFI_STATUS                    HashStatus;
>   EFI_STATUS                    DbStatus;
>   EFI_STATUS                    VarStatus;
> +  UINT32                        VarAttr;
>   BOOLEAN                       IsFound;
> 
>   SignatureList     = NULL;
> @@ -1745,7 +1746,7 @@ DxeImageVerificationHandler (
>   }
> 
>   SecureBootSize = sizeof (SecureBoot);
> -  VarStatus      = gRT->GetVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, NULL, &SecureBootSize, &SecureBoot);
> +  VarStatus      = gRT->GetVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &VarAttr, &SecureBootSize, &SecureBoot);
>   //
>   // Skip verification if SecureBoot variable doesn't exist.
>   //
> @@ -1756,7 +1757,12 @@ DxeImageVerificationHandler (
>   //
>   // Skip verification if SecureBoot is disabled but not AuditMode
>   //
> -  if ((VarStatus == EFI_SUCCESS) && (SecureBoot == SECURE_BOOT_MODE_DISABLE)) {
> +  if ((VarStatus == EFI_SUCCESS) &&
> +      !(VarAttr & EFI_VARIABLE_NON_VOLATILE) &&
> +      (VarAttr & EFI_VARIABLE_BOOTSERVICE_ACCESS) &&
> +      (VarAttr & EFI_VARIABLE_RUNTIME_ACCESS) &&
> +      (SecureBoot == SECURE_BOOT_MODE_DISABLE))
> +  {
>     return EFI_SUCCESS;
>   }
> 
> 

[-- Attachment #2: Type: text/html, Size: 6691 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-02-28  8:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-27 12:55 [PATCH 1/1] SecurityPkg/DxeImageVerificationLib: Check result of GetEfiGlobalVariable2 Gerd Hoffmann
2023-02-27 15:53 ` Marvin Häuser
2023-02-28  6:12   ` Gerd Hoffmann
2023-02-28  8:47     ` Marvin Häuser

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox