| 1 | |
| 2 | |
| 3 | *
|
| 4 | * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
|
| 5 | * Written by David Howells ([email protected])
|
| 6 |
|
| 7 |
|
| 8 | #define pr_fmt(fmt) "EFI: "fmt
|
| 9 | #include <linux/module.h>
|
| 10 | #include <linux/printk.h>
|
| 11 | #include <linux/err.h>
|
| 12 | #include <linux/efi.h>
|
| 13 |
|
| 14 | |
| 15 | * parse_efi_signature_list - Parse an EFI signature list for certificates
|
| 16 | * @source: The source of the key
|
| 17 | * @data: The data blob to parse
|
| 18 | * @size: The size of the data blob
|
| 19 | * @get_handler_for_guid: Get the handler func for the sig type (or NULL)
|
| 20 | *
|
| 21 | * Parse an EFI signature list looking for elements of interest. A list is
|
| 22 | * made up of a series of sublists, where all the elements in a sublist are of
|
| 23 | * the same type, but sublists can be of different types.
|
| 24 | *
|
| 25 | * For each sublist encountered, the @get_handler_for_guid function is called
|
| 26 | * with the type specifier GUID and returns either a pointer to a function to
|
| 27 | * handle elements of that type or NULL if the type is not of interest.
|
| 28 | *
|
| 29 | * If the sublist is of interest, each element is passed to the handler
|
| 30 | * function in turn.
|
| 31 | *
|
| 32 | * Error EBADMSG is returned if the list doesn't parse correctly and 0 is
|
| 33 | * returned if the list was parsed correctly. No error can be returned from
|
| 34 | * the @get_handler_for_guid function or the element handler function it
|
| 35 | * returns.
|
| 36 |
|
| 37 | int __init parse_efi_signature_list(
|
| 38 | const char *source,
|
| 39 | const void *data, size_t size,
|
| 40 | efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *))
|
| 41 | {
|
| 42 | efi_element_handler_t handler;
|
| 43 | unsigned int offs = 0;
|
| 44 |
|
| 45 | pr_devel("-->%s(,%zu)\n", __func__, size);
|
| 46 |
|
| 47 | while (size > 0) {
|
| 48 | const efi_signature_data_t *elem;
|
| 49 | efi_signature_list_t list;
|
| 50 | size_t lsize, esize, hsize, elsize;
|
| 51 |
|
| 52 | if (size < sizeof(list))
|
| 53 | return -EBADMSG;
|
| 54 |
|
| 55 | memcpy(&list, data, sizeof(list));
|
| 56 | pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
|
| 57 | offs,
|
| 58 | &list.signature_type, list.signature_list_size,
|
| 59 | list.signature_header_size, list.signature_size);
|
| 60 |
|
| 61 | lsize = list.signature_list_size;
|
| 62 | hsize = list.signature_header_size;
|
| 63 | esize = list.signature_size;
|
| 64 | elsize = lsize - sizeof(list) - hsize;
|
| 65 |
|
| 66 | if (lsize > size) {
|
| 67 | pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
|
| 68 | __func__, offs);
|
| 69 | return -EBADMSG;
|
| 70 | }
|
| 71 |
|
| 72 | if (lsize < sizeof(list) ||
|
| 73 | lsize - sizeof(list) < hsize ||
|
| 74 | esize < sizeof(*elem) ||
|
| 75 | elsize < esize ||
|
| 76 | elsize % esize != 0) {
|
| 77 | pr_devel("- bad size combo @%x\n", offs);
|
| 78 | return -EBADMSG;
|
| 79 | }
|
| 80 |
|
| 81 | handler = get_handler_for_guid(&list.signature_type);
|
| 82 | if (!handler) {
|
| 83 | data += lsize;
|
| 84 | size -= lsize;
|
| 85 | offs += lsize;
|
| 86 | continue;
|
| 87 | }
|
| 88 |
|
| 89 | data += sizeof(list) + hsize;
|
| 90 | size -= sizeof(list) + hsize;
|
| 91 | offs += sizeof(list) + hsize;
|
| 92 |
|
| 93 | for (; elsize > 0; elsize -= esize) {
|
| 94 | elem = data;
|
| 95 |
|
| 96 | pr_devel("ELEM[%04x]\n", offs);
|
| 97 | handler(source,
|
| 98 | &elem->signature_data,
|
| 99 | esize - sizeof(*elem));
|
| 100 |
|
| 101 | data += esize;
|
| 102 | size -= esize;
|
| 103 | offs += esize;
|
| 104 | }
|
| 105 | }
|
| 106 |
|
| 107 | return 0;
|
| 108 | }
|