public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
@ 2022-12-13 15:55 Lee, Chun-Yi
  2022-12-14  6:15 ` Gerd Hoffmann
  2022-12-14  6:53 ` Yao, Jiewen
  0 siblings, 2 replies; 8+ messages in thread
From: Lee, Chun-Yi @ 2022-12-13 15:55 UTC (permalink / raw)
  To: devel
  Cc: Min M Xu, Gerd Hoffmann, Jiewen Yao, Tom Lendacky,
	James Bottomley, Erdem Aktas, Lee, Chun-Yi

In the commit 4f173db8b4 "OvmfPkg/PlatformInitLib: Add functions for EmuVariableNvStore"
, it introduced a PlatformValidateNvVarStore() function for checking the
integrity of NvVarStore.

In some cases when the VariableHeader->StartId is VARIABLE_DATA, the VariableHeader->State
is not just one of the four primary states: VAR_IN_DELETED_TRANSITION, VAR_DELETED,
VAR_HEADER_VALID_ONLY, VAR_ADDED. The state may combined two or three
states, e.g.
    0x3C = (VAR_IN_DELETED_TRANSITION & VAR_ADDED) & VAR_DELETED
or
    0x3D = VAR_ADDED & VAR_DELETED

When the variable store has those variables, then system booting/rebooting will
hangs in a ASSERT:

NvVarStore Variable header State was invalid.
ASSERT
/mnt/working/source_code-git/edk2/OvmfPkg/Library/PlatformInitLib/Platform.c(819):
((BOOLEAN)(0==1))

Adding more log to UpdateVariable() and PlatformValidateNvVarStore(), we
can see there have some variables have 0x3C or 0x3D state in store.
e.g.

UpdateVariable(), VariableName=BootOrder
L1871, State=0000003F			<-- VAR_ADDED
State &= VAR_DELETED=0000003D
FlushHobVariableToFlash(), VariableName=BootOrder
...
UpdateVariable(), VariableName=InitialAttemptOrder
L1977, State=0000003F
State &= VAR_IN_DELETED_TRANSITION=0000003E
L2376, State=0000003E
State &= VAR_DELETED=0000003C
FlushHobVariableToFlash(), VariableName=InitialAttemptOrder
...
UpdateVariable(), VariableName=ConIn
L1977, State=0000003F
State &= VAR_IN_DELETED_TRANSITION=0000003E
L2376, State=0000003E
State &= VAR_DELETED=0000003C
FlushHobVariableToFlash(), VariableName=ConIn
...

So, only allowing the four primary states is not enough. This patch adds
two more combined states to the valid states list:

    (VAR_IN_DELETED_TRANSITION & VAR_ADDED) & VAR_DELETED = 0x3c

    VAR_ADDED & VAR_DELETED = 0x3d

Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
---
 OvmfPkg/Library/PlatformInitLib/Platform.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
index 77f22de046..2af4cefd10 100644
--- a/OvmfPkg/Library/PlatformInitLib/Platform.c
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -705,7 +705,9 @@ PlatformValidateNvVarStore (
       if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
             (VariableHeader->State == VAR_DELETED) ||
             (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
-            (VariableHeader->State == VAR_ADDED)))
+            (VariableHeader->State == VAR_ADDED) ||
+            (VariableHeader->State == (VAR_ADDED & VAR_DELETED)) ||
+            (VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION & VAR_DELETED))))
       {
         DEBUG ((DEBUG_ERROR, "NvVarStore Variable header State was invalid.\n"));
         return FALSE;
-- 
2.35.3


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

* Re: [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-13 15:55 [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases Lee, Chun-Yi
@ 2022-12-14  6:15 ` Gerd Hoffmann
  2022-12-14 13:46   ` [edk2-devel] " joeyli
  2022-12-14  6:53 ` Yao, Jiewen
  1 sibling, 1 reply; 8+ messages in thread
From: Gerd Hoffmann @ 2022-12-14  6:15 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: devel, Min M Xu, Jiewen Yao, Tom Lendacky, James Bottomley,
	Erdem Aktas, Lee, Chun-Yi

  Hi,

> When the variable store has those variables, then system booting/rebooting will
> hangs in a ASSERT:
> 
> NvVarStore Variable header State was invalid.
> ASSERT
> /mnt/working/source_code-git/edk2/OvmfPkg/Library/PlatformInitLib/Platform.c(819):
> ((BOOLEAN)(0==1))

I'm wondering how you manage to trigger this assert?

> Adding more log to UpdateVariable() and PlatformValidateNvVarStore(), we
> can see there have some variables have 0x3C or 0x3D state in store.
> e.g.

PlatformValidateNvVarStore() validates the varstore in ROM before
copying it to RAM.  The normal UpdateVariable() cycle changes the
copy in RAM ...

take care,
  Gerd


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

* Re: [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-13 15:55 [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases Lee, Chun-Yi
  2022-12-14  6:15 ` Gerd Hoffmann
@ 2022-12-14  6:53 ` Yao, Jiewen
  2022-12-14 15:05   ` [edk2-devel] " joeyli
  1 sibling, 1 reply; 8+ messages in thread
From: Yao, Jiewen @ 2022-12-14  6:53 UTC (permalink / raw)
  To: Lee, Chun-Yi, devel@edk2.groups.io
  Cc: Xu, Min M, Gerd Hoffmann, Tom Lendacky, James Bottomley,
	Aktas, Erdem, Lee, Chun-Yi

Hey
Good catch!

I think we need handle below valid cases:
1. VAR_HEADER_VALID_ONLY (0x7F) <-- Header added (*)
2. VAR_ADDED (0x3F) <-- Header + data added
3. VAR_ADDED & VAR_IN_DELETED_TRANSITION (0x3E) <-- marked as deleted, but still valid, before new data is added. (*)
4. VAR_ADDED & VAR_IN_DELETED_TRANSITION & VAR_DELETED (0x3C) <-- deleted, after new data is added.
5. VAR_ADDED & VAR_DELETED (0x3D) <-- deleted directly, without new data.
(*) means to support surprise shutdown.


For the patch:
>        if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
>              (VariableHeader->State == VAR_DELETED) ||
>              (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
> -            (VariableHeader->State == VAR_ADDED)))
> +            (VariableHeader->State == VAR_ADDED) ||
> +            (VariableHeader->State == (VAR_ADDED & VAR_DELETED)) ||
> +            (VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION & VAR_DELETED))))

I think:
A. If we allow (VAR_HEADER_VALID_ONLY), then we support surprise shutdown, we need also allow (VAR_ADDED & VAR_IN_DELETED_TRANSITION). It should be added as well.
B. The (VAR_IN_DELETED_TRANSITION) and (VAR_DELETED) are invalid state. They should be removed.
 
Would you please double check?




> -----Original Message-----
> From: Lee, Chun-Yi <joeyli.kernel@gmail.com>
> Sent: Tuesday, December 13, 2022 11:55 PM
> To: devel@edk2.groups.io
> Cc: Xu, Min M <min.m.xu@intel.com>; Gerd Hoffmann
> <kraxel@redhat.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>; James Bottomley <jejb@linux.ibm.com>;
> Aktas, Erdem <erdemaktas@google.com>; Lee, Chun-Yi <jlee@suse.com>
> Subject: [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of
> NvVarStore in some cases
> 
> In the commit 4f173db8b4 "OvmfPkg/PlatformInitLib: Add functions for
> EmuVariableNvStore"
> , it introduced a PlatformValidateNvVarStore() function for checking the
> integrity of NvVarStore.
> 
> In some cases when the VariableHeader->StartId is VARIABLE_DATA, the
> VariableHeader->State
> is not just one of the four primary states: VAR_IN_DELETED_TRANSITION,
> VAR_DELETED,
> VAR_HEADER_VALID_ONLY, VAR_ADDED. The state may combined two or
> three
> states, e.g.
>     0x3C = (VAR_IN_DELETED_TRANSITION & VAR_ADDED) & VAR_DELETED
> or
>     0x3D = VAR_ADDED & VAR_DELETED
> 
> When the variable store has those variables, then system booting/rebooting
> will
> hangs in a ASSERT:
> 
> NvVarStore Variable header State was invalid.
> ASSERT
> /mnt/working/source_code-
> git/edk2/OvmfPkg/Library/PlatformInitLib/Platform.c(819):
> ((BOOLEAN)(0==1))
> 
> Adding more log to UpdateVariable() and PlatformValidateNvVarStore(), we
> can see there have some variables have 0x3C or 0x3D state in store.
> e.g.
> 
> UpdateVariable(), VariableName=BootOrder
> L1871, State=0000003F			<-- VAR_ADDED
> State &= VAR_DELETED=0000003D
> FlushHobVariableToFlash(), VariableName=BootOrder
> ...
> UpdateVariable(), VariableName=InitialAttemptOrder
> L1977, State=0000003F
> State &= VAR_IN_DELETED_TRANSITION=0000003E
> L2376, State=0000003E
> State &= VAR_DELETED=0000003C
> FlushHobVariableToFlash(), VariableName=InitialAttemptOrder
> ...
> UpdateVariable(), VariableName=ConIn
> L1977, State=0000003F
> State &= VAR_IN_DELETED_TRANSITION=0000003E
> L2376, State=0000003E
> State &= VAR_DELETED=0000003C
> FlushHobVariableToFlash(), VariableName=ConIn
> ...
> 
> So, only allowing the four primary states is not enough. This patch adds
> two more combined states to the valid states list:
> 
>     (VAR_IN_DELETED_TRANSITION & VAR_ADDED) & VAR_DELETED = 0x3c
> 
>     VAR_ADDED & VAR_DELETED = 0x3d
> 
> Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
> ---
>  OvmfPkg/Library/PlatformInitLib/Platform.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c
> b/OvmfPkg/Library/PlatformInitLib/Platform.c
> index 77f22de046..2af4cefd10 100644
> --- a/OvmfPkg/Library/PlatformInitLib/Platform.c
> +++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
> @@ -705,7 +705,9 @@ PlatformValidateNvVarStore (
>        if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
>              (VariableHeader->State == VAR_DELETED) ||
>              (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
> -            (VariableHeader->State == VAR_ADDED)))
> +            (VariableHeader->State == VAR_ADDED) ||
> +            (VariableHeader->State == (VAR_ADDED & VAR_DELETED)) ||
> +            (VariableHeader->State == (VAR_ADDED &
> VAR_IN_DELETED_TRANSITION & VAR_DELETED))))
>        {
>          DEBUG ((DEBUG_ERROR, "NvVarStore Variable header State was
> invalid.\n"));
>          return FALSE;
> --
> 2.35.3


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

* Re: [edk2-devel] [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-14  6:15 ` Gerd Hoffmann
@ 2022-12-14 13:46   ` joeyli
  2022-12-14 14:12     ` Gerd Hoffmann
  2022-12-14 14:24     ` joeyli
  0 siblings, 2 replies; 8+ messages in thread
From: joeyli @ 2022-12-14 13:46 UTC (permalink / raw)
  To: devel, kraxel
  Cc: Lee, Chun-Yi, Min M Xu, Jiewen Yao, Tom Lendacky, James Bottomley,
	Erdem Aktas

Hi Gerd,

Thanks for your response! 

On Wed, Dec 14, 2022 at 07:15:28AM +0100, Gerd Hoffmann via groups.io wrote:
>   Hi,
> 
> > When the variable store has those variables, then system booting/rebooting will
> > hangs in a ASSERT:
> > 
> > NvVarStore Variable header State was invalid.
> > ASSERT
> > /mnt/working/source_code-git/edk2/OvmfPkg/Library/PlatformInitLib/Platform.c(819):
> > ((BOOLEAN)(0==1))
> 
> I'm wondering how you manage to trigger this assert?
>

Sorry for I forgot to put my testing environment in patch description.
My testing is on qemu with OVMF:

- edk2-master or edk2-stable202211
	build --verbose --debug=1 -D SECURE_BOOT_ENABLE -D TPM_ENABLE -D TPM_CONFIG_ENABLE \
	-D NETWORK_IP6_ENABLE -D NETWORK_HTTP_BOOT_ENABLE -a X64 -b DEBUG -t GCC5 \
	-p OvmfPkg/OvmfPkgX64.dsc -D FD_SIZE_4MB -D NETWORK_TLS_ENABLE 

- qemu-7.1.0 with libvirt-8.0.0
  pc-q35 with pflash type and nvram:
    <type arch='x86_64' machine='pc-q35-3.1'>hvm</type>
    <loader readonly='yes' secure='no' type='pflash'>/usr/share/qemu/ovmf-x86_64-code.bin</loader>
    <nvram template='/usr/share/qemu/ovmf-x86_64-vars.bin'>/var/lib/libvirt/qemu/nvram/opensuseTW_VARS.fd</nvram>
 
- grub2 2.06 and Linux kernel 6.1.0-rc5

Two test cases, both of them can reproduce the assert:

- First booting to grub2 menu, then "virsh destroy" the guest.
  The second boot hangs in the "NvVarStore Variable header State was invalid." assert

- First boot to Linux kernel 6.1.0-rc5, bash shell prompt shows up.
  Then run shutdown or reboot command.
  The second boot hangs in in the "NvVarStore Variable header State was invalid." assert 
 
> > Adding more log to UpdateVariable() and PlatformValidateNvVarStore(), we
> > can see there have some variables have 0x3C or 0x3D state in store.
> > e.g.
> 
> PlatformValidateNvVarStore() validates the varstore in ROM before
> copying it to RAM.  The normal UpdateVariable() cycle changes the
> copy in RAM ...
>

Yes, in the first boot, those variables have 0x3C or 0x3C state be
created. After shutdown or reboot, system hangs in the second boot.
The assert shows up in debug log.

Thanks a lot!
Joey Lee

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

* Re: [edk2-devel] [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-14 13:46   ` [edk2-devel] " joeyli
@ 2022-12-14 14:12     ` Gerd Hoffmann
  2022-12-14 15:24       ` joeyli
  2022-12-14 14:24     ` joeyli
  1 sibling, 1 reply; 8+ messages in thread
From: Gerd Hoffmann @ 2022-12-14 14:12 UTC (permalink / raw)
  To: joeyli
  Cc: devel, Lee, Chun-Yi, Min M Xu, Jiewen Yao, Tom Lendacky,
	James Bottomley, Erdem Aktas

> Sorry for I forgot to put my testing environment in patch description.
> My testing is on qemu with OVMF:
> 
> - edk2-master or edk2-stable202211
> 	build --verbose --debug=1 -D SECURE_BOOT_ENABLE -D TPM_ENABLE -D TPM_CONFIG_ENABLE \
> 	-D NETWORK_IP6_ENABLE -D NETWORK_HTTP_BOOT_ENABLE -a X64 -b DEBUG -t GCC5 \
> 	-p OvmfPkg/OvmfPkgX64.dsc -D FD_SIZE_4MB -D NETWORK_TLS_ENABLE 
> 
> - qemu-7.1.0 with libvirt-8.0.0
>   pc-q35 with pflash type and nvram:
>     <type arch='x86_64' machine='pc-q35-3.1'>hvm</type>
>     <loader readonly='yes' secure='no' type='pflash'>/usr/share/qemu/ovmf-x86_64-code.bin</loader>
>     <nvram template='/usr/share/qemu/ovmf-x86_64-vars.bin'>/var/lib/libvirt/qemu/nvram/opensuseTW_VARS.fd</nvram>

That is not secure.  You have unprotected writable flash.

You can either use a build with SMM_REQUIRE=TRUE and run with
secure='yes', so only the firmware in SMM mode can write to flash.

Or you run with both code and vars read-only.
Easiest is <loader>OVMF.fd</loader>.

Or you disable secure boot (SECURE_BOOT_ENABLE=FALSE) in your
builds.  You still have unprotected writable flash then, but
it isn't a security hole any more.  And the assert isn't triggered
either because that code path is only executed for secure boot
builds.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-14 13:46   ` [edk2-devel] " joeyli
  2022-12-14 14:12     ` Gerd Hoffmann
@ 2022-12-14 14:24     ` joeyli
  1 sibling, 0 replies; 8+ messages in thread
From: joeyli @ 2022-12-14 14:24 UTC (permalink / raw)
  To: devel, kraxel
  Cc: Lee, Chun-Yi, Min M Xu, Jiewen Yao, Tom Lendacky, James Bottomley,
	Erdem Aktas

Hi,

On Wed, Dec 14, 2022 at 09:46:36PM +0800, joeyli wrote:
> Hi Gerd,
> 
> Thanks for your response! 
> 
> On Wed, Dec 14, 2022 at 07:15:28AM +0100, Gerd Hoffmann via groups.io wrote:
> >   Hi,
> > 
> > > When the variable store has those variables, then system booting/rebooting will
> > > hangs in a ASSERT:
> > > 
> > > NvVarStore Variable header State was invalid.
> > > ASSERT
> > > /mnt/working/source_code-git/edk2/OvmfPkg/Library/PlatformInitLib/Platform.c(819):
> > > ((BOOLEAN)(0==1))
> > 
> > I'm wondering how you manage to trigger this assert?
> >
> 
> Sorry for I forgot to put my testing environment in patch description.
> My testing is on qemu with OVMF:
> 
> - edk2-master or edk2-stable202211
> 	build --verbose --debug=1 -D SECURE_BOOT_ENABLE -D TPM_ENABLE -D TPM_CONFIG_ENABLE \
> 	-D NETWORK_IP6_ENABLE -D NETWORK_HTTP_BOOT_ENABLE -a X64 -b DEBUG -t GCC5 \
> 	-p OvmfPkg/OvmfPkgX64.dsc -D FD_SIZE_4MB -D NETWORK_TLS_ENABLE 
> 
> - qemu-7.1.0 with libvirt-8.0.0
>   pc-q35 with pflash type and nvram:
>     <type arch='x86_64' machine='pc-q35-3.1'>hvm</type>
>     <loader readonly='yes' secure='no' type='pflash'>/usr/share/qemu/ovmf-x86_64-code.bin</loader>
>     <nvram template='/usr/share/qemu/ovmf-x86_64-vars.bin'>/var/lib/libvirt/qemu/nvram/opensuseTW_VARS.fd</nvram>
>  
> - grub2 2.06 and Linux kernel 6.1.0-rc5
>

I forgot shim-15.7, the fallback mechanism created new boot entry and
update bootorder in a new *_VARS.fd :

FSOpen: Open '\EFI\opensuse\boot.csv' Success
UpdateVariable() - Boot0003, 8BE4DF61-93CA-11D2-AA0D-00E098032B8C
FlushHobVariableToFlash() - Boot0003, 8BE4DF61-93CA-11D2-AA0D-00E098032B8C
UpdateVariable() - BootOrder, 8BE4DF61-93CA-11D2-AA0D-00E098032B8C 
L1870, State = 0x3F
State &= VAR_DELETED = 0x3D		<-- state of BootOrder
FlushHobVariableToFlash() - BootOrder, 8BE4DF61-93CA-11D2-AA0D-00E098032B8C

Joey Lee
 
> Two test cases, both of them can reproduce the assert:
> 
> - First booting to grub2 menu, then "virsh destroy" the guest.
>   The second boot hangs in the "NvVarStore Variable header State was invalid." assert
> 
> - First boot to Linux kernel 6.1.0-rc5, bash shell prompt shows up.
>   Then run shutdown or reboot command.
>   The second boot hangs in in the "NvVarStore Variable header State was invalid." assert 
>  
> > > Adding more log to UpdateVariable() and PlatformValidateNvVarStore(), we
> > > can see there have some variables have 0x3C or 0x3D state in store.
> > > e.g.
> > 
> > PlatformValidateNvVarStore() validates the varstore in ROM before
> > copying it to RAM.  The normal UpdateVariable() cycle changes the
> > copy in RAM ...
> >
> 
> Yes, in the first boot, those variables have 0x3C or 0x3C state be
> created. After shutdown or reboot, system hangs in the second boot.
> The assert shows up in debug log.
> 
> Thanks a lot!
> Joey Lee

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

* Re: [edk2-devel] [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-14  6:53 ` Yao, Jiewen
@ 2022-12-14 15:05   ` joeyli
  0 siblings, 0 replies; 8+ messages in thread
From: joeyli @ 2022-12-14 15:05 UTC (permalink / raw)
  To: devel, jiewen.yao
  Cc: Lee, Chun-Yi, Xu, Min M, Gerd Hoffmann, Tom Lendacky,
	James Bottomley, Aktas, Erdem

Hi Jiewen, 

Thanks for your response!

On Wed, Dec 14, 2022 at 06:53:42AM +0000, Yao, Jiewen via groups.io wrote:
> Hey
> Good catch!
> 
> I think we need handle below valid cases:
> 1. VAR_HEADER_VALID_ONLY (0x7F) <-- Header added (*)
> 2. VAR_ADDED (0x3F) <-- Header + data added
> 3. VAR_ADDED & VAR_IN_DELETED_TRANSITION (0x3E) <-- marked as deleted, but still valid, before new data is added. (*)
> 4. VAR_ADDED & VAR_IN_DELETED_TRANSITION & VAR_DELETED (0x3C) <-- deleted, after new data is added.
> 5. VAR_ADDED & VAR_DELETED (0x3D) <-- deleted directly, without new data.
> (*) means to support surprise shutdown.
>
> 
> For the patch:
> >        if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
> >              (VariableHeader->State == VAR_DELETED) ||
> >              (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
> > -            (VariableHeader->State == VAR_ADDED)))
> > +            (VariableHeader->State == VAR_ADDED) ||
> > +            (VariableHeader->State == (VAR_ADDED & VAR_DELETED)) ||
> > +            (VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION & VAR_DELETED))))
> 
> I think:
> A. If we allow (VAR_HEADER_VALID_ONLY), then we support surprise shutdown, we need also allow (VAR_ADDED & VAR_IN_DELETED_TRANSITION). It should be added as well.
> B. The (VAR_IN_DELETED_TRANSITION) and (VAR_DELETED) are invalid state. They should be removed.
>  
> Would you please double check?
>

I have followed your suggestion to change patch to add (VAR_ADDED & VAR_IN_DELETED_TRANSITION) and
removed (VAR_IN_DELETED_TRANSITION) and (VAR_DELETED). Like this:

Index: edk2/OvmfPkg/Library/PlatformInitLib/Platform.c
===================================================================
--- edk2.orig/OvmfPkg/Library/PlatformInitLib/Platform.c
+++ edk2/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -704,10 +704,11 @@ PlatformValidateNvVarStore (
       VariableOffset = NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
     } else {
         DEBUG ((DEBUG_ERROR, "VariableHeader->VendorGuid = %g, VariableHeader->State = 0x%x\n", VariableHeader->VendorGuid, VariableHeader->State));
-      if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||^M
-            (VariableHeader->State == VAR_DELETED) ||^M
-            (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||^M
-            (VariableHeader->State == VAR_ADDED)))^M
+      if (!((VariableHeader->State == VAR_HEADER_VALID_ONLY) ||^M
+           (VariableHeader->State == VAR_ADDED) ||^M
+           (VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) ||^M
+           (VariableHeader->State == (VAR_ADDED & VAR_DELETED)) ||^M
+           (VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION & VAR_DELETED))))^M
       {
         DEBUG ((DEBUG_ERROR, "NvVarStore Variable header State was invalid.\n"));
         return FALSE;

The above change works to me no my OVMF.

Thanks a lot!
Joey Lee
 
> 
> 
> 
> > -----Original Message-----
> > From: Lee, Chun-Yi <joeyli.kernel@gmail.com>
> > Sent: Tuesday, December 13, 2022 11:55 PM
> > To: devel@edk2.groups.io
> > Cc: Xu, Min M <min.m.xu@intel.com>; Gerd Hoffmann
> > <kraxel@redhat.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> > <thomas.lendacky@amd.com>; James Bottomley <jejb@linux.ibm.com>;
> > Aktas, Erdem <erdemaktas@google.com>; Lee, Chun-Yi <jlee@suse.com>
> > Subject: [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of
> > NvVarStore in some cases
> > 
> > In the commit 4f173db8b4 "OvmfPkg/PlatformInitLib: Add functions for
> > EmuVariableNvStore"
> > , it introduced a PlatformValidateNvVarStore() function for checking the
> > integrity of NvVarStore.
> > 
> > In some cases when the VariableHeader->StartId is VARIABLE_DATA, the
> > VariableHeader->State
> > is not just one of the four primary states: VAR_IN_DELETED_TRANSITION,
> > VAR_DELETED,
> > VAR_HEADER_VALID_ONLY, VAR_ADDED. The state may combined two or
> > three
> > states, e.g.
> >     0x3C = (VAR_IN_DELETED_TRANSITION & VAR_ADDED) & VAR_DELETED
> > or
> >     0x3D = VAR_ADDED & VAR_DELETED
> > 
> > When the variable store has those variables, then system booting/rebooting
> > will
> > hangs in a ASSERT:
> > 
> > NvVarStore Variable header State was invalid.
> > ASSERT
> > /mnt/working/source_code-
> > git/edk2/OvmfPkg/Library/PlatformInitLib/Platform.c(819):
> > ((BOOLEAN)(0==1))
> > 
> > Adding more log to UpdateVariable() and PlatformValidateNvVarStore(), we
> > can see there have some variables have 0x3C or 0x3D state in store.
> > e.g.
> > 
> > UpdateVariable(), VariableName=BootOrder
> > L1871, State=0000003F			<-- VAR_ADDED
> > State &= VAR_DELETED=0000003D
> > FlushHobVariableToFlash(), VariableName=BootOrder
> > ...
> > UpdateVariable(), VariableName=InitialAttemptOrder
> > L1977, State=0000003F
> > State &= VAR_IN_DELETED_TRANSITION=0000003E
> > L2376, State=0000003E
> > State &= VAR_DELETED=0000003C
> > FlushHobVariableToFlash(), VariableName=InitialAttemptOrder
> > ...
> > UpdateVariable(), VariableName=ConIn
> > L1977, State=0000003F
> > State &= VAR_IN_DELETED_TRANSITION=0000003E
> > L2376, State=0000003E
> > State &= VAR_DELETED=0000003C
> > FlushHobVariableToFlash(), VariableName=ConIn
> > ...
> > 
> > So, only allowing the four primary states is not enough. This patch adds
> > two more combined states to the valid states list:
> > 
> >     (VAR_IN_DELETED_TRANSITION & VAR_ADDED) & VAR_DELETED = 0x3c
> > 
> >     VAR_ADDED & VAR_DELETED = 0x3d
> > 
> > Signed-off-by: "Lee, Chun-Yi" <jlee@suse.com>
> > ---
> >  OvmfPkg/Library/PlatformInitLib/Platform.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c
> > b/OvmfPkg/Library/PlatformInitLib/Platform.c
> > index 77f22de046..2af4cefd10 100644
> > --- a/OvmfPkg/Library/PlatformInitLib/Platform.c
> > +++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
> > @@ -705,7 +705,9 @@ PlatformValidateNvVarStore (
> >        if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||
> >              (VariableHeader->State == VAR_DELETED) ||
> >              (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||
> > -            (VariableHeader->State == VAR_ADDED)))
> > +            (VariableHeader->State == VAR_ADDED) ||
> > +            (VariableHeader->State == (VAR_ADDED & VAR_DELETED)) ||
> > +            (VariableHeader->State == (VAR_ADDED &
> > VAR_IN_DELETED_TRANSITION & VAR_DELETED))))
> >        {
> >          DEBUG ((DEBUG_ERROR, "NvVarStore Variable header State was
> > invalid.\n"));
> >          return FALSE;
> > --
> > 2.35.3
> 
> 
> 
> 
> 

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

* Re: [edk2-devel] [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases
  2022-12-14 14:12     ` Gerd Hoffmann
@ 2022-12-14 15:24       ` joeyli
  0 siblings, 0 replies; 8+ messages in thread
From: joeyli @ 2022-12-14 15:24 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel, Lee, Chun-Yi, Min M Xu, Jiewen Yao, Tom Lendacky,
	James Bottomley, Erdem Aktas

On Wed, Dec 14, 2022 at 03:12:22PM +0100, Gerd Hoffmann wrote:
> > Sorry for I forgot to put my testing environment in patch description.
> > My testing is on qemu with OVMF:
> > 
> > - edk2-master or edk2-stable202211
> > 	build --verbose --debug=1 -D SECURE_BOOT_ENABLE -D TPM_ENABLE -D TPM_CONFIG_ENABLE \
> > 	-D NETWORK_IP6_ENABLE -D NETWORK_HTTP_BOOT_ENABLE -a X64 -b DEBUG -t GCC5 \
> > 	-p OvmfPkg/OvmfPkgX64.dsc -D FD_SIZE_4MB -D NETWORK_TLS_ENABLE 
> > 
> > - qemu-7.1.0 with libvirt-8.0.0
> >   pc-q35 with pflash type and nvram:
> >     <type arch='x86_64' machine='pc-q35-3.1'>hvm</type>
> >     <loader readonly='yes' secure='no' type='pflash'>/usr/share/qemu/ovmf-x86_64-code.bin</loader>
> >     <nvram template='/usr/share/qemu/ovmf-x86_64-vars.bin'>/var/lib/libvirt/qemu/nvram/opensuseTW_VARS.fd</nvram>
> 
> That is not secure.  You have unprotected writable flash.
> 
> You can either use a build with SMM_REQUIRE=TRUE and run with
> secure='yes', so only the firmware in SMM mode can write to flash.
> 
> Or you run with both code and vars read-only.
> Easiest is <loader>OVMF.fd</loader>.
>

Thanks for your suggestion! It's really helpful! I will try it.
 
> Or you disable secure boot (SECURE_BOOT_ENABLE=FALSE) in your
> builds.  You still have unprotected writable flash then, but
> it isn't a security hole any more.  And the assert isn't triggered
> either because that code path is only executed for secure boot
> builds.
>

Yes, before I produce the patch, I need to disable SECURE_BOOT_ENABLE
to workaround my VM hang problem.

IMHO, using "variable header State was invalid" assert to prevent user
writes to a unprotected flash is not a good idea. It causes some problem:

- User's existing virtual machine can not boot/reboot after updated to
  edk2-stable202211 OVMF. VM just hangs there and doesn't have any hint.

- The VM still works in the first boot. User doesn't know that second boot
  will hangs because they are writing an unprotected writable flash.

- Even enabled debug log, we don't know what does "NvVarStore Variable header
  State was invalid." mean.

Thanks
Joey Lee

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

end of thread, other threads:[~2022-12-14 15:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-12-13 15:55 [PATCH] OvmfPkg/PlatformInitLib: Fix integrity checking failed of NvVarStore in some cases Lee, Chun-Yi
2022-12-14  6:15 ` Gerd Hoffmann
2022-12-14 13:46   ` [edk2-devel] " joeyli
2022-12-14 14:12     ` Gerd Hoffmann
2022-12-14 15:24       ` joeyli
2022-12-14 14:24     ` joeyli
2022-12-14  6:53 ` Yao, Jiewen
2022-12-14 15:05   ` [edk2-devel] " joeyli

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