On 10/17/17 21:07, Zmuda, Wojciech wrote: > Hi Laszlo, > > > Thanks for this detailed explanation. I repeated the experiment with EBC > interpreter included, this time stepping much further in the code, and I > actually can see that with Secure Boot enabled the EFI_SECURITY_VIOLATION > status is propagated, which does not let the image to load. With Secure Boot > disabled, I get early EFI_SUCCESS and the image is loaded, as far as I can > see in the debugger. Everything seems to work as designed, then. > > > I have one more question in this matter, if I may ask: why doesn't this path > terminate immediately after finding that the OptionROM is untrusted? It > wouldn't be executed anyway, with or without EBC interpreter, so why bother > with further checking?
"It wouldn't be executed anyway" is not correct -- please search my previous email (also visible below, in the context) for the following string: Trust() DXE Service You can read about that service in the PI spec, version 1.6, Volume 2, 7.3 Dispatcher Services. (It might not apply to files loaded from option ROMs -- but in general, considering the EFI_SECURITY_FILE_AUTHENTICATION_STATE member function's contract, promotion of the security status seems to be the point, after which gBS->StartImage() is expected to succeed. I guess!) I can't answer your question any better, so please talk to SecurityPkg maintainers if you'd like to see further details. Thanks! Laszlo > > > Thank you very much, > > Wojciech > > ________________________________ > From: Laszlo Ersek <[email protected]> > Sent: Monday, October 16, 2017 11:11:01 AM > To: Zmuda, Wojciech > Cc: [email protected] > Subject: Re: [edk2] SecurityPkg: untrusted OptionRom is loaded despite > DENY_EXECUTE_ON_SECURITY_VIOLATION set. > > On 10/16/17 18:57, Zmuda, Wojciech wrote: >> Hello, >> >> I'd like to ask you for help with understanding Secure Boot policy >> mechanism, specifically DENY_EXECUTE_ON_SECURITY_VIOLATION for >> PcdOptionRomImageVerificationPolicy. The OptionROM in my setup is >> loaded while, in my opinion, it should be rejected. >> >> I'm testing the following scenario: Secure Boot is enabled with my own >> PK and KEK enrolled, but with no db, to make sure nothing unsigned or >> signed by somebody else but me can be executed. A PCIe card with >> OptionROM (some EBC code) is installed. >> gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy is >> set to 0x04 in my platform's package. What I expect, is the OptionROM >> execution being denied, as it is not signed by my certificate. What I >> observe, on the other hand, is a message on the console, that no EBC >> interpreter is found, which suggest, that the OptionROM is loaded, >> just fails at the execution of EBC. The same message is printed when >> Secure Boot is disabled. >> >> I tried to understand the code by stepping through it in the DS-5. The >> following part of >> SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c >> seems suspicious to me: >> >> SecurityStatus = gSecurity->FileAuthenticationState ( >> gSecurity, >> AuthenticationStatus, >> OriginalFilePath >> ); >> } > > This code is not from "DxeImageVerificationLib.c"; it is from > CoreLoadImageCommon() in "MdeModulePkg/Core/Dxe/Image/Image.c". With > more context: > > } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) { > // > // Verify the Authentication Status through the Security Architectural > Protocol > // > SecurityStatus = gSecurity->FileAuthenticationState ( > gSecurity, > AuthenticationStatus, > OriginalFilePath > ); > } > >> >> // >> // Check Security Status. >> // >> if (EFI_ERROR (SecurityStatus) && SecurityStatus != >> EFI_SECURITY_VIOLATION) { >> if (SecurityStatus == EFI_ACCESS_DENIED) { >> // >> // Image was not loaded because the platform policy prohibits the >> image from being loaded. >> // It's the only place we could meet EFI_ACCESS_DENIED. >> // >> *ImageHandle = NULL; >> } >> Status = SecurityStatus; >> Image = NULL; >> goto Done; >> } >> >> The return code of gSecurity->FileAuthenticationState () (which is >> implemented in >> MdeModulePkg/Core/Dxe/Image/Image.c:DxeImageVerificationHandler ()), >> is EFI_SECURITY_VIOLATION. Such return code skips this if-statement, >> that prevents the image to be loaded. According to the comment in the >> if-statement: for the policy to be respected, >> gSecurity->FileAuthenticationState () should return EFI_ACCESS_DENIED. > > No, that's a different kind of "platform policy". > > The PCD that you mention is indeed platform policy, but only for > DxeImageVerificationLib. The platform policy being referred-to in this > comment is on the level of the gSecurity->FileAuthenticationState() > function call; and for that, we have to review the type definition of > the > > EFI_SECURITY_ARCH_PROTOCOL.FileAuthenticationState > > member function. The type name for this member function is > EFI_SECURITY_FILE_AUTHENTICATION_STATE, and it is defined in > "MdePkg/Include/Protocol/Security.h". > > I will not quote the entire description from said header file, just the > part that explains the difference: > >> @retval EFI_SECURITY_VIOLATION The file specified by File did not >> authenticate, and >> the platform policy dictates that File >> should be placed >> in the untrusted state. A file may be >> promoted from >> the untrusted to the trusted state at a >> future time >> with a call to the Trust() DXE Service. >> @retval EFI_ACCESS_DENIED The file specified by File did not >> authenticate, and >> the platform policy dictates that File >> should not be >> used for any purpose. > > Back to your email: > > On 10/16/17 18:57, Zmuda, Wojciech wrote: >> That being said, I stepped through DxeImageVerificationHandler (). The >> PCD with OptionROM policy is checked correctly. The function handles >> ALWAYS_EXECUTE and NEVER_EXECUTE policies properly and hangs on >> QUERY_USER_ and ALLOW_EXECUTE_ON_SECURITY_VIOLATION. This seems fine, >> however there is no code handling the >> DENY_EXECUTE_ON_SECURITY_VIOLATION (0x04) case. Stepping through this >> function shows that the image to be loaded cannot be found in the db >> (correct, as there's no db). Then, the function jumps to its very end >> and returns EFI_SECURITY_VIOLATION, which skips the aforementioned >> if-statement: >> >> Done: >> if (Status != EFI_SUCCESS) { >> // >> // Policy decides to defer or reject the image; add its information in >> image executable information table. >> // >> NameStr = ConvertDevicePathToText (File, FALSE, TRUE); >> AddImageExeInfo (Action, NameStr, File, SignatureList, >> SignatureListSize); >> if (NameStr != NULL) { >> DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", >> NameStr)); >> FreePool(NameStr); >> } >> Status = EFI_SECURITY_VIOLATION; >> } >> >> if (SignatureList != NULL) { >> FreePool (SignatureList); >> } >> >> return Status; >> } > > This quote is indeed from > "SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c", > and indeed the EFI_SECURITY_VIOLATION value returned by it causes the > "if" statement you quoted from "MdeModulePkg/Core/Dxe/Image/Image.c" to > be skipped. > > However, that's not the whole story. In > "MdeModulePkg/Core/Dxe/Image/Image.c", in the CoreLoadImageCommon() > function, track the "SecurityStatus" variable from the point where the > EFI_ACCESS_DENIED branch is *not* taken, to the end of the function. > Near the end of the function, "Status" is EFI_SUCCESS, and thus > "SecurityStatus" will be assigned to it (and the function will > ultimately return EFI_SECURITY_VIOLATION): > > Done: > // > // All done accessing the source file > // If we allocated the Source buffer, free it > // > if (FHand.FreeBuffer) { > CoreFreePool (FHand.Source); > } > if (OriginalFilePath != InputFilePath) { > CoreFreePool (OriginalFilePath); > } > > // > // There was an error. If there's an Image structure, free it > // > if (EFI_ERROR (Status)) { > if (Image != NULL) { > CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0)); > Image = NULL; > } > } else if (EFI_ERROR (SecurityStatus)) { > Status = SecurityStatus; > } > > // > // Track the return status from LoadImage. > // > if (Image != NULL) { > Image->LoadImageStatus = Status; > } > > return Status; > } > > Back to your email: > > On 10/16/17 18:57, Zmuda, Wojciech wrote: >> Is there anything I'm doing wrong trying to prevent untrusted >> OptionROM execution? If my understanding is correct, my case should >> make DxeImageVerificationHandler () return EFI_ACCESS_DENIED here. For >> example, in the snippet above, Status should be set to >> EFI_ACCESS_DENIED if Policy == DENY_EXECUTE_ON_SECURITY_VIOLATION. > > To me it seems like everything is working by design. The image is loaded > and the security violation is recorded. Please see the documentation of > the EFI_SECURITY_VIOLATION return code in the UEFI-2.7 spec, under > EFI_BOOT_SERVICES.LoadImage(): > > Image was loaded and an ImageHandle was created with a valid > EFI_LOADED_IMAGE_PROTOCOL.. However, the current platform policy > specifies that the image should not be started. > > (This section also has a pointer to "35.1.5 Deferred Execution".) > > > I believe the misunderstanding comes from the facts that > > (a) the message > > CoreLoadPeImage: There is no EBC interpreter for an EBC image. > > is printed by the CoreLoadPeImage() function, and > > (b) that CoreLoadImageCommon() calls CoreLoadPeImage() *between* the > EFI_ACCESS_DENIED check that you thought should have been taken -- which > is not the case -- and the final setting of Status to > EFI_SECURITY_VIOLATION (from "SecurityStatus"), which actually *would* > occur, if you had an EBC driver included in your platform firmware. > > > In other words, CoreLoadImageCommon() identifies (and prepares to > return) the EFI_SECURITY_VIOLATION status code, based on > PcdOptionRomImageVerificationPolicy. However, before the function could > finish processing (and return this error code), it comes across a more > severe error -- no EBC interpreter -- which takes priority both with and > without the Secure Boot operational mode. > > If you want to be completely sure, I suggest including the EBC > interpreter in your platform, and retesting. > > (Based on commit 81d9f86f8a71 ("ArmVirtPkg: enable EBC interpreter for > AArch64", 2016-07-29), adding the EBC interpreter should be easy.) > > Again, to me it looks like everything is working by design. > > Thanks > Laszlo > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

