On 2015-07-24 16:00:12, Laszlo Ersek wrote: > If OVMF was built with -D SMM_REQUIRE, that implies that the runtime OS is > not trusted and we should defend against it tampering with the firmware's > data. > > One such datum is the PEI firmware volume (PEIFV). Normally PEIFV is > decompressed on the first boot by SEC, then the OS preserves it across S3 > suspend-resume cycles; at S3 resume SEC just reuses the originally > decompressed PEIFV. > > However, if we don't trust the OS, then SEC must decompress PEIFV from the > pristine flash every time, lest we execute OS-injected code or work with > OS-injected data. > > Due to how FVMAIN_COMPACT is organized, we can't decompress just PEIFV; > the decompression brings DXEFV with itself, plus it uses a temporary > output buffer and a scratch buffer too, which even reach above the end of > the finally installed DXEFV. For this reason we must keep away a > non-malicious OS from DXEFV too, plus the memory up to > PcdOvmfDecomprScratchEnd. > > The delay introduced by the LZMA decompression on S3 resume is negligible.
I definitely don't think this is the best we could do here. We dicussed this a bit in irc back on April 23rd, and I was grasping for some alternative implementations. :) Unfortuntately, none of the ideas I had were nearly as easy as this, and thus this seems like a reasonable next step. > If -D SMM_REQUIRE is not specified, then PcdSmmSmramRequire remains FALSE > (from the DEC file), and then this patch has no effect (not counting some > changed debug messages). > > If QEMU doesn't support S3 (or the user disabled it on the QEMU command > line), then this patch has no effect also. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Laszlo Ersek <ler...@redhat.com> > --- > OvmfPkg/PlatformPei/PlatformPei.inf | 4 +++ > OvmfPkg/Sec/SecMain.inf | 3 +++ > OvmfPkg/PlatformPei/Fv.c | 27 +++++++++++++++++++- > OvmfPkg/PlatformPei/MemDetect.c | 11 +++++++- > OvmfPkg/Sec/SecMain.c | 18 ++++++++++--- > 5 files changed, 58 insertions(+), 5 deletions(-) > > diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf > b/OvmfPkg/PlatformPei/PlatformPei.inf > index cb7d7dd..b9b0b20 100644 > --- a/OvmfPkg/PlatformPei/PlatformPei.inf > +++ b/OvmfPkg/PlatformPei/PlatformPei.inf > @@ -75,6 +75,7 @@ [Pcd] > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize > gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId > + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecomprScratchEnd > gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3AcpiReservedMemorySize > gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress > gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize > @@ -87,6 +88,9 @@ [Pcd] > gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable > gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress > > +[FeaturePcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire > + > [Ppis] > gEfiPeiMasterBootModePpiGuid > > diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf > index 0bd9f83..c66c7fc 100644 > --- a/OvmfPkg/Sec/SecMain.inf > +++ b/OvmfPkg/Sec/SecMain.inf > @@ -68,3 +68,6 @@ [Pcd] > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize > gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecomprScratchEnd > + > +[FeaturePcd] > + gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire > diff --git a/OvmfPkg/PlatformPei/Fv.c b/OvmfPkg/PlatformPei/Fv.c > index 3ed775c..7a89acd 100644 > --- a/OvmfPkg/PlatformPei/Fv.c > +++ b/OvmfPkg/PlatformPei/Fv.c > @@ -32,6 +32,8 @@ PeiFvInitialization ( > VOID > ) > { > + BOOLEAN SecureS3Needed; > + > DEBUG ((EFI_D_INFO, "Platform PEI Firmware Volume Initialization\n")); > > // > @@ -50,16 +52,39 @@ PeiFvInitialization ( > // > BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 > (PcdOvmfDxeMemFvSize)); > > + SecureS3Needed = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire); > + > // > // Create a memory allocation HOB for the DXE FV. > // > + // If "secure" S3 is needed, then SEC will decompress both PEI and DXE > + // firmware volumes at S3 resume too, hence we need to keep away the OS > from > + // DXEFV as well. Otherwise we only need to keep away DXE itself from the > + // DXEFV area. > + // > BuildMemoryAllocationHob ( > PcdGet32 (PcdOvmfDxeMemFvBase), > PcdGet32 (PcdOvmfDxeMemFvSize), > - EfiBootServicesData > + SecureS3Needed ? EfiACPIMemoryNVS : EfiBootServicesData > ); > > // > + // Additionally, said decompression will use temporary memory above the end > + // of DXEFV, so let's keep away the OS from there too. > + // > + if (SecureS3Needed) { > + UINT32 DxeMemFvEnd; > + > + DxeMemFvEnd = PcdGet32 (PcdOvmfDxeMemFvBase) + > + PcdGet32 (PcdOvmfDxeMemFvSize); > + BuildMemoryAllocationHob ( > + DxeMemFvEnd, > + PcdGet32 (PcdOvmfDecomprScratchEnd) - DxeMemFvEnd, > + EfiACPIMemoryNVS > + ); > + } > + > + // > // Let PEI know about the DXE FV so it can find the DXE Core > // > PeiServicesInstallFvInfoPpi ( > diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c > index 612bb4a..649b484 100644 > --- a/OvmfPkg/PlatformPei/MemDetect.c > +++ b/OvmfPkg/PlatformPei/MemDetect.c > @@ -222,7 +222,16 @@ PublishPeiMemory ( > // > // Determine the range of memory to use during PEI > // > - MemoryBase = PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 > (PcdOvmfDxeMemFvSize); > + // Technically we could lay the permanent PEI RAM over SEC's temporary > + // decompression and scratch buffer even if "secure S3" is needed, since > + // their lifetimes don't overlap. However, PeiFvInitialization() will > cover > + // RAM up to PcdOvmfDecomprScratchEnd with an EfiACPIMemoryNVS memory > + // allocation HOB, and other allocations served from the permanent PEI > RAM > + // shouldn't overlap with that HOB. > + // > + MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ? > + PcdGet32 (PcdOvmfDecomprScratchEnd) : > + PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize); > MemorySize = LowerMemorySize - MemoryBase; > if (MemorySize > PeiMemoryCap) { > MemoryBase = LowerMemorySize - PeiMemoryCap; > diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c > index 348d2b3..99dd6db 100644 > --- a/OvmfPkg/Sec/SecMain.c > +++ b/OvmfPkg/Sec/SecMain.c > @@ -538,13 +538,25 @@ FindPeiCoreImageBase ( > OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase > ) > { > + BOOLEAN S3Resume; > + > *PeiCoreImageBase = 0; > > - if (IsS3Resume ()) { > - DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n")); > + S3Resume = IsS3Resume (); > + if (S3Resume && !FeaturePcdGet (PcdSmmSmramRequire)) { > + // > + // A malicious runtime OS may have injected something into our previously > + // decoded PEI FV, but we don't care about that unless SMM/SMRAM is > required. > + // > + DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume (insecure)\n")); How about instead: DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume\n")); and DEBUG ((EFI_D_VERBOSE, "SEC: S3 resume (with PEI decompression)\n")); Reviewed-by: Jordan Justen <jordan.l.jus...@intel.com> > GetS3ResumePeiFv (BootFv); > } else { > - DEBUG ((EFI_D_VERBOSE, "SEC: Normal boot\n")); > + // > + // We're either not resuming, or resuming "securely" -- we'll decompress > + // both PEI FV and DXE FV from pristine flash. > + // > + DEBUG ((EFI_D_VERBOSE, "SEC: %a\n", > + S3Resume ? "S3 resume (hopefully secure)" : "Normal boot")); > FindMainFv (BootFv); > > DecompressMemFvs (BootFv); > -- > 1.8.3.1 > > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel