[UEFI架构]必不可少的SecurityArch

[UEFI架构]必不可少的SecurityArch 在UEFI架构下gEfiSecurityArchProtocolGuid作为一个必须实现的ProtocolgEfiSecurity2ArchProtocolGuid作为一个Option Protocol首先看看SecurityStubDxe的驱动内容如何EFI_STATUS EFIAPI SecurityStubInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; // // Make sure the Security Architectural Protocol is not already installed in the system // ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, gEfiSecurity2ArchProtocolGuid); ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, gEfiSecurityArchProtocolGuid); // // Install the Security Architectural Protocol onto a new handle // Status gBS-InstallMultipleProtocolInterfaces ( mSecurityArchProtocolHandle, gEfiSecurity2ArchProtocolGuid, mSecurity2Stub, gEfiSecurityArchProtocolGuid, mSecurityStub, NULL ); ASSERT_EFI_ERROR (Status); Defer3rdPartyImageLoadInitialize ();驱动本体看起来比较简单安装gEfiSecurityArchProtocolGuid/gEfiSecurity2ArchProtocolGuid 两个 Protocol而Defer3rdPartyImageLoadInitialize中则会安装gEfiDeferredImageLoadProtocolGuid Protocol并且在DxeSmmReadyToLock中检查是否有第三方的Module在 EndOfDxe 到 SmmReadyToLock 这个时间段被执行过 如果有那么这个系统认定为不可信状态直接进入CpuDeadLoop不在继续启动了那一个正确的执行顺序应该是 EndOfDxe - SmmReadyToLock - 3rd Module;VOID Defer3rdPartyImageLoadInitialize ( VOID ) { EFI_STATUS Status; EFI_HANDLE Handle; EFI_EVENT Event; VOID *Registration; Handle NULL; Status gBS-InstallMultipleProtocolInterfaces ( Handle, gEfiDeferredImageLoadProtocolGuid, mDeferredImageLoad, NULL ); ASSERT_EFI_ERROR (Status); Status gBS-CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, EndOfDxe, NULL, gEfiEndOfDxeEventGroupGuid, Event ); ASSERT_EFI_ERROR (Status); EfiCreateProtocolNotifyEvent ( gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, DxeSmmReadyToLock, NULL, Registration ); } VOID EFIAPI DxeSmmReadyToLock ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *Interface; Status gBS-LocateProtocol (gEfiDxeSmmReadyToLockProtocolGuid, NULL, Interface); if (EFI_ERROR (Status)) { return; } gBS-CloseEvent (Event); if (mImageLoadedAfterEndOfDxe) { // // Platform should not dispatch the 3rd party images after signaling EndOfDxe event // but before publishing DxeSmmReadyToLock protocol. // DEBUG (( DEBUG_ERROR, [Security] 3rd party images must be dispatched after DxeSmmReadyToLock Protocol installation!\n )); REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE) ); ASSERT (FALSE); CpuDeadLoop (); } }我们继续看安装的gEfiSecurityArchProtocolGuid到底有什么作用EFI_STATUS EFIAPI SecurityStubAuthenticateState ( IN CONST EFI_SECURITY_ARCH_PROTOCOL *This, IN UINT32 AuthenticationStatus, IN CONST EFI_DEVICE_PATH_PROTOCOL *File ) { EFI_STATUS Status; Status ExecuteSecurity2Handlers ( EFI_AUTH_OPERATION_AUTHENTICATION_STATE, AuthenticationStatus, File, NULL, 0, FALSE ); if (Status EFI_SUCCESS) { Status ExecuteSecurityHandlers (AuthenticationStatus, File); } return Status; } ExecuteSecurity2Handlers ( IN UINT32 AuthenticationOperation, IN UINT32 AuthenticationStatus, IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL, IN VOID *FileBuffer, IN UINTN FileSize, IN BOOLEAN BootPolicy ) { ...... // // Directly return successfully when no handler is registered. // if (mNumberOfSecurity2Handler 0) { return EFI_SUCCESS; } // // Run security handler in same order to their registered list // for (Index 0; Index mNumberOfSecurity2Handler; Index) { // // If FileBuffer is not NULL, the input is Image, which will be handled by EFI_AUTH_IMAGE_OPERATION_MASK operation. // If FileBuffer is NULL, the input is not Image, which will be handled by EFI_AUTH_NONE_IMAGE_OPERATION_MASK operation. // Other cases are ignored. // if (((FileBuffer ! NULL) ((mSecurity2Table[Index].Security2Operation EFI_AUTH_IMAGE_OPERATION_MASK) ! 0)) || ((FileBuffer NULL) ((mSecurity2Table[Index].Security2Operation EFI_AUTH_NONE_IMAGE_OPERATION_MASK) ! 0))) { // // Execute registered handlers based on input AuthenticationOperation // if ((mSecurity2Table[Index].Security2Operation AuthenticationOperation) ! 0) { Status mSecurity2Table[Index].Security2Handler ( AuthenticationStatus, File, FileBuffer, FileSize, BootPolicy );从ExecuteSecurity2Handlers 中可以看到如果mNumberOfSecurity2Handler0则根据条件执行对应的mSecurity2Table[Index].Security2HandlerEFI_STATUS EFIAPI RegisterSecurity2Handler ( IN SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler, IN UINT32 AuthenticationOperation ) { EFI_STATUS Status; ASSERT (Security2Handler ! NULL); // // Make sure AuthenticationOperation is valid in the register order. // ASSERT (CheckAuthentication2Operation (mCurrentAuthOperation2, AuthenticationOperation)); mCurrentAuthOperation2 mCurrentAuthOperation2 | AuthenticationOperation; // // Check whether the handler lists is enough to store new handler. // if (mNumberOfSecurity2Handler mMaxNumberOfSecurity2Handler) { // // Allocate more resources for new handler. // Status ReallocateSecurity2HandlerTable (); ASSERT_EFI_ERROR (Status); } // // Register new handler into the handler list. // mSecurity2Table[mNumberOfSecurity2Handler].Security2Operation AuthenticationOperation; mSecurity2Table[mNumberOfSecurity2Handler].Security2Handler Security2Handler; mNumberOfSecurity2Handler; return EFI_SUCCESS; }mNumberOfSecurity2Handler 则通过 RegisterSecurity2Handler 调用会递增至于谁来调用RegisterSecurity2Handler暂时先放置一边先来看看谁调用SecurityArch Protocol 里边的FileAuthentication实际上在LoadImage的时候就调用了EFI_STATUS CoreLoadImageCommon ( IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, IN OUT UINTN *NumberOfPages OPTIONAL, OUT EFI_HANDLE *ImageHandle, OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, IN UINT32 Attribute ) { ...... if (gSecurity2 ! NULL) { // // Verify File Authentication through the Security2 Architectural Protocol // SecurityStatus gSecurity2-FileAuthentication ( gSecurity2, OriginalFilePath, FHand.Source, FHand.SourceSize, BootPolicy );在Defer3rdPartyImageLoad中有如果是 FV里边的Image则直接返回成功后边则会继续调用ExecuteSecurity2Handlers来处理if (FileFromFv (File)) { return EFI_SUCCESS; }那针对第三方驱动如果已经EndOfDxe了则也会返回成功后边则会继续调用ExecuteSecurity2Handlers来处理如果在EndOfDxe之前则通过QueueImage放置在mDeferred3rdPartyImage中并返回EFI_ACCESS_DENIED暂时不执行if (mEndOfDxe) { mImageLoadedAfterEndOfDxe TRUE; // // The image might be first time loaded after EndOfDxe, // So ImageInfo can be NULL. // if (ImageInfo ! NULL) { ImageInfo-Loaded TRUE; } return EFI_SUCCESS; } else { // // The image might be second time loaded before EndOfDxe, // So ImageInfo can be non-NULL. // if (ImageInfo NULL) { QueueImage (File, BootPolicy); } return EFI_ACCESS_DENIED; }那么3rdImage 什么时候执行 VOID EFIAPI PlatformBootManagerBeforeConsole ( VOID ) { ...... // // We cant signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers // the preparation of S3 system information. That logic has a hard dependency // on the presence of the FACS ACPI table. Since our ACPI tables are only // installed after PCI enumeration completes, we must not trigger the S3 save // earlier, hence we cant signal End-of-Dxe earlier. // EfiEventGroupSignal (gEfiEndOfDxeEventGroupGuid); ...... // // Prevent further changes to LockBoxes or SMRAM. // Any TPM 2 Physical Presence Interface opcode must be handled before. // Handle NULL; Status gBS-InstallProtocolInterface ( Handle, gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); // // Dispatch deferred images after EndOfDxe event and ReadyToLock // installation. // EfiBootManagerDispatchDeferredImages ();在Bds阶段PlatformBootManagerBeforeConsole 会首先执行 EndOfDxe 然后 SmmReadyToLock 这时才会执行3rdImage, EfiBootManagerDispatchDeferredImages 通过LoadImage - StartImage来执行那这个时候LoadImage仍然会调用SecurityArch Protocol 里边的FileAuthentication这时已经属于EndOfDxe了则会继续调用ExecuteSecurity2Handlers来处理总结1.LoadImage时会调用SecurityArch Protocol ExecuteSecurity2Handlers 可以用来针对Image进行一些安全机制相关的处理2.如果在EndOfDxe之前3rd Image则会保存到Deferred List 里边 最后调用顺序为 EndOfDxe - SmmReadyToLock - 3rd Image Start Image