root/security/integrity/platform_certs/load_uefi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uefi_check_ignore_db
  2. get_cert_list
  3. uefi_blacklist_hash
  4. uefi_blacklist_x509_tbs
  5. uefi_blacklist_binary
  6. get_handler_for_db
  7. get_handler_for_dbx
  8. load_uefi_certs

   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 
  13 static efi_guid_t efi_cert_x509_guid __initdata = EFI_CERT_X509_GUID;
  14 static efi_guid_t efi_cert_x509_sha256_guid __initdata =
  15         EFI_CERT_X509_SHA256_GUID;
  16 static efi_guid_t efi_cert_sha256_guid __initdata = EFI_CERT_SHA256_GUID;
  17 
  18 /*
  19  * Look to see if a UEFI variable called MokIgnoreDB exists and return true if
  20  * it does.
  21  *
  22  * This UEFI variable is set by the shim if a user tells the shim to not use
  23  * the certs/hashes in the UEFI db variable for verification purposes.  If it
  24  * is set, we should ignore the db variable also and the true return indicates
  25  * this.
  26  */
  27 static __init bool uefi_check_ignore_db(void)
  28 {
  29         efi_status_t status;
  30         unsigned int db = 0;
  31         unsigned long size = sizeof(db);
  32         efi_guid_t guid = EFI_SHIM_LOCK_GUID;
  33 
  34         status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db);
  35         return status == EFI_SUCCESS;
  36 }
  37 
  38 /*
  39  * Get a certificate list blob from the named EFI variable.
  40  */
  41 static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid,
  42                                   unsigned long *size, efi_status_t *status)
  43 {
  44         unsigned long lsize = 4;
  45         unsigned long tmpdb[4];
  46         void *db;
  47 
  48         *status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
  49         if (*status == EFI_NOT_FOUND)
  50                 return NULL;
  51 
  52         if (*status != EFI_BUFFER_TOO_SMALL) {
  53                 pr_err("Couldn't get size: 0x%lx\n", *status);
  54                 return NULL;
  55         }
  56 
  57         db = kmalloc(lsize, GFP_KERNEL);
  58         if (!db)
  59                 return NULL;
  60 
  61         *status = efi.get_variable(name, guid, NULL, &lsize, db);
  62         if (*status != EFI_SUCCESS) {
  63                 kfree(db);
  64                 pr_err("Error reading db var: 0x%lx\n", *status);
  65                 return NULL;
  66         }
  67 
  68         *size = lsize;
  69         return db;
  70 }
  71 
  72 /*
  73  * Blacklist a hash.
  74  */
  75 static __init void uefi_blacklist_hash(const char *source, const void *data,
  76                                        size_t len, const char *type,
  77                                        size_t type_len)
  78 {
  79         char *hash, *p;
  80 
  81         hash = kmalloc(type_len + len * 2 + 1, GFP_KERNEL);
  82         if (!hash)
  83                 return;
  84         p = memcpy(hash, type, type_len);
  85         p += type_len;
  86         bin2hex(p, data, len);
  87         p += len * 2;
  88         *p = 0;
  89 
  90         mark_hash_blacklisted(hash);
  91         kfree(hash);
  92 }
  93 
  94 /*
  95  * Blacklist an X509 TBS hash.
  96  */
  97 static __init void uefi_blacklist_x509_tbs(const char *source,
  98                                            const void *data, size_t len)
  99 {
 100         uefi_blacklist_hash(source, data, len, "tbs:", 4);
 101 }
 102 
 103 /*
 104  * Blacklist the hash of an executable.
 105  */
 106 static __init void uefi_blacklist_binary(const char *source,
 107                                          const void *data, size_t len)
 108 {
 109         uefi_blacklist_hash(source, data, len, "bin:", 4);
 110 }
 111 
 112 /*
 113  * Return the appropriate handler for particular signature list types found in
 114  * the UEFI db and MokListRT tables.
 115  */
 116 static __init efi_element_handler_t get_handler_for_db(const efi_guid_t *
 117                                                        sig_type)
 118 {
 119         if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
 120                 return add_to_platform_keyring;
 121         return 0;
 122 }
 123 
 124 /*
 125  * Return the appropriate handler for particular signature list types found in
 126  * the UEFI dbx and MokListXRT tables.
 127  */
 128 static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *
 129                                                         sig_type)
 130 {
 131         if (efi_guidcmp(*sig_type, efi_cert_x509_sha256_guid) == 0)
 132                 return uefi_blacklist_x509_tbs;
 133         if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0)
 134                 return uefi_blacklist_binary;
 135         return 0;
 136 }
 137 
 138 /*
 139  * Load the certs contained in the UEFI databases into the platform trusted
 140  * keyring and the UEFI blacklisted X.509 cert SHA256 hashes into the blacklist
 141  * keyring.
 142  */
 143 static int __init load_uefi_certs(void)
 144 {
 145         efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
 146         efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
 147         void *db = NULL, *dbx = NULL, *mok = NULL;
 148         unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
 149         efi_status_t status;
 150         int rc = 0;
 151 
 152         if (!efi.get_variable)
 153                 return false;
 154 
 155         /* Get db, MokListRT, and dbx.  They might not exist, so it isn't
 156          * an error if we can't get them.
 157          */
 158         if (!uefi_check_ignore_db()) {
 159                 db = get_cert_list(L"db", &secure_var, &dbsize, &status);
 160                 if (!db) {
 161                         if (status == EFI_NOT_FOUND)
 162                                 pr_debug("MODSIGN: db variable wasn't found\n");
 163                         else
 164                                 pr_err("MODSIGN: Couldn't get UEFI db list\n");
 165                 } else {
 166                         rc = parse_efi_signature_list("UEFI:db",
 167                                         db, dbsize, get_handler_for_db);
 168                         if (rc)
 169                                 pr_err("Couldn't parse db signatures: %d\n",
 170                                        rc);
 171                         kfree(db);
 172                 }
 173         }
 174 
 175         mok = get_cert_list(L"MokListRT", &mok_var, &moksize, &status);
 176         if (!mok) {
 177                 if (status == EFI_NOT_FOUND)
 178                         pr_debug("MokListRT variable wasn't found\n");
 179                 else
 180                         pr_info("Couldn't get UEFI MokListRT\n");
 181         } else {
 182                 rc = parse_efi_signature_list("UEFI:MokListRT",
 183                                               mok, moksize, get_handler_for_db);
 184                 if (rc)
 185                         pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
 186                 kfree(mok);
 187         }
 188 
 189         dbx = get_cert_list(L"dbx", &secure_var, &dbxsize, &status);
 190         if (!dbx) {
 191                 if (status == EFI_NOT_FOUND)
 192                         pr_debug("dbx variable wasn't found\n");
 193                 else
 194                         pr_info("Couldn't get UEFI dbx list\n");
 195         } else {
 196                 rc = parse_efi_signature_list("UEFI:dbx",
 197                                               dbx, dbxsize,
 198                                               get_handler_for_dbx);
 199                 if (rc)
 200                         pr_err("Couldn't parse dbx signatures: %d\n", rc);
 201                 kfree(dbx);
 202         }
 203 
 204         return rc;
 205 }
 206 late_initcall(load_uefi_certs);

/* [<][>][^][v][top][bottom][index][help] */