blob: ee6bdb86799379e279d3365d006828ecdc4712f9 [file] [log] [blame]
/** @file LECmdLine.c
*
* Copyright (c) 2015-2018, 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 <Library/PartitionTableUpdate.h>
#include "LECmdLine.h"
#include <Library/MemoryAllocationLib.h>
/* verity command line related structures */
#define MAX_VERITY_CMD_LINE 512
#define MAX_VERITY_SECTOR_LEN 12
#define MAX_VERITY_HASH_LEN 65
STATIC CONST CHAR8 *VeritySystemPartitionStr = "/dev/mmcblk0p";
STATIC CONST CHAR8 *VerityName = "verity";
STATIC CONST CHAR8 *VerityAppliedOn = "system";
STATIC CONST CHAR8 *VerityEncriptionName = "sha256";
STATIC CONST CHAR8 *VeritySalt =
"aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7";
STATIC CONST CHAR8 *VerityBlockSize = "4096";
STATIC CONST CHAR8 *VerityRoot = "root=/dev/dm-0";
STATIC CONST CHAR8 *OptionalParam0 = "restart_on_corruption";
STATIC CONST CHAR8 *OptionalParam1 = "ignore_zero_blocks";
STATIC CONST CHAR8 *UseFec = "use_fec_from_device";
STATIC CONST CHAR8 *FecRoot = "fec_roots";
STATIC CONST CHAR8 *FecBlock = "fec_blocks";
STATIC CONST CHAR8 *FecStart = "fec_start";
#define FEATUREARGS 10
#if VERITY_LE
BOOLEAN IsLEVerity (VOID)
{
return TRUE;
}
#else
BOOLEAN IsLEVerity (VOID)
{
return FALSE;
}
#endif
/**
This function copies 'word' from a Null-terminated ASCII string
to another Null-terminated ASCII string with a maximum length,
And returns the size of a Null-terminated ASCII string in bytes,
including the Null terminator.
@param[in] String Pointer to a Null-terminated ASCII string.
@param[out] String Pointer to a Null-terminated ASCII string.
@param[out] UINT32* Number of bytes copied including NULL terminator.
0 if no 'word' found or error.
**/
STATIC EFI_STATUS
LEVerityWordnCpy ( CHAR8 *DstCmdLine,
UINT32 MaxLen,
CHAR8 *SrcCmdLine,
UINT32 *Len )
{
UINT32 Loop = 0;
EFI_STATUS Status = EFI_SUCCESS;
if ((DstCmdLine == NULL) ||
(SrcCmdLine == NULL)) {
*Len = 0;
Status = EFI_NOT_FOUND;
goto ErrWordnCpyOut;
}
if ((!MaxLen) &&
(MaxLen >= MAX_VERITY_CMD_LINE)) {
*Len = 0;
Status = EFI_BAD_BUFFER_SIZE;
goto ErrWordnCpyOut;
}
for (Loop = 0; Loop < MaxLen; Loop++) {
/* if space or NULL found, assign NULL, making it a string */
if ((SrcCmdLine[Loop]==' ') ||
(SrcCmdLine[Loop]=='\0')) {
DstCmdLine[Loop]='\0';
Loop++;
break;
}
else {
DstCmdLine[Loop]=SrcCmdLine[Loop];
if (Loop == (MaxLen - 1)) {
*Len = 0;
Status = EFI_NOT_FOUND;
goto ErrWordnCpyOut;
}
}
}
*Len = Loop;
ErrWordnCpyOut:
return Status;
}
/**
This function gets verity build time parameters passed in SourceCmdLine, and
constructs complete verity command line into LEVerityCmdLine.
@param[in] String Pointer to a Null-terminated ASCII string.
@param[out] String Pointer to a Null-terminated ASCII string.
@param[out] UINT32* String length of LEVerityCmdLine including NULL
terminator.
@retval EFI_SUCCESS Verity command line is constructed successfully.
@retval other Failed to construct Verity command line.
**/
EFI_STATUS
GetLEVerityCmdLine (CONST CHAR8 *SourceCmdLine,
CHAR8 **LEVerityCmdLine,
UINT32 *Len)
{
EFI_STATUS Status = EFI_SUCCESS;
CHAR8 *DMTemp = NULL;
UINT32 Length = 0;
CHAR8 *SectorSize = NULL;
CHAR8 *DataSize = NULL;
INT32 HashSize = 0;
CHAR8 *Hash = NULL;
CHAR8 *FecOff = NULL;
CHAR8 *DMDataStr = NULL;
BOOLEAN MultiSlotBoot = FALSE;
CHAR16 PartitionName[MAX_GPT_NAME_SIZE];
INT32 Index = 0;
/* Get verity command line from SourceCmdLine */
DMDataStr = AsciiStrStr (SourceCmdLine, "verity=");
if (DMDataStr != NULL) {
DMDataStr += AsciiStrLen ("verity=\"");
SectorSize = AllocateZeroPool (sizeof (CHAR8) * MAX_VERITY_SECTOR_LEN);
if (!SectorSize) {
DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SectorSize\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrLEVerityout;
}
/* Get Sector Size, Data Size, and Hash from verity specific command line */
Status = LEVerityWordnCpy ((CHAR8 *) &SectorSize[0],
MAX_VERITY_SECTOR_LEN, DMDataStr, &Length);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "GetLEVerityCmdLine: Sector Size error \n"));
goto ErrLEVerityout;
}
DMDataStr += Length;
DataSize = AllocateZeroPool (sizeof (CHAR8) * MAX_VERITY_SECTOR_LEN);
if (!DataSize) {
DEBUG ((EFI_D_ERROR, "Failed to allocate memory for DataSize\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrLEVerityout;
}
Status = LEVerityWordnCpy ((CHAR8 *) &DataSize[0],
MAX_VERITY_SECTOR_LEN, DMDataStr, &Length);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "GetLEVerityCmdLine: Data Size error \n"));
goto ErrLEVerityout;
}
DMDataStr += Length;
Hash = AllocateZeroPool (sizeof (CHAR8) * MAX_VERITY_HASH_LEN);
if (!Hash) {
DEBUG ((EFI_D_ERROR, "Failed to allocate memory for Hash\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrLEVerityout;
}
Status = LEVerityWordnCpy ((CHAR8 *) &Hash[0],
MAX_VERITY_HASH_LEN, DMDataStr, &Length);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "GetLEVerityCmdLine: Hash error \n"));
goto ErrLEVerityout;
}
DMDataStr += Length;
FecOff = AllocateZeroPool (sizeof (CHAR8) * MAX_VERITY_SECTOR_LEN);
if (!FecOff) {
DEBUG ((EFI_D_ERROR, "Failed to allocate memory for FecOff\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrLEVerityout;
}
Status = LEVerityWordnCpy ((CHAR8 *) &FecOff[0],
MAX_VERITY_SECTOR_LEN, DMDataStr, &Length);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "GetLEVerityCmdLine: Fec Offset error \n"));
goto ErrLEVerityout;
}
/* Get HashSize which is always greater by 8 bytes to DataSize */
HashSize = AsciiStrDecimalToUintn ((CHAR8 *) &DataSize[0]) + 8;
/* Get system partition index */
MultiSlotBoot = PartitionHasMultiSlot ((CONST CHAR16 *)L"boot");
StrnCpyS (PartitionName, MAX_GPT_NAME_SIZE, (CONST CHAR16 *)L"system",
StrLen ((CONST CHAR16 *)L"system"));
if (MultiSlotBoot) {
StrnCatS (PartitionName, MAX_GPT_NAME_SIZE,
GetCurrentSlotSuffix ().Suffix,
StrLen (GetCurrentSlotSuffix ().Suffix));
DEBUG ((EFI_D_VERBOSE, "Partition name:%s\n", PartitionName));
}
Index = GetPartitionIndex (PartitionName);
if (Index == INVALID_PTN) {
DEBUG ((EFI_D_ERROR,
"GetLEVerityCmdLine: System partition does not exist \n"));
Status = EFI_DEVICE_ERROR;
goto ErrLEVerityout;
}
DMTemp = AllocateZeroPool (sizeof (CHAR8) * MAX_VERITY_CMD_LINE);
if (!DMTemp) {
DEBUG ((EFI_D_ERROR, "Failed to allocate memory for DMTemp\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrLEVerityout;
}
/* Construct complete verity command line */
if (AsciiStrCmp (FecOff, "0") == 0) {
AsciiSPrint (
DMTemp,
MAX_VERITY_CMD_LINE,
" %a dm=\"%a none ro,0 %a %a 1 %a%d %a%d %a %a %a %d %a %a %a\"",
VerityRoot, VerityAppliedOn, SectorSize, VerityName,
VeritySystemPartitionStr, Index, VeritySystemPartitionStr, Index,
VerityBlockSize, VerityBlockSize, DataSize, HashSize, VerityEncriptionName,
Hash, VeritySalt
);
}
else {
AsciiSPrint (
DMTemp,
MAX_VERITY_CMD_LINE,
" %a dm=\"%a none ro,0 %a %a 1 %a%d %a%d %a %a %a %d %a %a %a %d %a %a %a %a%d %a 2 %a %a %a %a\"",
VerityRoot, VerityAppliedOn, SectorSize, VerityName,
VeritySystemPartitionStr, Index, VeritySystemPartitionStr, Index,
VerityBlockSize, VerityBlockSize, DataSize, HashSize, VerityEncriptionName,
Hash, VeritySalt, FEATUREARGS, OptionalParam0, OptionalParam1, UseFec,
VeritySystemPartitionStr, Index, FecRoot, FecBlock, FecOff, FecStart, FecOff
);
}
Length = AsciiStrLen (DMTemp) + 1; /* 1 extra byte for NULL */
*LEVerityCmdLine = AllocateZeroPool (Length);
if (!*LEVerityCmdLine) {
DEBUG ((EFI_D_ERROR, "LEVerityCmdLine buffer: Out of resources\n"));
Status = EFI_OUT_OF_RESOURCES;
goto ErrLEVerityout;
}
AsciiStrCpyS (*LEVerityCmdLine, Length, DMTemp);
*Len = Length;
DEBUG ((EFI_D_VERBOSE, "LEVerityCmdLine - %a - of length = %d \n",
*LEVerityCmdLine, *Len));
}
else {
DEBUG ((EFI_D_ERROR, "No verity command line found\n"));
Status = EFI_NOT_FOUND;
}
ErrLEVerityout:
if (SectorSize != NULL) {
FreePool (SectorSize);
SectorSize = NULL;
}
if (DataSize != NULL) {
FreePool (DataSize);
DataSize = NULL;
}
if (Hash != NULL) {
FreePool (Hash);
Hash = NULL;
}
if (FecOff != NULL) {
FreePool (FecOff);
FecOff = NULL;
}
if (DMTemp != NULL) {
FreePool (DMTemp);
DMTemp = NULL;
}
return Status;
}