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