Ejemplo n.º 1
0
/**
  Get variable header that has consecutive content.

  @param StoreInfo      Pointer to variable store info structure.
  @param Variable       Pointer to the Variable Header.
  @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.

  @retval TRUE          Variable header is valid.
  @retval FALSE         Variable header is not valid.

**/
BOOLEAN
GetVariableHeader (
  IN VARIABLE_STORE_INFO    *StoreInfo,
  IN VARIABLE_HEADER        *Variable,
  OUT VARIABLE_HEADER       **VariableHeader
  )
{
  EFI_PHYSICAL_ADDRESS  TargetAddress;
  EFI_PHYSICAL_ADDRESS  SpareAddress;
  EFI_HOB_GUID_TYPE     *GuidHob;
  UINTN                 PartialHeaderSize;

   //
   // First assume variable header pointed by Variable is consecutive.
   //
  *VariableHeader = Variable;

  if ((Variable != NULL) && (StoreInfo->FtwLastWriteData != NULL)) {
    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
    if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + sizeof (VARIABLE_HEADER)) > (UINTN) TargetAddress)) {
      //
      // Variable header pointed by Variable is inconsecutive,
      // create a guid hob to combine the two partial variable header content together.
      //
      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
      if (GuidHob != NULL) {
        *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
      } else {
        *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, sizeof (VARIABLE_HEADER));
        PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;
        //
        // Partial content is in NV storage.
        //
        CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);
        //
        // Another partial content is in spare block.
        //
        CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, sizeof (VARIABLE_HEADER) - PartialHeaderSize);
      }
    }
  }

  return IsValidVariableHeader (*VariableHeader);
}
Ejemplo n.º 2
0
/**
  This code gets the pointer to the next variable header.

  @param  Variable  Pointer to the Variable Header.

  @return  A VARIABLE_HEADER* pointer to next variable header.

**/
VARIABLE_HEADER *
GetNextVariablePtr (
    IN  VARIABLE_HEADER   *Variable
)
{
    UINTN Value;

    if (!IsValidVariableHeader (Variable)) {
        return NULL;
    }

    Value =  (UINTN) GetVariableDataPtr (Variable);
    Value += DataSizeOfVariable (Variable);
    Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));

    //
    // Be careful about pad size for alignment
    //
    return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
}
Ejemplo n.º 3
0
/**
  Process variable with key exchange key for verification.

  @param[in]  VariableName                The name of Variable to be found.
  @param[in]  VendorGuid                  The variable vendor GUID.
  @param[in]  Data                        The data pointer.
  @param[in]  DataSize                    The size of Data found. If size is less than the
                                          data, this value contains the required size.
  @param[in]  VirtualMode                 The current calling mode for this function.
  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
  @param[in]  Variable                    The variable information which is used to keep track of variable usage.
  @param[in]  Attributes                  The attribute value of the variable.

  @retval EFI_INVALID_PARAMETER           Invalid parameter.
  @retval EFI_SECURITY_VIOLATION          The variable did NOT pass the validation 
                                          check carried out by the firmware. 
  @retval EFI_SUCCESS                     The variable passed validation successfully.

**/
EFI_STATUS
ProcessVarWithKek (
  IN  CHAR16                               *VariableName,
  IN  EFI_GUID                             *VendorGuid,
  IN  VOID                                 *Data,
  IN  UINTN                                DataSize,
  IN  BOOLEAN                              VirtualMode,
  IN  ESAL_VARIABLE_GLOBAL                 *Global,
  IN  VARIABLE_POINTER_TRACK               *Variable,
  IN  UINT32                               Attributes OPTIONAL
  )
{
  EFI_STATUS                      Status;
  VARIABLE_POINTER_TRACK          KekVariable;
  EFI_SIGNATURE_LIST              *KekList;
  EFI_SIGNATURE_DATA              *KekItem;
  UINT32                          KekCount;
  EFI_VARIABLE_AUTHENTICATION     *CertData;
  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
  BOOLEAN                         IsFound;
  UINT32                          Index;
  VARIABLE_HEADER                 VariableHeader;
  BOOLEAN                         Valid;

  KekList = NULL;
  ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER));

  if (mPlatformMode == USER_MODE) {
    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
      //
      // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
      //
      return EFI_INVALID_PARAMETER;
    }

    CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
    CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
    if (Variable->CurrPtr != 0x0) {
      Valid = IsValidVariableHeader (
                Variable->CurrPtr, 
                Variable->Volatile, 
                &Global->VariableGlobal[VirtualMode], 
                Global->FvbInstance, 
                &VariableHeader
                );
      ASSERT (Valid);

      if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
        //
        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
        //
        return EFI_SECURITY_VIOLATION;
      }
    }
    //
    // Get KEK database from variable.
    //
    Status = FindVariable (
               Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY], 
               Global->GlobalVariableGuid[VirtualMode], 
               &KekVariable, 
               &Global->VariableGlobal[VirtualMode],
               Global->FvbInstance
               );
    ASSERT_EFI_ERROR (Status);

    ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
    GetVariableDataPtr (
      KekVariable.CurrPtr,
      KekVariable.Volatile,
      &Global->VariableGlobal[VirtualMode],
      Global->FvbInstance,
      (CHAR16 *) Global->KeyList
      );
    //
    // Enumerate all Kek items in this list to verify the variable certificate data.
    // If anyone is authenticated successfully, it means the variable is correct!
    //
    KekList   = (EFI_SIGNATURE_LIST *) Global->KeyList;
    IsFound   = FALSE;
    KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
    KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
    for (Index = 0; Index < KekCount; Index++) {
      if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
        IsFound = TRUE;
        break;
      }
      KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
    }

    if (!IsFound) {
      return EFI_SECURITY_VIOLATION;
    }

    Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);
    if (!EFI_ERROR (Status)) {
      Status = UpdateVariable (
                 VariableName, 
                 VendorGuid, 
                 (UINT8*)Data + AUTHINFO_SIZE, 
                 DataSize - AUTHINFO_SIZE, 
                 Attributes, 
                 0, 
                 CertData->MonotonicCount, 
                 VirtualMode,
                 Global,
                 Variable
                 );
    }
  } else {
    //
    // If in setup mode, no authentication needed.
    //
    Status = UpdateVariable (
               VariableName, 
               VendorGuid, 
               Data, 
               DataSize, 
               Attributes, 
               0, 
               0, 
               VirtualMode,
               Global,
               Variable
               );
  }

  return Status;
}
Ejemplo n.º 4
0
/**
  Process variable with platform key for verification.

  @param[in]  VariableName                The name of Variable to be found.
  @param[in]  VendorGuid                  The variable vendor GUID.
  @param[in]  Data                        The data pointer.
  @param[in]  DataSize                    The size of Data found. If size is less than the
                                          data, this value contains the required size.
  @param[in]  VirtualMode                 The current calling mode for this function.
  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
  @param[in]  Variable                    The variable information which is used to keep track of variable usage.
  @param[in]  Attributes                  The attribute value of the variable.
  @param[in]  IsPk                        Indicates whether to process pk.

  @retval EFI_INVALID_PARAMETER           Invalid parameter.
  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation 
                                          check carried out by the firmware. 
  @retval EFI_SUCCESS                     The variable passed validation successfully.

**/
EFI_STATUS
ProcessVarWithPk (
  IN  CHAR16                    *VariableName,
  IN  EFI_GUID                  *VendorGuid,
  IN  VOID                      *Data,
  IN  UINTN                     DataSize,
  IN  BOOLEAN                   VirtualMode,
  IN  ESAL_VARIABLE_GLOBAL      *Global,
  IN  VARIABLE_POINTER_TRACK    *Variable,
  IN  UINT32                    Attributes OPTIONAL,
  IN  BOOLEAN                   IsPk
  )
{
  EFI_STATUS                  Status;
  VARIABLE_POINTER_TRACK      PkVariable;
  EFI_SIGNATURE_LIST          *OldPkList;
  EFI_SIGNATURE_DATA          *OldPkData;
  EFI_VARIABLE_AUTHENTICATION *CertData;
  VARIABLE_HEADER             VariableHeader;
  BOOLEAN                     Valid;

  OldPkList = NULL;
  ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER));

  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
    //
    // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
    //
    return EFI_INVALID_PARAMETER;
  }

  if (mPlatformMode == USER_MODE) {
    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
      //
      // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
      //
      return EFI_INVALID_PARAMETER;
    }

    CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;

    if (Variable->CurrPtr != 0x0) {
      Valid = IsValidVariableHeader (
                Variable->CurrPtr, 
                Variable->Volatile, 
                &Global->VariableGlobal[VirtualMode], 
                Global->FvbInstance, 
                &VariableHeader
                );
      ASSERT (Valid);

      if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
        //
        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
        //
        return EFI_SECURITY_VIOLATION;
      }
    }
    //
    // Get platform key from variable.
    //
    Status = FindVariable (
               Global->VariableName[VirtualMode][VAR_PLATFORM_KEY], 
               Global->GlobalVariableGuid[VirtualMode], 
               &PkVariable, 
               &Global->VariableGlobal[VirtualMode],
               Global->FvbInstance
               );
    ASSERT_EFI_ERROR (Status);

    ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
    GetVariableDataPtr (
      PkVariable.CurrPtr,
      PkVariable.Volatile,
      &Global->VariableGlobal[VirtualMode],
      Global->FvbInstance,
      (CHAR16 *) Global->KeyList
      );

    OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;
    OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
    Status    = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);
    if (!EFI_ERROR (Status)) {
      Status = UpdateVariable (
                 VariableName, 
                 VendorGuid, 
                 (UINT8*)Data + AUTHINFO_SIZE, 
                 DataSize - AUTHINFO_SIZE, 
                 Attributes, 
                 0, 
                 CertData->MonotonicCount, 
                 VirtualMode, 
                 Global,
                 Variable
                 );

      if (!EFI_ERROR (Status)) {
        //
        // If delete PK in user mode, need change to setup mode.
        //
        if ((DataSize == AUTHINFO_SIZE) && IsPk) {
          UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);
        }
      }
    }
  } else {
    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);
    //
    // If enroll PK in setup mode, need change to user mode.
    //
    if ((DataSize != 0) && IsPk) {
      UpdatePlatformMode (VirtualMode, Global, USER_MODE);
    }
  }

  return Status;
}
Ejemplo n.º 5
0
/**
  Initializes for authenticated varibale service.

  @retval EFI_SUCCESS           The function successfully executed.
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate enough memory resources.

**/
EFI_STATUS
AutenticatedVariableServiceInitialize (
  VOID
  )
{
  EFI_STATUS              Status;
  VARIABLE_POINTER_TRACK  Variable;
  UINT8                   VarValue;
  UINT32                  VarAttr;
  UINTN                   DataSize;
  UINTN                   CtxSize;
  VARIABLE_HEADER         VariableHeader;
  BOOLEAN                 Valid;

  ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER));

  mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;
  mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical]     = &gEfiCertRsa2048Sha256Guid;
  mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;

  //
  // Initialize hash context.
  //
  CtxSize   = Sha256GetContextSize ();
  mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);
  ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);
  //
  // Check "AuthVarKeyDatabase" variable's existence. 
  // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. 
  //
  Status = FindVariable (
             mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], 
             &gEfiAuthenticatedVariableGuid, 
             &Variable, 
             &mVariableModuleGlobal->VariableGlobal[Physical],
             mVariableModuleGlobal->FvbInstance
             );

  if (Variable.CurrPtr == 0x0) {
    VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    VarValue      = 0;
    mPubKeyNumber = 0;
    Status        = UpdateVariable (
                      mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
                      &gEfiAuthenticatedVariableGuid,
                      &VarValue,
                      sizeof(UINT8),
                      VarAttr,
                      0,
                      0,
                      FALSE,
                      mVariableModuleGlobal,
                      &Variable
                      );
    if (EFI_ERROR (Status)) {
      return Status;
    }
  } else {
    //
    // Load database in global variable for cache.
    //
    Valid = IsValidVariableHeader (
              Variable.CurrPtr, 
              Variable.Volatile, 
              &mVariableModuleGlobal->VariableGlobal[Physical], 
              mVariableModuleGlobal->FvbInstance, 
              &VariableHeader
              );
    ASSERT (Valid);

    DataSize  = DataSizeOfVariable (&VariableHeader);
    ASSERT (DataSize <= MAX_KEYDB_SIZE);
    GetVariableDataPtr (
      Variable.CurrPtr,
      Variable.Volatile,
      &mVariableModuleGlobal->VariableGlobal[Physical],
      mVariableModuleGlobal->FvbInstance,
      (CHAR16 *) mVariableModuleGlobal->PubKeyStore
      );

    mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
  }
  //
  // Check "SetupMode" variable's existence. 
  // If it doesn't exist, check PK database's existence to determine the value.
  // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. 
  //
  Status = FindVariable (
             mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], 
             &gEfiGlobalVariableGuid, 
             &Variable, 
             &mVariableModuleGlobal->VariableGlobal[Physical],
             mVariableModuleGlobal->FvbInstance
             );

  if (Variable.CurrPtr == 0x0) {
    Status = FindVariable (
               mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY], 
               &gEfiGlobalVariableGuid, 
               &Variable, 
               &mVariableModuleGlobal->VariableGlobal[Physical],
               mVariableModuleGlobal->FvbInstance
               );
    if (Variable.CurrPtr == 0x0) {
      mPlatformMode = SETUP_MODE;
    } else {
      mPlatformMode = USER_MODE;
    }

    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    Status  = UpdateVariable (
                mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
                &gEfiGlobalVariableGuid,
                &mPlatformMode,
                sizeof(UINT8),
                VarAttr,
                0,
                0,
                FALSE,
                mVariableModuleGlobal,
                &Variable
                );
    if (EFI_ERROR (Status)) {
      return Status;
    }
  } else {
    GetVariableDataPtr (
      Variable.CurrPtr,
      Variable.Volatile,
      &mVariableModuleGlobal->VariableGlobal[Physical],
      mVariableModuleGlobal->FvbInstance,
      (CHAR16 *) &mPlatformMode
      );
  }
  //
  // Check "SignatureSupport" variable's existence. 
  // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. 
  //
  Status = FindVariable (
             EFI_SIGNATURE_SUPPORT_NAME, 
             &gEfiGlobalVariableGuid, 
             &Variable, 
             &mVariableModuleGlobal->VariableGlobal[Physical],
             mVariableModuleGlobal->FvbInstance
             );

  if (Variable.CurrPtr == 0x0) {
    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    Status  = UpdateVariable (
                EFI_SIGNATURE_SUPPORT_NAME,
                &gEfiGlobalVariableGuid,
                mSignatureSupport,
                SIGSUPPORT_NUM * sizeof(EFI_GUID),
                VarAttr,
                0,
                0,
                FALSE,
                mVariableModuleGlobal,
                &Variable
                );
  }

  return Status;
}
Ejemplo n.º 6
0
int
main(int argc, char *argv[])
{
	char *progname = argv[0], *buf, *vardata, *timestampstr = NULL;
	uint32_t attributes = EFI_VARIABLE_NON_VOLATILE
		| EFI_VARIABLE_RUNTIME_ACCESS
		| EFI_VARIABLE_BOOTSERVICE_ACCESS
		| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
	int flashfile, varfile, i, offset, varlen, varfilesize, listvars = 0;
	const int chunk = 8;
	wchar_t var[128];
	struct stat st;
	EFI_GUID *owner = NULL, guid;
	EFI_TIME timestamp;

	while (argc > 1 && argv[1][0] == '-') {
		if (strcmp("--version", argv[1]) == 0) {
			version(progname);
			exit(0);
		} else if (strcmp("--help", argv[1]) == 0) {
			help(progname);
			exit(0);
		} else if (strcmp(argv[1], "-g") == 0) {
			if (str_to_guid(argv[2], &guid)) {
				fprintf(stderr, "Invalid GUID %s\n", argv[2]);
				exit(1);
			}
			owner = &guid;
			argv += 2;
			argc -= 2;
		} else if (strcmp("-t", argv[1]) == 0) {
			timestampstr = argv[2];
			argv += 2;
			argc -= 2;
		} else if (strcmp("-l", argv[1]) == 0) {
			listvars = 1;
			argv += 1;
			argc -= 1;
		} else {
			/* unrecognised option */
			break;
		}
	}

	if ((argc != 4 && !listvars) || (argc != 2 && listvars)) {
		usage(progname);
		exit(1);
	}

	/* copy to wchar16_t including trailing zero */
	for (i = 0; i < strlen(argv[2]) + 1; i++)
		var[i] = argv[2][i];
	varlen = i*2;		/* size of storage including zero */

	if (!owner)
		owner = get_owner_guid(argv[2]);
	if (!owner) {
		fprintf(stderr, "variable %s has no defined guid, one must be specified\n", argv[2]);
		exit(1);
	}


	memset(&timestamp, 0, sizeof(timestamp));
	time_t t;
	struct tm *tm, tms;

	memset(&tms, 0, sizeof(tms));


	if (timestampstr) {
		strptime(timestampstr, "%Y-%m-%d %H:%M:%S", &tms);
		tm = &tms;
	} else {
		time(&t);
		tm = localtime(&t);
	}

	/* timestamp.Year is from 0 not 1900 as tm year is */
	timestamp.Year = tm->tm_year + 1900;
	/* timestamp Month is 1-12 not 0-11 as tm_mon is */
	timestamp.Month = tm->tm_mon + 1;
	timestamp.Day = tm->tm_mday;
	timestamp.Hour = tm->tm_hour;
	timestamp.Minute = tm->tm_min;
	timestamp.Second = tm->tm_sec;

	printf("Timestamp is %d-%d-%d %02d:%02d:%02d\n", timestamp.Year,
	       timestamp.Month, timestamp.Day, timestamp.Hour, timestamp.Minute,
	       timestamp.Second);

	flashfile = open(argv[1], O_RDWR);
	if (flashfile < 0) {
		fprintf(stderr, "Failed to read file %s:", argv[1]);
		perror("");
	}

	varfile = open(argv[3], O_RDONLY);
	if (varfile < 0) {
		fprintf(stderr, "Failed to read file %s:", argv[1]);
		perror("");
	}
	fstat(varfile, &st);
	varfilesize = st.st_size;

	vardata = malloc(varfilesize);
	if (read(varfile, vardata, varfilesize) != varfilesize) {
		perror("Failed to read variable file");
		exit(1);
	}
	close(varfile);

	buf = malloc(sizeof(EFI_GUID));

	for (i = 0; ; i += chunk) {
		lseek(flashfile, i, SEEK_SET);
		if (read(flashfile, buf, sizeof(EFI_GUID)) != sizeof(EFI_GUID))
			goto eof;
		if (memcmp(buf, &SECURE_VARIABLE_GUID, sizeof(EFI_GUID)) == 0)
			break;
	}   
	offset = i;
	printf("Variable header found at offset 0x%x\n", offset);
	lseek(flashfile, offset, SEEK_SET);
	free(buf);
	buf = malloc(sizeof(VARIABLE_STORE_HEADER));
	read(flashfile, buf, sizeof(VARIABLE_STORE_HEADER));

	VARIABLE_STORE_HEADER *vsh = (VARIABLE_STORE_HEADER *)buf;
	if (vsh->Format != VARIABLE_STORE_FORMATTED &&
	    vsh->State != VARIABLE_STORE_HEALTHY) {
		fprintf(stderr, "Variable store header is corrupt\n");
		exit(1);
	}
	UINT32 size = vsh->Size;
	free(buf);
	buf = malloc(size);
	lseek(flashfile, offset, SEEK_SET);
	read(flashfile, buf, size);
	vsh = (VARIABLE_STORE_HEADER *)buf;
	printf("Variable Store Size = 0x%x\n", vsh->Size);

	VARIABLE_HEADER *vh = (void *)HEADER_ALIGN(vsh + 1);
	printf("variables begin at 0x%x\n", (int)((char *)vh - (char *)vsh));
	for (i = 0; IsValidVariableHeader(vh); i++) {
		vh = (void *)HEADER_ALIGN((char *)(vh + 1) + vh->NameSize + vh->DataSize);
	}
	printf("Found %d variables, now at offset %ld\n", i, (long)((char *)vh - (char *)vsh));
	memset(vh, 0, sizeof(*vh));
	vh->StartId = VARIABLE_DATA;
	vh->State = VAR_ADDED;
	vh->Attributes = attributes;
	vh->NameSize = varlen;
	vh->DataSize = varfilesize;
	vh->TimeStamp = timestamp;
	vh->VendorGuid = *owner;

	buf = (void *)(vh + 1);
	memcpy (buf, var, varlen);
	buf += varlen;
	memcpy (buf, vardata, varfilesize);
	lseek(flashfile, offset, SEEK_SET);
	write(flashfile, vsh, vsh->Size);
	close(flashfile);
	
	exit(0);

 eof:
	printf("No variables found in file at offset 0x%x\n", i);
	exit(2);
}