Merge tag 'mmc-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[linux-2.6-microblaze.git] / security / integrity / platform_certs / load_uefi.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/kernel.h>
4 #include <linux/sched.h>
5 #include <linux/cred.h>
6 #include <linux/err.h>
7 #include <linux/efi.h>
8 #include <linux/slab.h>
9 #include <keys/asymmetric-type.h>
10 #include <keys/system_keyring.h>
11 #include "../integrity.h"
12 #include "keyring_handler.h"
13
14 /*
15  * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
16  * it does.
17  *
18  * This UEFI variable is set by the shim if a user tells the shim to not use
19  * the certs/hashes in the UEFI db variable for verification purposes.  If it
20  * is set, we should ignore the db variable also and the true return indicates
21  * this.
22  */
23 static __init bool uefi_check_ignore_db(void)
24 {
25         efi_status_t status;
26         unsigned int db = 0;
27         unsigned long size = sizeof(db);
28         efi_guid_t guid = EFI_SHIM_LOCK_GUID;
29
30         status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
31         return status == EFI_SUCCESS;
32 }
33
34 /*
35  * Get a certificate list blob from the named EFI variable.
36  */
37 static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
38                                   unsigned long *size, efi_status_t *status)
39 {
40         unsigned long lsize = 4;
41         unsigned long tmpdb[4];
42         void *db;
43
44         *status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
45         if (*status == EFI_NOT_FOUND)
46                 return NULL;
47
48         if (*status != EFI_BUFFER_TOO_SMALL) {
49                 pr_err("Couldn't get size: 0x%lx\n", *status);
50                 return NULL;
51         }
52
53         db = kmalloc(lsize, GFP_KERNEL);
54         if (!db)
55                 return NULL;
56
57         *status = efi.get_variable(name, guid, NULL, &lsize, db);
58         if (*status != EFI_SUCCESS) {
59                 kfree(db);
60                 pr_err("Error reading db var: 0x%lx\n", *status);
61                 return NULL;
62         }
63
64         *size = lsize;
65         return db;
66 }
67
68 /*
69  * load_moklist_certs() - Load MokList certs
70  *
71  * Load the certs contained in the UEFI MokListRT database into the
72  * platform trusted keyring.
73  *
74  * This routine checks the EFI MOK config table first. If and only if
75  * that fails, this routine uses the MokListRT ordinary UEFI variable.
76  *
77  * Return:      Status
78  */
79 static int __init load_moklist_certs(void)
80 {
81         struct efi_mokvar_table_entry *mokvar_entry;
82         efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
83         void *mok;
84         unsigned long moksize;
85         efi_status_t status;
86         int rc;
87
88         /* First try to load certs from the EFI MOKvar config table.
89          * It's not an error if the MOKvar config table doesn't exist
90          * or the MokListRT entry is not found in it.
91          */
92         mokvar_entry = efi_mokvar_entry_find("MokListRT");
93         if (mokvar_entry) {
94                 rc = parse_efi_signature_list("UEFI:MokListRT (MOKvar table)",
95                                               mokvar_entry->data,
96                                               mokvar_entry->data_size,
97                                               get_handler_for_db);
98                 /* All done if that worked. */
99                 if (!rc)
100                         return rc;
101
102                 pr_err("Couldn't parse MokListRT signatures from EFI MOKvar config table: %d\n",
103                        rc);
104         }
105
106         /* Get MokListRT. It might not exist, so it isn't an error
107          * if we can't get it.
108          */
109         mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
110         if (mok) {
111                 rc = parse_efi_signature_list("UEFI:MokListRT",
112                                               mok, moksize, get_handler_for_db);
113                 kfree(mok);
114                 if (rc)
115                         pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
116                 return rc;
117         }
118         if (status == EFI_NOT_FOUND)
119                 pr_debug("MokListRT variable wasn't found\n");
120         else
121                 pr_info("Couldn't get UEFI MokListRT\n");
122         return 0;
123 }
124
125 /*
126  * load_uefi_certs() - Load certs from UEFI sources
127  *
128  * Load the certs contained in the UEFI databases into the platform trusted
129  * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
130  * keyring.
131  */
132 static int __init load_uefi_certs(void)
133 {
134         efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
135         efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
136         void *db = NULL, *dbx = NULL, *mokx = NULL;
137         unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0;
138         efi_status_t status;
139         int rc = 0;
140
141         if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
142                 return false;
143
144         /* Get db and dbx.  They might not exist, so it isn't an error
145          * if we can't get them.
146          */
147         if (!uefi_check_ignore_db()) {
148                 db = get_cert_list(L"db", &secure_var, &dbsize, &status);
149                 if (!db) {
150                         if (status == EFI_NOT_FOUND)
151                                 pr_debug("MODSIGN: db variable wasn't found\n");
152                         else
153                                 pr_err("MODSIGN: Couldn't get UEFI db list\n");
154                 } else {
155                         rc = parse_efi_signature_list("UEFI:db",
156                                         db, dbsize, get_handler_for_db);
157                         if (rc)
158                                 pr_err("Couldn't parse db signatures: %d\n",
159                                        rc);
160                         kfree(db);
161                 }
162         }
163
164         dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
165         if (!dbx) {
166                 if (status == EFI_NOT_FOUND)
167                         pr_debug("dbx variable wasn't found\n");
168                 else
169                         pr_info("Couldn't get UEFI dbx list\n");
170         } else {
171                 rc = parse_efi_signature_list("UEFI:dbx",
172                                               dbx, dbxsize,
173                                               get_handler_for_dbx);
174                 if (rc)
175                         pr_err("Couldn't parse dbx signatures: %d\n", rc);
176                 kfree(dbx);
177         }
178
179         mokx = get_cert_list(L"MokListXRT", &mok_var, &mokxsize, &status);
180         if (!mokx) {
181                 if (status == EFI_NOT_FOUND)
182                         pr_debug("mokx variable wasn't found\n");
183                 else
184                         pr_info("Couldn't get mokx list\n");
185         } else {
186                 rc = parse_efi_signature_list("UEFI:MokListXRT",
187                                               mokx, mokxsize,
188                                               get_handler_for_dbx);
189                 if (rc)
190                         pr_err("Couldn't parse mokx signatures %d\n", rc);
191                 kfree(mokx);
192         }
193
194         /* Load the MokListRT certs */
195         rc = load_moklist_certs();
196
197         return rc;
198 }
199 late_initcall(load_uefi_certs);