Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp4638059imu; Sun, 25 Nov 2018 07:23:32 -0800 (PST) X-Google-Smtp-Source: AFSGD/W9rdswP4UjBdSTiWcJj/TSsAMxh+GiNsHmWazsvuYW2I94z5L1DFwIetcfe7BUGjyx5GVl X-Received: by 2002:a63:1e17:: with SMTP id e23mr21121578pge.130.1543159412119; Sun, 25 Nov 2018 07:23:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1543159412; cv=none; d=google.com; s=arc-20160816; b=bZgHiDIlcA1OH9ULYUso3CccKwxnGevlkYmJv0nx7L5zyGVkT10xzbWaEnzpXDmz1H YlaHsBtzhczPqUahhKwpwrokuJaVXWVZi4x+7xbo80XyKMs1p8/uZYgSNYj27avktytI k7FuEl90BBSDMf7IH8tJYsn2ETiG2h0xXYVUJpgAlNKaDfH0YrQiPLkTVnfjLSKSh5Dp xUpPdAgH0K3cN5YxkEh8DVTmQBG5dg+Lc5VPY3hTshhATv1Dv9PS5NWOFWjMZ0bRoJF0 M8dqVSXaiSzpxpj7EaU+fIrZy7hdjoWHOvR7PbhvzPZr4ti1dIul+T8yTVAdAdDuN55Y 7KYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:references:in-reply-to:date :subject:cc:to:from; bh=/s0NeE7B5e3K1i/i+hGVmaD7CzqE0rb5yPBdM1oon2s=; b=qJ4YtzvI7a479lrw2DkxznoWNXtQJd4Pw4PxDngWLR3GGx9zvzLmSgEcnWxppuoX1O 0gkWNwp8EO0yKap8q4Fc+19JCAUyS/kKbrWLl6U61AjJMxVndN4cfAgzNrYjNGyte9Q3 sf0aCS+d5pAQDWoob/3cXBKaBiCN5StytHMAyLCj7IGgupiKhZWA7gWLI4Qgo6EHJTSi Q+/LW2tqWVGW1v46tMnnTGA7+yQEr5tL4qGFHBG+Pp+dX+uK/WTBnsNgGMNi41fwXnlM eTEPrnZtXNIGvANE2S7u+OR0MRyn0FKg0EZMRMGJEuN4J2TOl7t9/muPnYYQOcD2EhV+ +uXg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v34si4341456plg.205.2018.11.25.07.23.17; Sun, 25 Nov 2018 07:23:32 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726852AbeKZCKV (ORCPT + 99 others); Sun, 25 Nov 2018 21:10:21 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:41810 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726812AbeKZCKU (ORCPT ); Sun, 25 Nov 2018 21:10:20 -0500 Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id wAPFEehr134678 for ; Sun, 25 Nov 2018 10:19:03 -0500 Received: from e06smtp07.uk.ibm.com (e06smtp07.uk.ibm.com [195.75.94.103]) by mx0a-001b2d01.pphosted.com with ESMTP id 2nymh4eubg-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sun, 25 Nov 2018 10:19:03 -0500 Received: from localhost by e06smtp07.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sun, 25 Nov 2018 15:19:00 -0000 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp07.uk.ibm.com (192.168.101.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Sun, 25 Nov 2018 15:18:56 -0000 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id wAPFItJM39321734 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Sun, 25 Nov 2018 15:18:55 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1606C4C044; Sun, 25 Nov 2018 15:18:55 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D6F574C046; Sun, 25 Nov 2018 15:18:50 +0000 (GMT) Received: from swastik.ibmuc.com (unknown [9.85.72.131]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sun, 25 Nov 2018 15:18:50 +0000 (GMT) From: Nayna Jain To: linux-integrity@vger.kernel.org Cc: linux-security-module@vger.kernel.org, linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org, zohar@linux.ibm.com, dhowells@redhat.com, jforbes@redhat.com, seth.forshee@canonical.com, kexec@lists.infradead.org, keyrings@vger.kernel.org, vgoyal@redhat.com, ebiederm@xmission.com, mpe@ellerman.id.au, Josh Boyer , Nayna Jain Subject: [PATCH 5/7] efi: Import certificates from UEFI Secure Boot Date: Sun, 25 Nov 2018 20:44:58 +0530 X-Mailer: git-send-email 2.13.6 In-Reply-To: <20181125151500.8298-1-nayna@linux.ibm.com> References: <20181125151500.8298-1-nayna@linux.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 18112515-0028-0000-0000-00000321345A X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18112515-0029-0000-0000-000023DD3552 Message-Id: <20181125151500.8298-6-nayna@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:,, definitions=2018-11-25_14:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1811250071 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Josh Boyer New Patch Description: ====================== Secure Boot stores a list of allowed certificates in the 'db' variable. This patch imports those certificates into the platform keyring. The shim UEFI bootloader has a similar certificate list stored in the 'MokListRT' variable. We import those as well. Secure Boot also maintains a list of disallowed certificates in the 'dbx' variable. We load those certificates into the system blacklist keyring and forbid any kernel signed with those from loading. Original Patch Description: ============================ Secure Boot stores a list of allowed certificates in the 'db' variable. This imports those certificates into the system trusted keyring. This allows for a third party signing certificate to be used in conjunction with signed modules. By importing the public certificate into the 'db' variable, a user can allow a module signed with that certificate to load. The shim UEFI bootloader has a similar certificate list stored in the 'MokListRT' variable. We import those as well. Secure Boot also maintains a list of disallowed certificates in the 'dbx' variable. We load those certificates into the newly introduced system blacklist keyring and forbid any module signed with those from loading and forbid the use within the kernel of any key with a matching hash. This facility is enabled by setting CONFIG_LOAD_UEFI_KEYS. Signed-off-by: Josh Boyer Signed-off-by: David Howells Signed-off-by: Nayna Jain --- Changelog: v0: - This patch replaces the loading of certificates onto the secondary keyring with platform keyring - removed the CONFIG LOAD_UEFI_KEYS - moved the file load_uefi.o from certs to security/integrity/platform_certs security/integrity/Makefile | 5 +- security/integrity/platform_certs/load_uefi.c | 168 ++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 security/integrity/platform_certs/load_uefi.c diff --git a/security/integrity/Makefile b/security/integrity/Makefile index 6ee9058866cd..86df9aba8c0f 100644 --- a/security/integrity/Makefile +++ b/security/integrity/Makefile @@ -10,7 +10,10 @@ integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \ - platform_certs/efi_parser.o + platform_certs/efi_parser.o \ + platform_certs/load_uefi.o +obj-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/load_uefi.o +$(obj)/load_uefi.o: KBUILD_CFLAGS += -fshort-wchar subdir-$(CONFIG_IMA) += ima obj-$(CONFIG_IMA) += ima/ diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c new file mode 100644 index 000000000000..dbccb45147ef --- /dev/null +++ b/security/integrity/platform_certs/load_uefi.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "../integrity.h" + +static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID; +static __initdata efi_guid_t efi_cert_x509_sha256_guid = EFI_CERT_X509_SHA256_GUID; +static __initdata efi_guid_t efi_cert_sha256_guid = EFI_CERT_SHA256_GUID; + +/* + * Get a certificate list blob from the named EFI variable. + */ +static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, + unsigned long *size) +{ + efi_status_t status; + unsigned long lsize = 4; + unsigned long tmpdb[4]; + void *db; + + status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb); + if (status != EFI_BUFFER_TOO_SMALL) { + pr_err("Couldn't get size: 0x%lx\n", status); + return NULL; + } + + db = kmalloc(lsize, GFP_KERNEL); + if (!db) { + pr_err("Couldn't allocate memory for uefi cert list\n"); + return NULL; + } + + status = efi.get_variable(name, guid, NULL, &lsize, db); + if (status != EFI_SUCCESS) { + kfree(db); + pr_err("Error reading db var: 0x%lx\n", status); + return NULL; + } + + *size = lsize; + return db; +} + +/* + * Blacklist an X509 TBS hash. + */ +static __init void uefi_blacklist_x509_tbs(const char *source, + const void *data, size_t len) +{ + char *hash, *p; + + hash = kmalloc(4 + len * 2 + 1, GFP_KERNEL); + if (!hash) + return; + p = memcpy(hash, "tbs:", 4); + p += 4; + bin2hex(p, data, len); + p += len * 2; + *p = 0; + + mark_hash_blacklisted(hash); + kfree(hash); +} + +/* + * Blacklist the hash of an executable. + */ +static __init void uefi_blacklist_binary(const char *source, + const void *data, size_t len) +{ + char *hash, *p; + + hash = kmalloc(4 + len * 2 + 1, GFP_KERNEL); + if (!hash) + return; + p = memcpy(hash, "bin:", 4); + p += 4; + bin2hex(p, data, len); + p += len * 2; + *p = 0; + + mark_hash_blacklisted(hash); + kfree(hash); +} + +/* + * Return the appropriate handler for particular signature list types found in + * the UEFI db and MokListRT tables. + */ +static __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type) +{ + if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) + return add_to_platform_keyring; + return 0; +} + +/* + * Return the appropriate handler for particular signature list types found in + * the UEFI dbx and MokListXRT tables. + */ +static __init efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type) +{ + if (efi_guidcmp(*sig_type, efi_cert_x509_sha256_guid) == 0) + return uefi_blacklist_x509_tbs; + if (efi_guidcmp(*sig_type, efi_cert_sha256_guid) == 0) + return uefi_blacklist_binary; + return 0; +} + +/* + * Load the certs contained in the UEFI databases + */ +static int __init load_uefi_certs(void) +{ + efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID; + efi_guid_t mok_var = EFI_SHIM_LOCK_GUID; + void *db = NULL, *dbx = NULL, *mok = NULL; + unsigned long dbsize = 0, dbxsize = 0, moksize = 0; + int rc = 0; + + if (!efi.get_variable) + return false; + + /* Get db, MokListRT, and dbx. They might not exist, so it isn't + * an error if we can't get them. + */ + db = get_cert_list(L"db", &secure_var, &dbsize); + if (!db) { + pr_err("Couldn't get UEFI db list\n"); + } else { + rc = parse_efi_signature_list("UEFI:db", + db, dbsize, get_handler_for_db); + if (rc) + pr_err("Couldn't parse db signatures: %d\n", rc); + kfree(db); + } + + mok = get_cert_list(L"MokListRT", &mok_var, &moksize); + if (!mok) { + pr_info("Couldn't get UEFI MokListRT\n"); + } else { + rc = parse_efi_signature_list("UEFI:MokListRT", + mok, moksize, get_handler_for_db); + if (rc) + pr_err("Couldn't parse MokListRT signatures: %d\n", rc); + kfree(mok); + } + + dbx = get_cert_list(L"dbx", &secure_var, &dbxsize); + if (!dbx) { + pr_info("Couldn't get UEFI dbx list\n"); + } else { + rc = parse_efi_signature_list("UEFI:dbx", + dbx, dbxsize, + get_handler_for_dbx); + if (rc) + pr_err("Couldn't parse dbx signatures: %d\n", rc); + kfree(dbx); + } + + return rc; +} +late_initcall(load_uefi_certs); -- 2.13.6