QcomModulePkg: Separate boot image verification from BootLinux
Adding VerifiedBoot module to handle image verification.
Modularizing image verification to add next version of AVB.
Change-Id: I3ecaab8e1cd7c74d2bac962b20826c0d066674ea
diff --git a/QcomModulePkg/Library/avb/VerifiedBoot.c b/QcomModulePkg/Library/avb/VerifiedBoot.c
new file mode 100644
index 0000000..fa39200
--- /dev/null
+++ b/QcomModulePkg/Library/avb/VerifiedBoot.c
@@ -0,0 +1,353 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "VerifiedBoot.h"
+#include "BootLinux.h"
+#include <Library/VerifiedBootMenu.h>
+
+STATIC CONST CHAR8 *VerityMode = " androidboot.veritymode=";
+STATIC CONST CHAR8 *VerifiedState = " androidboot.verifiedbootstate=";
+STATIC CONST CHAR8 *KeymasterLoadState = " androidboot.keymaster=1";
+STATIC CONST CHAR8 *Space = " ";
+STATIC struct verified_boot_verity_mode VbVm[] =
+{
+ {FALSE, "logging"},
+ {TRUE, "enforcing"},
+};
+STATIC struct verified_boot_state_name VbSn[] =
+{
+ {GREEN, "green"},
+ {ORANGE, "orange"},
+ {YELLOW, "yellow"},
+ {RED, "red"},
+};
+
+struct boolean_string
+{
+ BOOLEAN value;
+ CHAR8 *name;
+};
+
+STATIC struct boolean_string BooleanString[] =
+{
+ {FALSE, "false"},
+ {TRUE, "true"}
+};
+
+UINT32 GetAVBVersion()
+{
+#if VERIFIED_BOOT
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+BOOLEAN VerifiedBootEnbled()
+{
+ return (GetAVBVersion() > NO_AVB);
+}
+
+STATIC EFI_STATUS AppendVBCmdLine(BootInfo *Info, CONST CHAR8 *Src)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ INT32 SrcLen = AsciiStrLen(Src);
+ CHAR8 *Dst = Info->VBCmdLine + Info->VBCmdLineFilledLen;
+ INT32 DstLen = Info->VBCmdLineLen - Info->VBCmdLineFilledLen;
+
+ GUARD(AsciiStrnCatS(Dst, DstLen, Src, SrcLen));
+ Info->VBCmdLineFilledLen += SrcLen;
+
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_STATUS AppendVBCommonCmdLine(BootInfo *Info)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ GUARD(AppendVBCmdLine(Info, VerityMode));
+ GUARD(AppendVBCmdLine(Info, VbVm[IsEnforcing()].name));
+ if (Info->VbIntf->Revision >= QCOM_VERIFIEDBOOT_PROTOCOL_REVISION) {
+ GUARD(AppendVBCmdLine(Info, VerifiedState));
+ GUARD(AppendVBCmdLine(Info, VbSn[Info->BootState].name));
+ }
+ GUARD(AppendVBCmdLine(Info, KeymasterLoadState));
+ GUARD(AppendVBCmdLine(Info, Space));
+ return EFI_SUCCESS;
+}
+
+STATIC EFI_STATUS VBCommonInit(BootInfo *Info)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ Info->BootState = RED;
+
+ Status = gBS->LocateProtocol(&gEfiQcomVerifiedBootProtocolGuid, NULL,
+ (VOID **)&(Info->VbIntf));
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_ERROR, "Unable to locate VB protocol: %r\n", Status));
+ return Status;
+ }
+ /* allocate VB command line*/
+ Info->VBCmdLine = AllocatePool(DTB_PAD_SIZE);
+ if (Info->VBCmdLine == NULL) {
+ DEBUG((EFI_D_ERROR, "VB CmdLine allocation failed!\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+ Info->VBCmdLineLen = DTB_PAD_SIZE;
+ Info->VBCmdLineFilledLen = 0;
+ Info->VBCmdLine[Info->VBCmdLineFilledLen] = '\0';
+
+ return Status;
+}
+
+STATIC EFI_STATUS LoadImageNoAuth(BootInfo *Info)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ if (Info->Images[0].ImageBuffer != NULL && Info->Images[0].ImageSize > 0) {
+ /* fastboot boot option image already loaded */
+ return Status;
+ }
+
+ Status = LoadImage(Info->Pname, (VOID **)&(Info->Images[0].ImageBuffer),
+ (UINT32 *)&(Info->Images[0].ImageSize));
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_ERROR,
+ "ERROR: Failed to load image from partition: %r\n", Status));
+ return EFI_LOAD_ERROR;
+ }
+ Info->NumLoadedImages = 1;
+ Info->Images[0].Name = AllocatePool(StrLen(Info->Pname) + 1);
+ UnicodeStrToAsciiStr(Info->Pname, Info->Images[0].Name);
+ return Status;
+}
+
+STATIC EFI_STATUS LoadImageAndAuthVB1(BootInfo *Info)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ CHAR8 StrPnameAscii[MAX_GPT_NAME_SIZE]; /* partition name starting with
+ / and no suffix */
+ CHAR8 PnameAscii[MAX_GPT_NAME_SIZE];
+ CHAR8 *SystemPath = NULL;
+ UINT32 SystemPathLen = 0;
+
+ GUARD(VBCommonInit(Info));
+ GUARD(LoadImageNoAuth(Info));
+
+ device_info_vb_t DevInfo_vb;
+ DevInfo_vb.is_unlocked = IsUnlocked();
+ DevInfo_vb.is_unlock_critical = IsUnlockCritical();
+ Status = Info->VbIntf->VBDeviceInit(Info->VbIntf,
+ (device_info_vb_t *)&DevInfo_vb);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_ERROR, "Error during VBDeviceInit: %r\n", Status));
+ return Status;
+ }
+
+ AsciiStrnCpyS(StrPnameAscii, ARRAY_SIZE(StrPnameAscii), "/", AsciiStrLen("/"));
+ UnicodeStrToAsciiStr(Info->Pname, PnameAscii);
+ if (Info->MultiSlotBoot) {
+ AsciiStrnCatS(StrPnameAscii, ARRAY_SIZE(StrPnameAscii), PnameAscii,
+ AsciiStrLen(PnameAscii) - (MAX_SLOT_SUFFIX_SZ - 1));
+ } else {
+ AsciiStrnCatS(StrPnameAscii, ARRAY_SIZE(StrPnameAscii),
+ PnameAscii, AsciiStrLen(PnameAscii));
+ }
+
+ Status = Info->VbIntf->VBVerifyImage(Info->VbIntf, (UINT8 *)StrPnameAscii,
+ (UINT8 *)Info->Images[0].ImageBuffer,
+ Info->Images[0].ImageSize,
+ &Info->BootState);
+ if (Status != EFI_SUCCESS || Info->BootState == BOOT_STATE_MAX) {
+ DEBUG((EFI_D_ERROR, "VBVerifyImage failed with: %r\n", Status));
+ return Status;
+ }
+
+ Status = Info->VbIntf->VBSendRot(Info->VbIntf);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_ERROR, "Error sending Rot : %r\n", Status));
+ return Status;
+ }
+
+ SystemPathLen = GetSystemPath(&SystemPath);
+ if (SystemPathLen == 0 || SystemPath == NULL) {
+ DEBUG((EFI_D_ERROR, "GetSystemPath failed!\n"));
+ return EFI_LOAD_ERROR;
+ }
+ GUARD(AppendVBCommonCmdLine(Info));
+ GUARD(AppendVBCmdLine(Info, SystemPath));
+
+ return Status;
+}
+
+STATIC EFI_STATUS DisplayVerifiedBootScreen(BootInfo *Info)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ CHAR8 FfbmStr[FFBM_MODE_BUF_SIZE] = {'\0'};
+
+ if (GetAVBVersion() < AVB_1) {
+ return EFI_SUCCESS;
+ }
+
+ if (!StrnCmp(Info->Pname, L"boot", StrLen(L"boot"))) {
+ Status = GetFfbmCommand(FfbmStr, FFBM_MODE_BUF_SIZE);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_VERBOSE,
+ "No Ffbm cookie found, ignore: %r\n", Status));
+ FfbmStr[0] = '\0';
+ }
+ }
+
+ DEBUG((EFI_D_VERBOSE, "Boot State is : %d\n", Info->BootState));
+ switch (Info->BootState) {
+ case RED:
+ DisplayVerifiedBootMenu(DISPLAY_MENU_RED);
+ MicroSecondDelay(5000000);
+ ShutdownDevice();
+ break;
+ case YELLOW:
+ DisplayVerifiedBootMenu(DISPLAY_MENU_YELLOW);
+ MicroSecondDelay(5000000);
+ break;
+ case ORANGE:
+ if (FfbmStr[0] == '\0') {
+ DisplayVerifiedBootMenu(DISPLAY_MENU_ORANGE);
+ MicroSecondDelay(5000000);
+ }
+ break;
+ default:
+ break;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS LoadImageAndAuth(BootInfo *Info)
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ BOOLEAN MdtpActive = FALSE;
+ QCOM_MDTP_PROTOCOL *MdtpProtocol;
+ UINT32 AVBVersion = NO_AVB;
+
+ if (Info == NULL) {
+ DEBUG((EFI_D_ERROR, "Invalid parameter Info\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* Get Partition Name*/
+ if (!Info->MultiSlotBoot) {
+ if (Info->BootIntoRecovery) {
+ DEBUG((EFI_D_INFO, "Booting Into Recovery Mode\n"));
+ StrnCpyS(Info->Pname, ARRAY_SIZE(Info->Pname),
+ L"recovery", StrLen(L"recovery"));
+ } else {
+ DEBUG((EFI_D_INFO, "Booting Into Mission Mode\n"));
+ StrnCpyS(Info->Pname, ARRAY_SIZE(Info->Pname), L"boot",
+ StrLen(L"boot"));
+ }
+ } else {
+ FindBootableSlot(Info->BootableSlot,
+ ARRAY_SIZE(Info->BootableSlot) - 1);
+ if (!Info->BootableSlot[0]) {
+ DEBUG((EFI_D_ERROR, "No bootable slot\n"));
+ return EFI_LOAD_ERROR;
+ }
+ StrnCpyS(Info->Pname, ARRAY_SIZE(Info->Pname),
+ Info->BootableSlot, StrLen(Info->BootableSlot));
+ }
+
+ DEBUG((EFI_D_VERBOSE, "MultiSlot %a, partition name %s\n",
+ BooleanString[Info->MultiSlotBoot].name, Info->Pname));
+
+ if (FixedPcdGetBool(EnableMdtpSupport)) {
+ Status = IsMdtpActive(&MdtpActive);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR,
+ "Failed to get activation state for MDTP, "
+ "Status=%r."
+ " Considering MDTP as active and continuing \n",
+ Status));
+ if (Status != EFI_NOT_FOUND)
+ MdtpActive = TRUE;
+ }
+ }
+
+ AVBVersion = GetAVBVersion();
+ DEBUG((EFI_D_VERBOSE, "AVB version %d\n", AVBVersion));
+
+ /* Load and Authenticate */
+ switch (AVBVersion) {
+ case NO_AVB:
+ return LoadImageNoAuth(Info);
+ break;
+ case AVB_1:
+ Status = LoadImageAndAuthVB1(Info);
+ break;
+ default:
+ DEBUG((EFI_D_ERROR, "Unsupported AVB version %d\n", AVBVersion));
+ Status = EFI_UNSUPPORTED;
+ }
+
+ // if MDTP is active Display Recovery UI
+ if (Status != EFI_SUCCESS && MdtpActive) {
+ Status = gBS->LocateProtocol(&gQcomMdtpProtocolGuid, NULL,
+ (VOID **)&MdtpProtocol);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR,
+ "Failed to locate MDTP protocol, Status=%r\n", Status));
+ return Status;
+ }
+ /* Perform Local Deactivation of MDTP */
+ Status = MdtpProtocol->MdtpDeactivate(MdtpProtocol, FALSE);
+ }
+
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_ERROR, "LoadImageAndAuth failed %r\n", Status));
+ return Status;
+ }
+
+ DisplayVerifiedBootScreen(Info);
+
+ DEBUG((EFI_D_VERBOSE, "Sending Milestone Call\n"));
+ Status = Info->VbIntf->VBSendMilestone(Info->VbIntf);
+ if (Status != EFI_SUCCESS) {
+ DEBUG((EFI_D_ERROR, "Error sending milestone call to TZ\n"));
+ return Status;
+ }
+
+ return Status;
+}
+
+VOID FreeVerifiedBootResource(BootInfo *Info)
+{
+ DEBUG((EFI_D_VERBOSE, "FreeVerifiedBootResource\n"));
+ if (Info->VBCmdLine != NULL) {
+ FreePool(Info->VBCmdLine);
+ }
+ return;
+}