Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorri...
[sfrench/cifs-2.6.git] / security / integrity / platform_certs / efi_parser.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* EFI signature/key/certificate list parser
3  *
4  * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
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.b, 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 }