Home | History | Annotate | Download | only in uefi
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Permission is hereby granted, free of charge, to any person
      5  * obtaining a copy of this software and associated documentation
      6  * files (the "Software"), to deal in the Software without
      7  * restriction, including without limitation the rights to use, copy,
      8  * modify, merge, publish, distribute, sublicense, and/or sell copies
      9  * of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be
     13  * included in all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  */
     24 
     25 #include <efi.h>
     26 #include <efilib.h>
     27 
     28 #include <libavb_ab/libavb_ab.h>
     29 
     30 #include "uefi_avb_ops.h"
     31 #include "uefi_avb_util.h"
     32 
     33 #include <efi.h>
     34 #include <efilib.h>
     35 
     36 /* GPT related constants. */
     37 #define GPT_REVISION 0x00010000
     38 #define GPT_MAGIC "EFI PART"
     39 #define GPT_MIN_SIZE 92
     40 #define GPT_ENTRIES_LBA 2
     41 #define AVB_BLOCK_SIZE 512
     42 #define ENTRIES_PER_BLOCK 4
     43 #define ENTRY_NAME_LEN 36
     44 #define MAX_GPT_ENTRIES 128
     45 
     46 typedef struct {
     47   uint8_t signature[8];
     48   uint32_t revision;
     49   uint32_t header_size;
     50   uint32_t header_crc32;
     51   uint32_t reserved;
     52   uint64_t header_lba;
     53   uint64_t alternate_header_lba;
     54   uint64_t first_usable_lba;
     55   uint64_t last_usable_lba;
     56   uint8_t disk_guid[16];
     57   uint64_t entry_lba;
     58   uint32_t entry_count;
     59   uint32_t entry_size;
     60   uint32_t entry_crc32;
     61   uint8_t reserved2[420];
     62 } GPTHeader;
     63 
     64 typedef struct {
     65   uint8_t type_GUID[16];
     66   uint8_t unique_GUID[16];
     67   uint64_t first_lba;
     68   uint64_t last_lba;
     69   uint64_t flags;
     70   uint16_t name[ENTRY_NAME_LEN];
     71 } GPTEntry;
     72 
     73 static EFI_STATUS find_partition_entry_by_name(IN EFI_BLOCK_IO* block_io,
     74                                                const char* partition_name,
     75                                                GPTEntry** entry_buf) {
     76   EFI_STATUS err;
     77   GPTHeader* gpt_header = NULL;
     78   GPTEntry all_gpt_entries[MAX_GPT_ENTRIES];
     79   uint16_t* partition_name_ucs2 = NULL;
     80   size_t partition_name_bytes;
     81   size_t partition_name_ucs2_capacity;
     82   size_t partition_name_ucs2_len;
     83 
     84   gpt_header = (GPTHeader*)avb_malloc(sizeof(GPTHeader));
     85   if (gpt_header == NULL) {
     86     avb_error("Could not allocate for GPT header\n");
     87     return EFI_NOT_FOUND;
     88   }
     89 
     90   *entry_buf = (GPTEntry*)avb_malloc(sizeof(GPTEntry) * ENTRIES_PER_BLOCK);
     91   if (entry_buf == NULL) {
     92     avb_error("Could not allocate for partition entry\n");
     93     avb_free(gpt_header);
     94     return EFI_NOT_FOUND;
     95   }
     96 
     97   err = uefi_call_wrapper(block_io->ReadBlocks,
     98                           NUM_ARGS_READ_BLOCKS,
     99                           block_io,
    100                           block_io->Media->MediaId,
    101                           1,
    102                           sizeof(GPTHeader),
    103                           gpt_header);
    104   if (EFI_ERROR(err)) {
    105     avb_error("Could not ReadBlocks for gpt header\n");
    106     avb_free(gpt_header);
    107     avb_free(*entry_buf);
    108     *entry_buf = NULL;
    109     return EFI_NOT_FOUND;
    110   }
    111 
    112   partition_name_bytes = avb_strlen(partition_name);
    113   partition_name_ucs2_capacity = sizeof(uint16_t) * (partition_name_bytes + 1);
    114   partition_name_ucs2 = avb_calloc(partition_name_ucs2_capacity);
    115   if (partition_name_ucs2 == NULL) {
    116     avb_error("Could not allocate for ucs2 partition name\n");
    117     avb_free(gpt_header);
    118     avb_free(*entry_buf);
    119     *entry_buf = NULL;
    120     return EFI_NOT_FOUND;
    121   }
    122   if (!uefi_avb_utf8_to_ucs2((const uint8_t*)partition_name,
    123                              partition_name_bytes,
    124                              partition_name_ucs2,
    125                              partition_name_ucs2_capacity,
    126                              NULL)) {
    127     avb_error("Could not convert partition name to UCS-2\n");
    128     avb_free(gpt_header);
    129     avb_free(partition_name_ucs2);
    130     avb_free(*entry_buf);
    131     *entry_buf = NULL;
    132     return EFI_NOT_FOUND;
    133   }
    134   partition_name_ucs2_len = StrLen(partition_name_ucs2);
    135 
    136   /* Block-aligned bytes for entries. */
    137   UINTN entries_num_bytes =
    138       block_io->Media->BlockSize * (MAX_GPT_ENTRIES / ENTRIES_PER_BLOCK);
    139 
    140   err = uefi_call_wrapper(block_io->ReadBlocks,
    141                           NUM_ARGS_READ_BLOCKS,
    142                           block_io,
    143                           block_io->Media->MediaId,
    144                           GPT_ENTRIES_LBA,
    145                           entries_num_bytes,
    146                           &all_gpt_entries);
    147   if (EFI_ERROR(err)) {
    148     avb_error("Could not ReadBlocks for GPT header\n");
    149     avb_free(gpt_header);
    150     avb_free(partition_name_ucs2);
    151     avb_free(*entry_buf);
    152     *entry_buf = NULL;
    153     return EFI_NOT_FOUND;
    154   }
    155 
    156   /* Find matching partition name. */
    157   for (int n = 0; n < gpt_header->entry_count; n++) {
    158     if ((partition_name_ucs2_len == StrLen(all_gpt_entries[n].name)) &&
    159         avb_memcmp(all_gpt_entries[n].name,
    160                    partition_name_ucs2,
    161                    partition_name_ucs2_len * 2) == 0) {
    162       avb_memcpy((*entry_buf), &all_gpt_entries[n], sizeof(GPTEntry));
    163       avb_free(partition_name_ucs2);
    164       avb_free(gpt_header);
    165       return EFI_SUCCESS;
    166     }
    167   }
    168 
    169   avb_free(partition_name_ucs2);
    170   avb_free(gpt_header);
    171   avb_free(*entry_buf);
    172   *entry_buf = NULL;
    173   return EFI_NOT_FOUND;
    174 }
    175 
    176 static AvbIOResult read_from_partition(AvbOps* ops,
    177                                        const char* partition_name,
    178                                        int64_t offset_from_partition,
    179                                        size_t num_bytes,
    180                                        void* buf,
    181                                        size_t* out_num_read) {
    182   EFI_STATUS err;
    183   GPTEntry* partition_entry;
    184   uint64_t partition_size;
    185   UEFIAvbOpsData* data = (UEFIAvbOpsData*)ops->user_data;
    186 
    187   avb_assert(partition_name != NULL);
    188   avb_assert(buf != NULL);
    189   avb_assert(out_num_read != NULL);
    190 
    191   err = find_partition_entry_by_name(
    192       data->block_io, partition_name, &partition_entry);
    193   if (EFI_ERROR(err)) {
    194     return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
    195   }
    196 
    197   partition_size =
    198       (partition_entry->last_lba - partition_entry->first_lba + 1) *
    199       data->block_io->Media->BlockSize;
    200 
    201   if (offset_from_partition < 0) {
    202     if ((-offset_from_partition) > partition_size) {
    203       avb_error("Offset outside range.\n");
    204       avb_free(partition_entry);
    205       return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
    206     }
    207     offset_from_partition = partition_size - (-offset_from_partition);
    208   }
    209 
    210   /* Check if num_bytes goes beyond partition end. If so, don't read beyond
    211    * this boundary -- do a partial I/O instead.
    212    */
    213   if (num_bytes > partition_size - offset_from_partition)
    214     *out_num_read = partition_size - offset_from_partition;
    215   else
    216     *out_num_read = num_bytes;
    217 
    218   err = uefi_call_wrapper(
    219       data->disk_io->ReadDisk,
    220       5,
    221       data->disk_io,
    222       data->block_io->Media->MediaId,
    223       (partition_entry->first_lba * data->block_io->Media->BlockSize) +
    224           offset_from_partition,
    225       *out_num_read,
    226       buf);
    227   if (EFI_ERROR(err)) {
    228     avb_error("Could not read from Disk.\n");
    229     *out_num_read = 0;
    230     avb_free(partition_entry);
    231     return AVB_IO_RESULT_ERROR_IO;
    232   }
    233 
    234   avb_free(partition_entry);
    235   return AVB_IO_RESULT_OK;
    236 }
    237 
    238 static AvbIOResult write_to_partition(AvbOps* ops,
    239                                       const char* partition_name,
    240                                       int64_t offset_from_partition,
    241                                       size_t num_bytes,
    242                                       const void* buf) {
    243   EFI_STATUS err;
    244   GPTEntry* partition_entry;
    245   uint64_t partition_size;
    246   UEFIAvbOpsData* data = (UEFIAvbOpsData*)ops->user_data;
    247 
    248   avb_assert(partition_name != NULL);
    249   avb_assert(buf != NULL);
    250 
    251   err = find_partition_entry_by_name(
    252       data->block_io, partition_name, &partition_entry);
    253   if (EFI_ERROR(err)) {
    254     return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
    255   }
    256 
    257   partition_size = (partition_entry->last_lba - partition_entry->first_lba) *
    258                    data->block_io->Media->BlockSize;
    259 
    260   if (offset_from_partition < 0) {
    261     if ((-offset_from_partition) > partition_size) {
    262       avb_error("Offset outside range.\n");
    263       avb_free(partition_entry);
    264       return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
    265     }
    266     offset_from_partition = partition_size - (-offset_from_partition);
    267   }
    268 
    269   /* Check if num_bytes goes beyond partition end. If so, error out -- no
    270    * partial I/O.
    271    */
    272   if (num_bytes > partition_size - offset_from_partition) {
    273     avb_error("Cannot write beyond partition boundary.\n");
    274     avb_free(partition_entry);
    275     return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
    276   }
    277 
    278   err = uefi_call_wrapper(
    279       data->disk_io->WriteDisk,
    280       5,
    281       data->disk_io,
    282       data->block_io->Media->MediaId,
    283       (partition_entry->first_lba * data->block_io->Media->BlockSize) +
    284           offset_from_partition,
    285       num_bytes,
    286       buf);
    287 
    288   if (EFI_ERROR(err)) {
    289     avb_error("Could not write to Disk.\n");
    290     avb_free(partition_entry);
    291     return AVB_IO_RESULT_ERROR_IO;
    292   }
    293 
    294   avb_free(partition_entry);
    295   return AVB_IO_RESULT_OK;
    296 }
    297 
    298 static AvbIOResult get_size_of_partition(AvbOps* ops,
    299                                          const char* partition_name,
    300                                          uint64_t* out_size) {
    301   EFI_STATUS err;
    302   GPTEntry* partition_entry;
    303   uint64_t partition_size;
    304   UEFIAvbOpsData* data = (UEFIAvbOpsData*)ops->user_data;
    305 
    306   avb_assert(partition_name != NULL);
    307 
    308   err = find_partition_entry_by_name(
    309       data->block_io, partition_name, &partition_entry);
    310   if (EFI_ERROR(err)) {
    311     return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
    312   }
    313 
    314   partition_size =
    315       (partition_entry->last_lba - partition_entry->first_lba + 1) *
    316       data->block_io->Media->BlockSize;
    317 
    318   if (out_size != NULL) {
    319     *out_size = partition_size;
    320   }
    321 
    322   avb_free(partition_entry);
    323   return AVB_IO_RESULT_OK;
    324 }
    325 
    326 /* Helper method to get the parent path to the current |walker| path
    327  * given the initial path, |init|. Resulting path is stored in |next|.
    328  * Caller is responsible for freeing |next|. Stores allocated bytes
    329  * for |next| in |out_bytes|. Returns EFI_SUCCESS on success.
    330  */
    331 static EFI_STATUS walk_path(IN EFI_DEVICE_PATH* init,
    332                             IN EFI_DEVICE_PATH* walker,
    333                             OUT EFI_DEVICE_PATH** next,
    334                             OUT UINTN* out_bytes) {
    335   /* Number of bytes from initial path to current walker. */
    336   UINTN walker_bytes = (uint8_t*)NextDevicePathNode(walker) - (uint8_t*)init;
    337   *out_bytes = sizeof(EFI_DEVICE_PATH) + walker_bytes;
    338 
    339   *next = (EFI_DEVICE_PATH*)avb_malloc(*out_bytes);
    340   if (*next == NULL) {
    341     *out_bytes = 0;
    342     return EFI_NOT_FOUND;
    343   }
    344 
    345   /* Copy in the previous paths. */
    346   avb_memcpy((*next), init, walker_bytes);
    347   /* Copy in the new ending of the path. */
    348   avb_memcpy(
    349       (uint8_t*)(*next) + walker_bytes, EndDevicePath, sizeof(EFI_DEVICE_PATH));
    350   return EFI_SUCCESS;
    351 }
    352 
    353 /* Helper method to validate a GPT header, |gpth|.
    354  *
    355  * @return EFI_STATUS EFI_SUCCESS on success.
    356  */
    357 static EFI_STATUS validate_gpt(const IN GPTHeader* gpth) {
    358   if (avb_memcmp(gpth->signature, GPT_MAGIC, sizeof(gpth->signature)) != 0) {
    359     avb_error("GPT signature does not match.\n");
    360     return EFI_NOT_FOUND;
    361   }
    362   /* Make sure GPT header bytes are within minimun and block size. */
    363   if (gpth->header_size < GPT_MIN_SIZE) {
    364     avb_error("GPT header too small.\n");
    365     return EFI_NOT_FOUND;
    366   }
    367   if (gpth->header_size > AVB_BLOCK_SIZE) {
    368     avb_error("GPT header too big.\n");
    369     return EFI_NOT_FOUND;
    370   }
    371 
    372   GPTHeader gpth_tmp = {{0}};
    373   avb_memcpy(&gpth_tmp, gpth, sizeof(GPTHeader));
    374   uint32_t gpt_header_crc = gpth_tmp.header_crc32;
    375   gpth_tmp.header_crc32 = 0;
    376   uint32_t gpt_header_crc_calc =
    377       CalculateCrc((uint8_t*)&gpth_tmp, gpth_tmp.header_size);
    378 
    379   if (gpt_header_crc != gpt_header_crc_calc) {
    380     avb_error("GPT header crc invalid.\n");
    381     return EFI_NOT_FOUND;
    382   }
    383 
    384   if (gpth->revision != GPT_REVISION) {
    385     avb_error("GPT header wrong revision.\n");
    386     return EFI_NOT_FOUND;
    387   }
    388 
    389   return EFI_SUCCESS;
    390 }
    391 
    392 /* Queries |disk_handle| for a |block_io| device and the corresponding
    393  * path, |block_path|.  The |block_io| device is found by iteratively
    394  * querying parent devices and checking for a GPT Header.  This
    395  * ensures the resulting |block_io| device is the top level block
    396  * device having access to partition entries. Returns EFI_STATUS
    397  * EFI_NOT_FOUND on failure, EFI_SUCCESS otherwise.
    398  */
    399 static EFI_STATUS get_disk_block_io(IN EFI_HANDLE* block_handle,
    400                                     OUT EFI_BLOCK_IO** block_io,
    401                                     OUT EFI_DISK_IO** disk_io,
    402                                     OUT EFI_DEVICE_PATH** io_path) {
    403   EFI_STATUS err;
    404   EFI_HANDLE disk_handle;
    405   UINTN path_bytes;
    406   EFI_DEVICE_PATH* disk_path;
    407   EFI_DEVICE_PATH* walker_path;
    408   EFI_DEVICE_PATH* init_path;
    409   GPTHeader gpt_header = {{0}};
    410   init_path = DevicePathFromHandle(block_handle);
    411 
    412   if (!init_path) {
    413     return EFI_NOT_FOUND;
    414   }
    415 
    416   walker_path = init_path;
    417   while (!IsDevicePathEnd(walker_path)) {
    418     walker_path = NextDevicePathNode(walker_path);
    419 
    420     err = walk_path(init_path, walker_path, &(*io_path), &path_bytes);
    421     if (EFI_ERROR(err)) {
    422       avb_error("Cannot walk device path.\n");
    423       return EFI_NOT_FOUND;
    424     }
    425 
    426     disk_path = (EFI_DEVICE_PATH*)avb_malloc(path_bytes);
    427     avb_memcpy(disk_path, *io_path, path_bytes);
    428     err = uefi_call_wrapper(BS->LocateDevicePath,
    429                             NUM_ARGS_LOCATE_DEVICE_PATH,
    430                             &BlockIoProtocol,
    431                             &(*io_path),
    432                             &block_handle);
    433     if (EFI_ERROR(err)) {
    434       avb_free(*io_path);
    435       avb_free(disk_path);
    436       continue;
    437     }
    438     err = uefi_call_wrapper(BS->LocateDevicePath,
    439                             NUM_ARGS_LOCATE_DEVICE_PATH,
    440                             &DiskIoProtocol,
    441                             &disk_path,
    442                             &disk_handle);
    443     if (EFI_ERROR(err)) {
    444       avb_error("LocateDevicePath, DISK_IO_PROTOCOL.\n");
    445       avb_free(*io_path);
    446       avb_free(disk_path);
    447       continue;
    448     }
    449 
    450     /* Handle Block and Disk I/O. Attempt to get handle on device,
    451      * must be Block/Disk Io type.
    452      */
    453     err = uefi_call_wrapper(BS->HandleProtocol,
    454                             NUM_ARGS_HANDLE_PROTOCOL,
    455                             block_handle,
    456                             &BlockIoProtocol,
    457                             (VOID**)&(*block_io));
    458     if (EFI_ERROR(err)) {
    459       avb_error("Cannot get handle on block device.\n");
    460       avb_free(*io_path);
    461       avb_free(disk_path);
    462       continue;
    463     }
    464     err = uefi_call_wrapper(BS->HandleProtocol,
    465                             NUM_ARGS_HANDLE_PROTOCOL,
    466                             disk_handle,
    467                             &DiskIoProtocol,
    468                             (VOID**)&(*disk_io));
    469     if (EFI_ERROR(err)) {
    470       avb_error("Cannot get handle on disk device.\n");
    471       avb_free(*io_path);
    472       avb_free(disk_path);
    473       continue;
    474     }
    475 
    476     if ((*block_io)->Media->LogicalPartition ||
    477         !(*block_io)->Media->MediaPresent) {
    478       avb_error("Logical partion or No Media Present, continue...\n");
    479       avb_free(*io_path);
    480       avb_free(disk_path);
    481       continue;
    482     }
    483 
    484     err = uefi_call_wrapper((*block_io)->ReadBlocks,
    485                             NUM_ARGS_READ_BLOCKS,
    486                             (*block_io),
    487                             (*block_io)->Media->MediaId,
    488                             1,
    489                             sizeof(GPTHeader),
    490                             &gpt_header);
    491 
    492     if (EFI_ERROR(err)) {
    493       avb_error("ReadBlocks, Block Media error.\n");
    494       avb_free(*io_path);
    495       avb_free(disk_path);
    496       continue;
    497     }
    498 
    499     err = validate_gpt(&gpt_header);
    500     if (EFI_ERROR(err)) {
    501       avb_error("Invalid GPTHeader\n");
    502       avb_free(*io_path);
    503       avb_free(disk_path);
    504       continue;
    505     }
    506 
    507     return EFI_SUCCESS;
    508   }
    509 
    510   (*block_io) = NULL;
    511   return EFI_NOT_FOUND;
    512 }
    513 
    514 static AvbIOResult validate_vbmeta_public_key(
    515     AvbOps* ops,
    516     const uint8_t* public_key_data,
    517     size_t public_key_length,
    518     const uint8_t* public_key_metadata,
    519     size_t public_key_metadata_length,
    520     bool* out_key_is_trusted) {
    521   /* For now we just allow any key. */
    522   if (out_key_is_trusted != NULL) {
    523     *out_key_is_trusted = true;
    524   }
    525   avb_debug("TODO: implement validate_vbmeta_public_key().\n");
    526   return AVB_IO_RESULT_OK;
    527 }
    528 
    529 static AvbIOResult read_rollback_index(AvbOps* ops,
    530                                        size_t rollback_index_slot,
    531                                        uint64_t* out_rollback_index) {
    532   /* For now we always return 0 as the stored rollback index. */
    533   avb_debug("TODO: implement read_rollback_index().\n");
    534   if (out_rollback_index != NULL) {
    535     *out_rollback_index = 0;
    536   }
    537   return AVB_IO_RESULT_OK;
    538 }
    539 
    540 static AvbIOResult write_rollback_index(AvbOps* ops,
    541                                         size_t rollback_index_slot,
    542                                         uint64_t rollback_index) {
    543   /* For now this is a no-op. */
    544   avb_debug("TODO: implement write_rollback_index().\n");
    545   return AVB_IO_RESULT_OK;
    546 }
    547 
    548 static AvbIOResult read_is_device_unlocked(AvbOps* ops, bool* out_is_unlocked) {
    549   /* For now we always return that the device is unlocked. */
    550   avb_debug("TODO: implement read_is_device_unlocked().\n");
    551   *out_is_unlocked = true;
    552   return AVB_IO_RESULT_OK;
    553 }
    554 
    555 static void set_hex(char* buf, uint8_t value) {
    556   char hex_digits[17] = "0123456789abcdef";
    557   buf[0] = hex_digits[value >> 4];
    558   buf[1] = hex_digits[value & 0x0f];
    559 }
    560 
    561 static AvbIOResult get_unique_guid_for_partition(AvbOps* ops,
    562                                                  const char* partition,
    563                                                  char* guid_buf,
    564                                                  size_t guid_buf_size) {
    565   EFI_STATUS err;
    566   GPTEntry* partition_entry;
    567   UEFIAvbOpsData* data = (UEFIAvbOpsData*)ops->user_data;
    568 
    569   avb_assert(partition != NULL);
    570   avb_assert(guid_buf != NULL);
    571 
    572   err =
    573       find_partition_entry_by_name(data->block_io, partition, &partition_entry);
    574   if (EFI_ERROR(err)) {
    575     avb_error("Error getting unique GUID for partition.\n");
    576     return AVB_IO_RESULT_ERROR_IO;
    577   }
    578 
    579   if (guid_buf_size < 37) {
    580     avb_error("GUID buffer size too small.\n");
    581     return AVB_IO_RESULT_ERROR_IO;
    582   }
    583 
    584   /* The GUID encoding is somewhat peculiar in terms of byte order. It
    585    * is what it is.
    586    */
    587   set_hex(guid_buf + 0, partition_entry->unique_GUID[3]);
    588   set_hex(guid_buf + 2, partition_entry->unique_GUID[2]);
    589   set_hex(guid_buf + 4, partition_entry->unique_GUID[1]);
    590   set_hex(guid_buf + 6, partition_entry->unique_GUID[0]);
    591   guid_buf[8] = '-';
    592   set_hex(guid_buf + 9, partition_entry->unique_GUID[5]);
    593   set_hex(guid_buf + 11, partition_entry->unique_GUID[4]);
    594   guid_buf[13] = '-';
    595   set_hex(guid_buf + 14, partition_entry->unique_GUID[7]);
    596   set_hex(guid_buf + 16, partition_entry->unique_GUID[6]);
    597   guid_buf[18] = '-';
    598   set_hex(guid_buf + 19, partition_entry->unique_GUID[8]);
    599   set_hex(guid_buf + 21, partition_entry->unique_GUID[9]);
    600   guid_buf[23] = '-';
    601   set_hex(guid_buf + 24, partition_entry->unique_GUID[10]);
    602   set_hex(guid_buf + 26, partition_entry->unique_GUID[11]);
    603   set_hex(guid_buf + 28, partition_entry->unique_GUID[12]);
    604   set_hex(guid_buf + 30, partition_entry->unique_GUID[13]);
    605   set_hex(guid_buf + 32, partition_entry->unique_GUID[14]);
    606   set_hex(guid_buf + 34, partition_entry->unique_GUID[15]);
    607   guid_buf[36] = '\0';
    608   return AVB_IO_RESULT_OK;
    609 }
    610 
    611 AvbOps* uefi_avb_ops_new(EFI_HANDLE app_image) {
    612   UEFIAvbOpsData* data;
    613   EFI_STATUS err;
    614   EFI_LOADED_IMAGE* loaded_app_image = NULL;
    615   EFI_GUID loaded_image_protocol = LOADED_IMAGE_PROTOCOL;
    616 
    617   data = avb_calloc(sizeof(UEFIAvbOpsData));
    618   data->ops.user_data = data;
    619 
    620   data->efi_image_handle = app_image;
    621   err = uefi_call_wrapper(BS->HandleProtocol,
    622                           NUM_ARGS_HANDLE_PROTOCOL,
    623                           app_image,
    624                           &loaded_image_protocol,
    625                           (VOID**)&loaded_app_image);
    626   if (EFI_ERROR(err)) {
    627     avb_error("HandleProtocol, LOADED_IMAGE_PROTOCOL.\n");
    628     return 0;
    629   }
    630 
    631   /* Get parent device disk and block I/O. */
    632   err = get_disk_block_io(loaded_app_image->DeviceHandle,
    633                           &data->block_io,
    634                           &data->disk_io,
    635                           &data->path);
    636   if (EFI_ERROR(err)) {
    637     avb_error("Could not acquire block or disk device handle.\n");
    638     return 0;
    639   }
    640 
    641   data->ops.ab_ops = &data->ab_ops;
    642   data->ops.read_from_partition = read_from_partition;
    643   data->ops.write_to_partition = write_to_partition;
    644   data->ops.validate_vbmeta_public_key = validate_vbmeta_public_key;
    645   data->ops.read_rollback_index = read_rollback_index;
    646   data->ops.write_rollback_index = write_rollback_index;
    647   data->ops.read_is_device_unlocked = read_is_device_unlocked;
    648   data->ops.get_unique_guid_for_partition = get_unique_guid_for_partition;
    649   data->ops.get_size_of_partition = get_size_of_partition;
    650 
    651   data->ab_ops.ops = &data->ops;
    652   data->ab_ops.read_ab_metadata = avb_ab_data_read;
    653   data->ab_ops.write_ab_metadata = avb_ab_data_write;
    654 
    655   return &data->ops;
    656 }
    657 
    658 void uefi_avb_ops_free(AvbOps* ops) {
    659   UEFIAvbOpsData* data = ops->user_data;
    660   avb_free(data);
    661 }
    662