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
46typedef 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
64typedef 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
73static 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
176static 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
238static 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
298static 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 */
331static 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 */
357static 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 */
399static 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
514static 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
529static 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
540static 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
548static 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
555static 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
561static 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
611AvbOps* 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
658void uefi_avb_ops_free(AvbOps* ops) {
659  UEFIAvbOpsData* data = ops->user_data;
660  avb_free(data);
661}
662