From patchwork Tue Dec 4 07:39:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711197 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8699016B1 for ; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 724B72A544 for ; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 667442A59A; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 777992A582 for ; Tue, 4 Dec 2018 07:37:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726052AbeLDHh0 (ORCPT ); Tue, 4 Dec 2018 02:37:26 -0500 Received: from mga14.intel.com ([192.55.52.115]:52443 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726027AbeLDHh0 (ORCPT ); Tue, 4 Dec 2018 02:37:26 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="97861634" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga006.jf.intel.com with ESMTP; 03 Dec 2018 23:37:22 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 01/13] x86/mktme: Document the MKTME APIs Date: Mon, 3 Dec 2018 23:39:48 -0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This includes an overview, a section on each API: MTKME Keys and system call encrypt_mprotect(), and a demonstration program. (Some of this info is destined for man pages.) Change-Id: I34dc9ff1a1308c057ec4bb3e652c4d7ce6995606 Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- Documentation/x86/mktme/index.rst | 11 +++ Documentation/x86/mktme/mktme_demo.rst | 53 ++++++++++++++ Documentation/x86/mktme/mktme_encrypt.rst | 58 +++++++++++++++ Documentation/x86/mktme/mktme_keys.rst | 109 +++++++++++++++++++++++++++++ Documentation/x86/mktme/mktme_overview.rst | 60 ++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 Documentation/x86/mktme/index.rst create mode 100644 Documentation/x86/mktme/mktme_demo.rst create mode 100644 Documentation/x86/mktme/mktme_encrypt.rst create mode 100644 Documentation/x86/mktme/mktme_keys.rst create mode 100644 Documentation/x86/mktme/mktme_overview.rst diff --git a/Documentation/x86/mktme/index.rst b/Documentation/x86/mktme/index.rst new file mode 100644 index 000000000000..8c556d04cbc4 --- /dev/null +++ b/Documentation/x86/mktme/index.rst @@ -0,0 +1,11 @@ + +============================================= +Multi-Key Total Memory Encryption (MKTME) API +============================================= + +.. toctree:: + + mktme_overview + mktme_keys + mktme_encrypt + mktme_demo diff --git a/Documentation/x86/mktme/mktme_demo.rst b/Documentation/x86/mktme/mktme_demo.rst new file mode 100644 index 000000000000..afd50772e65d --- /dev/null +++ b/Documentation/x86/mktme/mktme_demo.rst @@ -0,0 +1,53 @@ +Demonstration Program using MKTME API's +======================================= + +/* Compile with the keyutils library: cc -o mdemo mdemo.c -lkeyutils */ + +#include +#include +#include +#include +#include +#include +#include + +#define PAGE_SIZE sysconf(_SC_PAGE_SIZE) +#define sys_encrypt_mprotect 335 + +void main(void) +{ + char *options_CPU = "algorithm=aes-xts-128 type=cpu"; + long size = PAGE_SIZE; + key_serial_t key; + void *ptra; + int ret; + + /* Allocate an MKTME Key */ + key = add_key("mktme", "testkey", options_CPU, strlen(options_CPU), + KEY_SPEC_THREAD_KEYRING); + + if (key == -1) { + printf("addkey FAILED\n"); + return; + } + /* Map a page of ANONYMOUS memory */ + ptra = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if (!ptra) { + printf("failed to mmap"); + goto inval_key; + } + /* Encrypt that page of memory with the MKTME Key */ + ret = syscall(sys_encrypt_mprotect, ptra, size, PROT_NONE, key); + if (ret) + printf("mprotect error [%d]\n", ret); + + /* Enjoy that page of encrypted memory */ + + /* Free the memory */ + ret = munmap(ptra, size); + +inval_key: + /* Free the Key */ + if (keyctl(KEYCTL_INVALIDATE, key) == -1) + printf("invalidate failed on key [%d]\n", key); +} diff --git a/Documentation/x86/mktme/mktme_encrypt.rst b/Documentation/x86/mktme/mktme_encrypt.rst new file mode 100644 index 000000000000..ede5237183fc --- /dev/null +++ b/Documentation/x86/mktme/mktme_encrypt.rst @@ -0,0 +1,58 @@ +MKTME API: system call encrypt_mprotect() +========================================= + +Synopsis +-------- +int encrypt_mprotect(void \*addr, size_t len, int prot, key_serial_t serial); + +Where *key_serial_t serial* is the serial number of a key allocated +using the MKTME Key Service. + +Description +----------- + encrypt_mprotect() encrypts the memory pages containing any part + of the address range in the interval specified by addr and len. + + encrypt_mprotect() supports the legacy mprotect() behavior plus + the enabling of memory encryption. That means that in addition + to encrypting the memory, the protection flags will be updated + as requested in the call. + + The *addr* and *len* must be aligned to a page boundary. + + The caller must have *KEY_NEED_VIEW* permission on the key. + + The range of memory that is to be protected must be mapped as + *ANONYMOUS*. + +Errors +------ + In addition to the Errors returned from legacy mprotect() + encrypt_mprotect will return: + + ENOKEY *serial* parameter does not represent a valid key. + + EINVAL *len* parameter is not page aligned. + + EACCES Caller does not have *KEY_NEED_VIEW* permission on the key. + +EXAMPLE +-------- + Allocate an MKTME Key:: + serial = add_key("mktme", "name", "type=cpu algorithm=aes-xts-128" @u + + Map ANONYMOUS memory:: + ptr = mmap(NULL, size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + + Protect memory:: + ret = syscall(SYS_encrypt_mprotect, ptr, size, PROT_READ|PROT_WRITE, + serial); + + Use the encrypted memory + + Free memory:: + ret = munmap(ptr, size); + + Free the key resource:: + ret = keyctl(KEYCTL_INVALIDATE, serial); + diff --git a/Documentation/x86/mktme/mktme_keys.rst b/Documentation/x86/mktme/mktme_keys.rst new file mode 100644 index 000000000000..5837909b2c54 --- /dev/null +++ b/Documentation/x86/mktme/mktme_keys.rst @@ -0,0 +1,109 @@ +MKTME Key Service API +===================== +MKTME is a new key service type added to the Linux Kernel Key Service. + +The MKTME Key Service type is available when CONFIG_X86_INTEL_MKTME is +turned on in Intel platforms that support the MKTME feature. + +The MKTME Key Service type manages the allocation of hardware encryption +keys. Users can request an MKTME type key and then use that key to +encrypt memory with the encrypt_mprotect() system call. + +Usage +----- + When using the Kernel Key Service to request an *mktme* key, + specify the *payload* as follows: + + type= + *user* User will supply the encryption key data. Use this + type to directly program a hardware encryption key. + + *cpu* User requests a CPU generated encryption key. + The CPU generates and assigns an ephemeral key. + + *clear* User requests that a hardware encryption key be + cleared. This will clear the encryption key from + the hardware. On execution this hardware key gets + TME behavior. + + *no-encrypt* + User requests that hardware does not encrypt + memory when this key is in use. + + algorithm= + When type=user or type=cpu the algorithm field must be + *aes-xts-128* + + When type=clear or type=no-encrypt the algorithm field + must not be present in the payload. + + key= + When type=user the user must supply a 128 bit encryption + key as exactly 32 ASCII hexadecimal characters. + + When type=cpu the user may optionally supply 128 bits of + entropy for the CPU generated encryption key in this field. + It must be exactly 32 ASCII hexadecimal characters. + + When type=clear or type=no-encrypt this key field must + not be present in the payload. + + tweak= + When type=user the user must supply a 128 bit tweak key + as exactly 32 ASCII hexadecimal characters. + + When type=cpu the user may optionally supply 128 bits of + entropy for the CPU generated tweak key in this field. It + must be exactly 32 ASCII hexadecimal characters. + + When type=clear or type=no-encrypt the tweak field must + not be present in the payload. + +ERRORS +------ + In addition to the Errors returned from the Kernel Key Service, + add_key(2) or keyctl(1) commands, the MKTME Key Service type may + return the following errors: + + EINVAL for any payload specification that does not match the + MKTME type payload as defined above. + EACCES for access denied. MKTME key type uses capabilities to + restrict the allocation of keys. CAP_SYS_RESOURCE is + required, but it will accept the broader capability of + CAP_SYS_ADMIN. See capabilities(7). + + ENOKEY if a hardware key cannot be allocated. Additional error + messages will describe the hardware programming errors. + +EXAMPLES +-------- + Add a 'user' type key:: + + char \*options_USER = "type=user + algorithm=aes-xts-128 + key=12345678912345671234567891234567 + tweak=12345678912345671234567891234567"; + + key = add_key("mktme", "name", options_USER, strlen(options_USER), + KEY_SPEC_THREAD_KEYRING); + + Add a 'cpu' type key:: + + char \*options_USER = "type=cpu algorithm=aes-xts-128"; + + key = add_key("mktme", "name", options_CPU, strlen(options_CPU), + KEY_SPEC_THREAD_KEYRING); + + Update a key to 'Clear' type:: + + Note: This has the effect of clearing out the previously programmed + encryption data in the hardware. Use this to clear the hardware slot + prior to invalidating the key. + + ret = keyctl(KEYCTL_UPDATE, key, "type=clear", strlen(options_CLEAR); + + Add a "no-encrypt' type key:: + + key = add_key("mktme", "name", "no-encrypt", strlen(options_CPU), + KEY_SPEC_THREAD_KEYRING); + diff --git a/Documentation/x86/mktme/mktme_overview.rst b/Documentation/x86/mktme/mktme_overview.rst new file mode 100644 index 000000000000..cc2c4a8320e7 --- /dev/null +++ b/Documentation/x86/mktme/mktme_overview.rst @@ -0,0 +1,60 @@ +Overview +======== +MKTME (Multi-Key Total Memory Encryption) is a technology that allows +memory encryption on Intel platforms. The main use case for the feature +is virtual machine isolation. The API should apply to a wide range of +use cases. + +Find the Intel Architecture Specification for MKTME here: +https://software.intel.com/sites/default/files/managed/a5/16/Multi-Key-Total-Memory-Encryption-Spec.pdf + +The Encryption Process +---------------------- +Userspace will see MKTME encryption as a Step Process. + +Step 1: Use the MKTME Key Service API to allocate an encryption key. + +Step 2: Use the encrypt_mprotect() system call to protect memory + with the encryption key obtained in Step 1. + +Definitions +----------- +Keys: References to Keys in this document are to Userspace Keys. + These keys are requested by users and jointly managed by the + MKTME Key Service Type, and more broadly by the Kernel Key + Service of which MKTME is a part. + + This document does not intend to document KKS, but only the + MKTME type of the KKS. The options of the KKS can be grouped + into 2 classes for purposes of understanding how MKTME operates + within the broader KKS. + +KeyIDs: References to KeyIDs in this document are to the hardware KeyID + slots that are available on Intel Platforms. A KeyID is a + numerical index into a software programmable slot in the Intel + hardware. Refer to the Intel specification linked above for + details on the implementation of MKTME in Intel platforms. + +Key<-->KeyID Mapping: + The MKTME Key Service maintains a mapping between Keys and KeyIDS. + This mapping is known only to the kernel. Userspace does not need + to know which hardware KeyID slot it's Userspace Key has been + assigned. + +Configuration +------------- + +CONFIG_X86_INTEL_MKTME + MKTME is enabled by selecting CONFIG_X86_INTEL_MKTME on Intel + platforms supporting the MKTME feature. + +mktme_savekeys + mktme_savekeys is a kernel cmdline parameter. + + This parameter allows the kernel to save the user specified + MKTME key payload. Saving this payload means that the MKTME + Key Service can always allow the addition of new physical + packages. If the mktme_savekeys parameter is not present, + users key data will not be saved, and new physical packages + may only be added to the system if no user type MKTME keys + are in use. From patchwork Tue Dec 4 07:39:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711187 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A0DA216B1 for ; Tue, 4 Dec 2018 07:37:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7CB802A506 for ; Tue, 4 Dec 2018 07:37:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6DC9A2A57C; Tue, 4 Dec 2018 07:37:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E4332A506 for ; Tue, 4 Dec 2018 07:37:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725983AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 Received: from mga03.intel.com ([134.134.136.65]:5832 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725994AbeLDHhY (ORCPT ); Tue, 4 Dec 2018 02:37:24 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="98463926" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga008.jf.intel.com with ESMTP; 03 Dec 2018 23:37:22 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 02/13] mm: Generalize the mprotect implementation to support extensions Date: Mon, 3 Dec 2018 23:39:49 -0800 Message-Id: <3389bc8e46479ba102f88c157aebd49b905ac289.1543903910.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Today mprotect is implemented to support legacy mprotect behavior plus an extension for memory protection keys. Make it more generic so that it can support additional extensions in the future. This is done is preparation for adding a new system call for memory encyption keys. The intent is that the new encrypted mprotect will be another extension to legacy mprotect. Change-Id: Ib09b9d1b605b12d0254d7fb4968dfcc8e3c79dd7 Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- mm/mprotect.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mm/mprotect.c b/mm/mprotect.c index df408956dccc..b57075e278fb 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -35,6 +35,8 @@ #include "internal.h" +#define NO_KEY -1 + static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, unsigned long end, pgprot_t newprot, int dirty_accountable, int prot_numa) @@ -451,9 +453,9 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, } /* - * pkey==-1 when doing a legacy mprotect() + * When pkey==NO_KEY we get legacy mprotect behavior here. */ -static int do_mprotect_pkey(unsigned long start, size_t len, +static int do_mprotect_ext(unsigned long start, size_t len, unsigned long prot, int pkey) { unsigned long nstart, end, tmp, reqprot; @@ -577,7 +579,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len, SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, unsigned long, prot) { - return do_mprotect_pkey(start, len, prot, -1); + return do_mprotect_ext(start, len, prot, NO_KEY); } #ifdef CONFIG_ARCH_HAS_PKEYS @@ -585,7 +587,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len, SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len, unsigned long, prot, int, pkey) { - return do_mprotect_pkey(start, len, prot, pkey); + return do_mprotect_ext(start, len, prot, pkey); } SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val) From patchwork Tue Dec 4 07:39:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711207 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3A8D116B1 for ; Tue, 4 Dec 2018 07:37:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2712D2A46B for ; Tue, 4 Dec 2018 07:37:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1B81C2A57C; Tue, 4 Dec 2018 07:37:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AD23C2A544 for ; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726059AbeLDHh2 (ORCPT ); Tue, 4 Dec 2018 02:37:28 -0500 Received: from mga14.intel.com ([192.55.52.115]:52443 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726013AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="95937319" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga007.jf.intel.com with ESMTP; 03 Dec 2018 23:37:22 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 03/13] syscall/x86: Wire up a new system call for memory encryption keys Date: Mon, 3 Dec 2018 23:39:50 -0800 Message-Id: <952381f6d8b394242590f03a4f7122789681ffbb.1543903910.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP encrypt_mprotect() is a new system call to support memory encryption. It takes the same parameters as legacy mprotect, plus an additional key serial number that is mapped to an encryption keyid. Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/entry/syscalls/syscall_64.tbl | 1 + include/linux/syscalls.h | 2 ++ include/uapi/asm-generic/unistd.h | 4 +++- kernel/sys_ni.c | 2 ++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 3cf7b533b3d1..f41ad857d5c6 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -398,3 +398,4 @@ 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl 385 i386 io_pgetevents sys_io_pgetevents __ia32_compat_sys_io_pgetevents 386 i386 rseq sys_rseq __ia32_sys_rseq +387 i386 encrypt_mprotect sys_encrypt_mprotect __ia32_sys_encrypt_mprotect diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index f0b1709a5ffb..cf2decfa6119 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -343,6 +343,7 @@ 332 common statx __x64_sys_statx 333 common io_pgetevents __x64_sys_io_pgetevents 334 common rseq __x64_sys_rseq +335 common encrypt_mprotect __x64_sys_encrypt_mprotect # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 2ac3d13a915b..c728b47e9004 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -907,6 +907,8 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer); asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, int flags, uint32_t sig); +asmlinkage long sys_encrypt_mprotect(unsigned long start, size_t len, + unsigned long prot, key_serial_t serial); /* * Architecture-specific system calls diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 538546edbfbd..696c222ebe40 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -738,9 +738,11 @@ __SYSCALL(__NR_statx, sys_statx) __SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents) #define __NR_rseq 293 __SYSCALL(__NR_rseq, sys_rseq) +#define __NR_encrypt_mprotect 294 +__SYSCALL(__NR_encrypt_mprotect, sys_encrypt_mprotect) #undef __NR_syscalls -#define __NR_syscalls 294 +#define __NR_syscalls 295 /* * 32 bit systems traditionally used different diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index df556175be50..1b48f709c265 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -336,6 +336,8 @@ COND_SYSCALL(pkey_mprotect); COND_SYSCALL(pkey_alloc); COND_SYSCALL(pkey_free); +/* multi-key total memory encryption keys */ +COND_SYSCALL(encrypt_mprotect); /* * Architecture specific weak syscall entries. From patchwork Tue Dec 4 07:39:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711199 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D6C1117D5 for ; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C31722A53E for ; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B77572A582; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 304352A53E for ; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726036AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 Received: from mga02.intel.com ([134.134.136.20]:63183 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726005AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:22 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="256618438" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga004.jf.intel.com with ESMTP; 03 Dec 2018 23:37:22 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 04/13] x86/mm: Add helper functions for MKTME memory encryption keys Date: Mon, 3 Dec 2018 23:39:51 -0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Define a global mapping structure to manage the mapping of userspace Keys to hardware KeyIDs in MKTME (Multi-Key Total Memory Encryption). Implement helper functions that access this mapping structure. The helpers will be used by these MKTME API's: > Key Service API: security/keys/mktme_keys.c > encrypt_mprotect() system call: mm/mprotect.c Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- arch/x86/include/asm/mktme.h | 12 ++++++ arch/x86/mm/mktme.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/arch/x86/include/asm/mktme.h b/arch/x86/include/asm/mktme.h index f05baa15e6f6..dbb49909d665 100644 --- a/arch/x86/include/asm/mktme.h +++ b/arch/x86/include/asm/mktme.h @@ -12,6 +12,18 @@ extern phys_addr_t mktme_keyid_mask; extern int mktme_nr_keyids; extern int mktme_keyid_shift; +/* Manage mappings between hardware KeyIDs and userspace Keys */ +extern int mktme_map_alloc(void); +extern void mktme_map_free(void); +extern void mktme_map_lock(void); +extern void mktme_map_unlock(void); +extern int mktme_map_mapped_keyids(void); +extern void mktme_map_set_keyid(int keyid, void *key); +extern void mktme_map_free_keyid(int keyid); +extern int mktme_map_keyid_from_key(void *key); +extern void *mktme_map_key_from_keyid(int keyid); +extern int mktme_map_get_free_keyid(void); + DECLARE_STATIC_KEY_FALSE(mktme_enabled_key); static inline bool mktme_enabled(void) { diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index c81727540e7c..34224d4e3f45 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -40,6 +40,97 @@ int __vma_keyid(struct vm_area_struct *vma) return (prot & mktme_keyid_mask) >> mktme_keyid_shift; } +/* + * struct mktme_map and the mktme_map_* functions manage the mapping + * of userspace Keys to hardware KeyIDs. These are used by the MKTME Key + * Service API and the encrypt_mprotect() system call. + */ + +struct mktme_mapping { + struct mutex lock; /* protect this map & HW state */ + unsigned int mapped_keyids; + void *key[]; +}; + +struct mktme_mapping *mktme_map; + +static inline long mktme_map_size(void) +{ + long size = 0; + + size += sizeof(*mktme_map); + size += sizeof(mktme_map->key[0]) * (mktme_nr_keyids + 1); + return size; +} + +int mktme_map_alloc(void) +{ + mktme_map = kvzalloc(mktme_map_size(), GFP_KERNEL); + if (!mktme_map) + return 0; + mutex_init(&mktme_map->lock); + return 1; +} + +void mktme_map_free(void) +{ + kvfree(mktme_map); +} + +void mktme_map_lock(void) +{ + mutex_lock(&mktme_map->lock); +} + +void mktme_map_unlock(void) +{ + mutex_unlock(&mktme_map->lock); +} + +int mktme_map_mapped_keyids(void) +{ + return mktme_map->mapped_keyids; +} + +void mktme_map_set_keyid(int keyid, void *key) +{ + mktme_map->key[keyid] = key; + mktme_map->mapped_keyids++; +} + +void mktme_map_free_keyid(int keyid) +{ + mktme_map->key[keyid] = 0; + mktme_map->mapped_keyids--; +} + +int mktme_map_keyid_from_key(void *key) +{ + int i; + + for (i = 1; i <= mktme_nr_keyids; i++) + if (mktme_map->key[i] == key) + return i; + return 0; +} + +void *mktme_map_key_from_keyid(int keyid) +{ + return mktme_map->key[keyid]; +} + +int mktme_map_get_free_keyid(void) +{ + int i; + + if (mktme_map->mapped_keyids < mktme_nr_keyids) { + for (i = 1; i <= mktme_nr_keyids; i++) + if (mktme_map->key[i] == 0) + return i; + } + return 0; +} + /* Prepare page to be used for encryption. Called from page allocator. */ void __prep_encrypted_page(struct page *page, int order, int keyid, bool zero) { From patchwork Tue Dec 4 07:39:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711205 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E640D1923 for ; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D32F32A46B for ; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C796C2A5A7; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 644AE2A46B for ; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726054AbeLDHh2 (ORCPT ); Tue, 4 Dec 2018 02:37:28 -0500 Received: from mga05.intel.com ([192.55.52.43]:27404 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725996AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="299106228" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by fmsmga006.fm.intel.com with ESMTP; 03 Dec 2018 23:37:22 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 05/13] x86/mm: Set KeyIDs in encrypted VMAs Date: Mon, 3 Dec 2018 23:39:52 -0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP MKTME architecture requires the KeyID to be placed in PTE bits 51:46. To create an encrypted VMA, place the KeyID in the upper bits of vm_page_prot that matches the position of those PTE bits. When the VMA is assigned a KeyID it is always considered a KeyID change. The VMA is either going from not encrypted to encrypted, or from encrypted with any KeyID to encrypted with any other KeyID. To make the change safely, remove the user pages held by the VMA and unlink the VMA's anonymous chain. Change-Id: I676056525c49c8803898315a10b196ef5a5c5415 Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- arch/x86/include/asm/mktme.h | 4 ++++ arch/x86/mm/mktme.c | 26 ++++++++++++++++++++++++++ include/linux/mm.h | 6 ++++++ 3 files changed, 36 insertions(+) diff --git a/arch/x86/include/asm/mktme.h b/arch/x86/include/asm/mktme.h index dbb49909d665..de3e529f3ab0 100644 --- a/arch/x86/include/asm/mktme.h +++ b/arch/x86/include/asm/mktme.h @@ -24,6 +24,10 @@ extern int mktme_map_keyid_from_key(void *key); extern void *mktme_map_key_from_keyid(int keyid); extern int mktme_map_get_free_keyid(void); +/* Set the encryption keyid bits in a VMA */ +extern void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid, + unsigned long start, unsigned long end); + DECLARE_STATIC_KEY_FALSE(mktme_enabled_key); static inline bool mktme_enabled(void) { diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index 34224d4e3f45..e3fdf7b48173 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -131,6 +132,31 @@ int mktme_map_get_free_keyid(void) return 0; } +/* Set the encryption keyid bits in a VMA */ +void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid, + unsigned long start, unsigned long end) +{ + int oldkeyid = vma_keyid(vma); + pgprotval_t newprot; + + /* Unmap pages with old KeyID if there's any. */ + zap_page_range(vma, start, end - start); + + if (oldkeyid == newkeyid) + return; + + newprot = pgprot_val(vma->vm_page_prot); + newprot &= ~mktme_keyid_mask; + newprot |= (unsigned long)newkeyid << mktme_keyid_shift; + vma->vm_page_prot = __pgprot(newprot); + + /* + * The VMA doesn't have any inherited pages. + * Start anon VMA tree from scratch. + */ + unlink_anon_vmas(vma); +} + /* Prepare page to be used for encryption. Called from page allocator. */ void __prep_encrypted_page(struct page *page, int order, int keyid, bool zero) { diff --git a/include/linux/mm.h b/include/linux/mm.h index 1309761bb6d0..e2d87e92ca74 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2806,5 +2806,11 @@ void __init setup_nr_node_ids(void); static inline void setup_nr_node_ids(void) {} #endif +#ifndef CONFIG_X86_INTEL_MKTME +static inline void mprotect_set_encrypt(struct vm_area_struct *vma, + int newkeyid, + unsigned long start, + unsigned long end) {} +#endif /* CONFIG_X86_INTEL_MKTME */ #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ From patchwork Tue Dec 4 07:39:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711193 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8027D13BF for ; Tue, 4 Dec 2018 07:37:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6E9822A46B for ; Tue, 4 Dec 2018 07:37:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 62B962A57C; Tue, 4 Dec 2018 07:37:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EB63C2A46B for ; Tue, 4 Dec 2018 07:37:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726045AbeLDHh0 (ORCPT ); Tue, 4 Dec 2018 02:37:26 -0500 Received: from mga05.intel.com ([192.55.52.43]:27404 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725994AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="106817038" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by fmsmga008.fm.intel.com with ESMTP; 03 Dec 2018 23:37:23 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 07/13] x86/mm: Add helpers for reference counting encrypted VMAs Date: Mon, 3 Dec 2018 23:39:54 -0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP In order to safely manage the usage of memory encryption keys, VMAs using each KeyID need to be counted. This count allows the MKTME (Multi-Key Total Memory Encryption) Key Service to know when the KeyID resource is actually in use, or when it is idle and may be considered for reuse. Define a global refcount_t array and provide helper functions to manipulate the counts. Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- arch/x86/include/asm/mktme.h | 9 +++++++ arch/x86/mm/mktme.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mm.h | 2 ++ 3 files changed, 69 insertions(+) diff --git a/arch/x86/include/asm/mktme.h b/arch/x86/include/asm/mktme.h index de3e529f3ab0..22d52635562c 100644 --- a/arch/x86/include/asm/mktme.h +++ b/arch/x86/include/asm/mktme.h @@ -28,6 +28,15 @@ extern int mktme_map_get_free_keyid(void); extern void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid, unsigned long start, unsigned long end); +/* Manage the MTKME encrypt_count references */ +extern int mktme_alloc_encrypt_array(void); +extern void mktme_free_encrypt_array(void); +extern int mktme_read_encrypt_ref(int keyid); +extern void vma_get_encrypt_ref(struct vm_area_struct *vma); +extern void vma_put_encrypt_ref(struct vm_area_struct *vma); +extern void key_get_encrypt_ref(int keyid); +extern void key_put_encrypt_ref(int keyid); + DECLARE_STATIC_KEY_FALSE(mktme_enabled_key); static inline bool mktme_enabled(void) { diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index e3fdf7b48173..facf08f9cb74 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -157,6 +157,64 @@ void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid, unlink_anon_vmas(vma); } +/* + * Helper functions manage the encrypt_count[] array that counts + * references on each MKTME hardware keyid. The gets & puts are + * used in core mm code that allocates and free's VMA's. The alloc, + * free, and read functions are used by the MKTME key service to + * manage key allocation and programming. + */ +refcount_t *encrypt_count; + +int mktme_alloc_encrypt_array(void) +{ + encrypt_count = kvcalloc(mktme_nr_keyids, sizeof(refcount_t), + GFP_KERNEL); + if (!encrypt_count) + return -ENOMEM; + return 0; +} + +void mktme_free_encrypt_array(void) +{ + kvfree(encrypt_count); +} + +int mktme_read_encrypt_ref(int keyid) +{ + return refcount_read(&encrypt_count[keyid]); +} + +void vma_get_encrypt_ref(struct vm_area_struct *vma) +{ + if (vma_keyid(vma)) + refcount_inc(&encrypt_count[vma_keyid(vma)]); +} + +void vma_put_encrypt_ref(struct vm_area_struct *vma) +{ + if (vma_keyid(vma)) + if (refcount_dec_and_test(&encrypt_count[vma_keyid(vma)])) { + mktme_map_lock(); + mktme_map_free_keyid(vma_keyid(vma)); + mktme_map_unlock(); + } +} + +void key_get_encrypt_ref(int keyid) +{ + refcount_inc(&encrypt_count[keyid]); +} + +void key_put_encrypt_ref(int keyid) +{ + if (refcount_dec_and_test(&encrypt_count[keyid])) { + mktme_map_lock(); + mktme_map_free_keyid(keyid); + mktme_map_unlock(); + } +} + /* Prepare page to be used for encryption. Called from page allocator. */ void __prep_encrypted_page(struct page *page, int order, int keyid, bool zero) { diff --git a/include/linux/mm.h b/include/linux/mm.h index 09182d78e7b7..453d675dd116 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2812,6 +2812,8 @@ static inline void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid, unsigned long start, unsigned long end) {} +static inline void vma_get_encrypt_ref(struct vm_area_struct *vma) {} +static inline void vma_put_encrypt_ref(struct vm_area_struct *vma) {} #endif /* CONFIG_X86_INTEL_MKTME */ #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ From patchwork Tue Dec 4 07:39:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711201 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8324813BF for ; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6E5DD2A544 for ; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 62CBF2A57C; Tue, 4 Dec 2018 07:37:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 01B272A46B for ; Tue, 4 Dec 2018 07:37:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726042AbeLDHh0 (ORCPT ); Tue, 4 Dec 2018 02:37:26 -0500 Received: from mga12.intel.com ([192.55.52.136]:55172 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726035AbeLDHhZ (ORCPT ); Tue, 4 Dec 2018 02:37:25 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:25 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="115858977" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by FMSMGA003.fm.intel.com with ESMTP; 03 Dec 2018 23:37:24 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 08/13] mm: Use reference counting for encrypted VMAs Date: Mon, 3 Dec 2018 23:39:55 -0800 Message-Id: <985ba614d49986fdfc0397434fd1dd9eb5646c6f.1543903910.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP The MKTME (Multi-Key Total Memory Encryption) Key Service needs a reference count on encrypted VMAs. This reference count is used to determine when a hardware encryption keyid is in use, which in turn, tells the key service what operations can be safely performed with this keyid. The approach is: 1) Increment/decrement the reference count during encrypt_mprotect() system call for initial or updated encryption on a VMA. 2) Piggy back on the new vm_area_dup/free() helpers. If the VMAs being duplicated, or freed are encrypted, adjust the reference count. Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- arch/x86/mm/mktme.c | 2 ++ kernel/fork.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index facf08f9cb74..55d34beb9b81 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -145,10 +145,12 @@ void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid, if (oldkeyid == newkeyid) return; + vma_put_encrypt_ref(vma); newprot = pgprot_val(vma->vm_page_prot); newprot &= ~mktme_keyid_mask; newprot |= (unsigned long)newkeyid << mktme_keyid_shift; vma->vm_page_prot = __pgprot(newprot); + vma_get_encrypt_ref(vma); /* * The VMA doesn't have any inherited pages. diff --git a/kernel/fork.c b/kernel/fork.c index 07cddff89c7b..d12d27b50966 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -341,12 +341,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) if (new) { *new = *orig; INIT_LIST_HEAD(&new->anon_vma_chain); + vma_get_encrypt_ref(new); } return new; } void vm_area_free(struct vm_area_struct *vma) { + vma_put_encrypt_ref(vma); kmem_cache_free(vm_area_cachep, vma); } From patchwork Tue Dec 4 07:39:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711219 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEAD11923 for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ACA242A53E for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A0AC12A59A; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4A1962A53E for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726084AbeLDHhb (ORCPT ); Tue, 4 Dec 2018 02:37:31 -0500 Received: from mga07.intel.com ([134.134.136.100]:2376 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725994AbeLDHha (ORCPT ); Tue, 4 Dec 2018 02:37:30 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="124858776" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by fmsmga004.fm.intel.com with ESMTP; 03 Dec 2018 23:37:25 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 09/13] mm: Restrict memory encryption to anonymous VMA's Date: Mon, 3 Dec 2018 23:39:56 -0800 Message-Id: <0b294e74f06a0d6bee51efcd7b0eb1f20b00babe.1543903910.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Memory encryption is only supported for mappings that are ANONYMOUS. Test the entire range of VMA's in an encrypt_mprotect() request to make sure they all meet that requirement before encrypting any. The encrypt_mprotect syscall will return -EINVAL and will not encrypt any VMA's if this check fails. Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- mm/mprotect.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mm/mprotect.c b/mm/mprotect.c index ad8127dc9aac..f1c009409134 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -345,6 +345,24 @@ static int prot_none_walk(struct vm_area_struct *vma, unsigned long start, return walk_page_range(start, end, &prot_none_walk); } +/* + * Encrypted mprotect is only supported on anonymous mappings. + * All VMA's in the requested range must be anonymous. If this + * test fails on any single VMA, the entire mprotect request fails. + */ +bool mem_supports_encryption(struct vm_area_struct *vma, unsigned long end) +{ + struct vm_area_struct *test_vma = vma; + + do { + if (!vma_is_anonymous(test_vma)) + return false; + + test_vma = test_vma->vm_next; + } while (test_vma && test_vma->vm_start < end); + return true; +} + int mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, unsigned long start, unsigned long end, unsigned long newflags, @@ -531,6 +549,12 @@ static int do_mprotect_ext(unsigned long start, size_t len, goto out; } } + + if (keyid > 0 && !mem_supports_encryption(vma, end)) { + error = -EINVAL; + goto out; + } + if (start > vma->vm_start) prev = vma; From patchwork Tue Dec 4 07:39:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711209 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2622216B1 for ; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 130E82A46B for ; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0702B2A57C; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1296A2A53E for ; Tue, 4 Dec 2018 07:37:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726079AbeLDHh3 (ORCPT ); Tue, 4 Dec 2018 02:37:29 -0500 Received: from mga17.intel.com ([192.55.52.151]:16867 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726053AbeLDHh1 (ORCPT ); Tue, 4 Dec 2018 02:37:27 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="300822536" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by fmsmga005.fm.intel.com with ESMTP; 03 Dec 2018 23:37:26 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 10/13] keys/mktme: Add the MKTME Key Service type for memory encryption Date: Mon, 3 Dec 2018 23:39:57 -0800 Message-Id: <42d44fb5ddbbf7241a2494fc688e274ade641965.1543903910.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP MKTME (Multi-Key Total Memory Encryption) is a technology that allows transparent memory encryption in upcoming Intel platforms. MKTME will support mulitple encryption domains, each having their own key. The main use case for the feature is virtual machine isolation. The API needs the flexibility to work for a wide range of uses. The MKTME key service type manages the addition and removal of the memory encryption keys. It maps Userspace Keys to hardware KeyIDs. It programs the hardware with the user requested encryption options. The only supported encryption algorithm is AES-XTS 128. The MKTME key service is half of the MKTME API level solution. It pairs with a new memory encryption system call: encrypt_mprotect() that uses the keys to encrypt memory. See Documentation/x86/mktme/mktme.rst Change-Id: Idda4af2beabb739c77719897affff183ee9fa716 Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- arch/x86/Kconfig | 1 + include/keys/mktme-type.h | 41 ++++++ security/keys/Kconfig | 11 ++ security/keys/Makefile | 1 + security/keys/mktme_keys.c | 339 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 393 insertions(+) create mode 100644 include/keys/mktme-type.h create mode 100644 security/keys/mktme_keys.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7ac78e2856c7..c2e3bb5af077 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1531,6 +1531,7 @@ config X86_INTEL_MKTME bool "Intel Multi-Key Total Memory Encryption" select DYNAMIC_PHYSICAL_MASK select PAGE_EXTENSION + select MKTME_KEYS depends on X86_64 && CPU_SUP_INTEL ---help--- Say yes to enable support for Multi-Key Total Memory Encryption. diff --git a/include/keys/mktme-type.h b/include/keys/mktme-type.h new file mode 100644 index 000000000000..c63c6568087f --- /dev/null +++ b/include/keys/mktme-type.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Key service for Multi-KEY Total Memory Encryption */ + +#ifndef _KEYS_MKTME_TYPE_H +#define _KEYS_MKTME_TYPE_H + +#include + +/* + * The AES-XTS 128 encryption algorithm requires 128 bits for each + * user supplied data key and tweak key. + */ +#define MKTME_AES_XTS_SIZE 16 /* 16 bytes, 128 bits */ + +enum mktme_alg { + MKTME_ALG_AES_XTS_128, +}; + +const char *const mktme_alg_names[] = { + [MKTME_ALG_AES_XTS_128] = "aes-xts-128", +}; + +enum mktme_type { + MKTME_TYPE_ERROR = -1, + MKTME_TYPE_USER, + MKTME_TYPE_CPU, + MKTME_TYPE_CLEAR, + MKTME_TYPE_NO_ENCRYPT, +}; + +const char *const mktme_type_names[] = { + [MKTME_TYPE_USER] = "user", + [MKTME_TYPE_CPU] = "cpu", + [MKTME_TYPE_CLEAR] = "clear", + [MKTME_TYPE_NO_ENCRYPT] = "no-encrypt", +}; + +extern struct key_type key_type_mktme; + +#endif /* _KEYS_MKTME_TYPE_H */ diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 6462e6654ccf..c36972113e67 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -101,3 +101,14 @@ config KEY_DH_OPERATIONS in the kernel. If you are unsure as to whether this is required, answer N. + +config MKTME_KEYS + bool "Multi-Key Total Memory Encryption Keys" + depends on KEYS && X86_INTEL_MKTME + help + This option provides support for Multi-Key Total Memory + Encryption (MKTME) on Intel platforms offering the feature. + MKTME allows userspace to manage the hardware encryption + keys through the kernel key services. + + If you are unsure as to whether this is required, answer N. diff --git a/security/keys/Makefile b/security/keys/Makefile index 9cef54064f60..94c84f10a857 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += keyctl_pkey.o obj-$(CONFIG_BIG_KEYS) += big_key.o obj-$(CONFIG_TRUSTED_KEYS) += trusted.o obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ +obj-$(CONFIG_MKTME_KEYS) += mktme_keys.o diff --git a/security/keys/mktme_keys.c b/security/keys/mktme_keys.c new file mode 100644 index 000000000000..e615eb58e600 --- /dev/null +++ b/security/keys/mktme_keys.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-3.0 + +/* Documentation/x86/mktme/mktme_keys.rst */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +struct kmem_cache *mktme_prog_cache; /* Hardware programming cache */ + +static const char * const mktme_program_err[] = { + "KeyID was successfully programmed", /* 0 */ + "Invalid KeyID programming command", /* 1 */ + "Insufficient entropy", /* 2 */ + "KeyID not valid", /* 3 */ + "Invalid encryption algorithm chosen", /* 4 */ + "Failure to access key table", /* 5 */ +}; + +enum mktme_opt_id { + OPT_ERROR = -1, + OPT_TYPE, + OPT_KEY, + OPT_TWEAK, + OPT_ALGORITHM, +}; + +static const match_table_t mktme_token = { + {OPT_TYPE, "type=%s"}, + {OPT_KEY, "key=%s"}, + {OPT_TWEAK, "tweak=%s"}, + {OPT_ALGORITHM, "algorithm=%s"}, + {OPT_ERROR, NULL} +}; + +struct mktme_payload { + u32 keyid_ctrl; /* Command & Encryption Algorithm */ + u8 data_key[MKTME_AES_XTS_SIZE]; + u8 tweak_key[MKTME_AES_XTS_SIZE]; +}; + +/* Key Service Method called when Key is garbage collected. */ +static void mktme_destroy_key(struct key *key) +{ + key_put_encrypt_ref(mktme_map_keyid_from_key(key)); +} + +/* Copy the payload to the HW programming structure and program this KeyID */ +static int mktme_program_keyid(int keyid, struct mktme_payload *payload) +{ + struct mktme_key_program *kprog = NULL; + u8 kern_entropy[MKTME_AES_XTS_SIZE]; + int i, ret; + + kprog = kmem_cache_zalloc(mktme_prog_cache, GFP_KERNEL); + if (!kprog) + return -ENOMEM; + + /* Hardware programming requires cached aligned struct */ + kprog->keyid = keyid; + kprog->keyid_ctrl = payload->keyid_ctrl; + memcpy(kprog->key_field_1, payload->data_key, MKTME_AES_XTS_SIZE); + memcpy(kprog->key_field_2, payload->tweak_key, MKTME_AES_XTS_SIZE); + + /* Strengthen the entropy fields for CPU generated keys */ + if ((payload->keyid_ctrl & 0xff) == MKTME_KEYID_SET_KEY_RANDOM) { + get_random_bytes(&kern_entropy, sizeof(kern_entropy)); + for (i = 0; i < (MKTME_AES_XTS_SIZE); i++) { + kprog->key_field_1[i] ^= kern_entropy[i]; + kprog->key_field_2[i] ^= kern_entropy[i]; + } + } + ret = mktme_key_program(kprog); + kmem_cache_free(mktme_prog_cache, kprog); + return ret; +} + +/* Key Service Method to update an existing key. */ +static int mktme_update_key(struct key *key, + struct key_preparsed_payload *prep) +{ + struct mktme_payload *payload = prep->payload.data[0]; + int keyid, ref_count; + int ret; + + mktme_map_lock(); + keyid = mktme_map_keyid_from_key(key); + if (keyid <= 0) + return -EINVAL; + /* + * ref_count will be at least one when we get here because the + * key already exists. If ref_count is not > 1, it is safe to + * update the key while holding the mktme_map_lock. + */ + ref_count = mktme_read_encrypt_ref(keyid); + if (ref_count > 1) { + pr_debug("mktme not updating keyid[%d] encrypt_count[%d]\n", + keyid, ref_count); + return -EBUSY; + } + ret = mktme_program_keyid(keyid, payload); + if (ret != MKTME_PROG_SUCCESS) { + pr_debug("%s: %s\n", __func__, mktme_program_err[ret]); + ret = -ENOKEY; + } + mktme_map_unlock(); + return ret; +} + +/* Key Service Method to create a new key. Payload is preparsed. */ +int mktme_instantiate_key(struct key *key, struct key_preparsed_payload *prep) +{ + struct mktme_payload *payload = prep->payload.data[0]; + int keyid, ret; + + mktme_map_lock(); + keyid = mktme_map_get_free_keyid(); + if (keyid == 0) { + ret = -ENOKEY; + goto out; + } + ret = mktme_program_keyid(keyid, payload); + if (ret != MKTME_PROG_SUCCESS) { + pr_debug("%s: %s\n", __func__, mktme_program_err[ret]); + ret = -ENOKEY; + goto out; + } + mktme_map_set_keyid(keyid, key); + key_get_encrypt_ref(keyid); +out: + mktme_map_unlock(); + return ret; +} + +/* Verify the user provided the needed arguments for the TYPE of Key */ +static int mktme_check_options(struct mktme_payload *payload, + unsigned long token_mask, enum mktme_type type) +{ + if (!token_mask) + return -EINVAL; + + switch (type) { + case MKTME_TYPE_USER: + if (test_bit(OPT_ALGORITHM, &token_mask)) + payload->keyid_ctrl |= MKTME_AES_XTS_128; + else + return -EINVAL; + + if ((test_bit(OPT_KEY, &token_mask)) && + (test_bit(OPT_TWEAK, &token_mask))) + payload->keyid_ctrl |= MKTME_KEYID_SET_KEY_DIRECT; + else + return -EINVAL; + break; + + case MKTME_TYPE_CPU: + if (test_bit(OPT_ALGORITHM, &token_mask)) + payload->keyid_ctrl |= MKTME_AES_XTS_128; + else + return -EINVAL; + + payload->keyid_ctrl |= MKTME_KEYID_SET_KEY_RANDOM; + break; + + case MKTME_TYPE_CLEAR: + payload->keyid_ctrl |= MKTME_KEYID_CLEAR_KEY; + break; + + case MKTME_TYPE_NO_ENCRYPT: + payload->keyid_ctrl |= MKTME_KEYID_NO_ENCRYPT; + break; + + default: + return -EINVAL; + } + return 0; +} + +/* Parse the options and store the key programming data in the payload. */ +static int mktme_get_options(char *options, struct mktme_payload *payload) +{ + enum mktme_type type = MKTME_TYPE_ERROR; + substring_t args[MAX_OPT_ARGS]; + unsigned long token_mask = 0; + char *p = options; + int ret, token; + + while ((p = strsep(&options, " \t"))) { + if (*p == '\0' || *p == ' ' || *p == '\t') + continue; + token = match_token(p, mktme_token, args); + if (test_and_set_bit(token, &token_mask)) + return -EINVAL; + + switch (token) { + case OPT_KEY: + ret = hex2bin(payload->data_key, args[0].from, + MKTME_AES_XTS_SIZE); + if (ret < 0) + return -EINVAL; + break; + + case OPT_TWEAK: + ret = hex2bin(payload->tweak_key, args[0].from, + MKTME_AES_XTS_SIZE); + if (ret < 0) + return -EINVAL; + break; + + case OPT_TYPE: + type = match_string(mktme_type_names, + ARRAY_SIZE(mktme_type_names), + args[0].from); + if (type < 0) + return -EINVAL; + break; + + case OPT_ALGORITHM: + ret = match_string(mktme_alg_names, + ARRAY_SIZE(mktme_alg_names), + args[0].from); + if (ret < 0) + return -EINVAL; + break; + + default: + return -EINVAL; + } + } + return mktme_check_options(payload, token_mask, type); +} + +void mktme_free_preparsed_key(struct key_preparsed_payload *prep) +{ + kzfree(prep->payload.data[0]); +} + +/* + * Key Service Method to preparse a payload before a key is created. + * Check permissions and the options. Load the proposed key field + * data into the payload for use by instantiate and update methods. + */ +int mktme_preparse_key(struct key_preparsed_payload *prep) +{ + struct mktme_payload *mktme_payload; + size_t datalen = prep->datalen; + char *options; + int ret; + + if (!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (datalen <= 0 || datalen > 1024 || !prep->data) + return -EINVAL; + + options = kmemdup(prep->data, datalen + 1, GFP_KERNEL); + if (!options) + return -ENOMEM; + + options[datalen] = '\0'; + + mktme_payload = kzalloc(sizeof(*mktme_payload), GFP_KERNEL); + if (!mktme_payload) { + ret = -ENOMEM; + goto out; + } + ret = mktme_get_options(options, mktme_payload); + if (ret < 0) + goto out; + + prep->quotalen = sizeof(mktme_payload); + prep->payload.data[0] = mktme_payload; +out: + kzfree(options); + return ret; +} + +struct key_type key_type_mktme = { + .name = "mktme", + .preparse = mktme_preparse_key, + .free_preparse = mktme_free_preparsed_key, + .instantiate = mktme_instantiate_key, + .update = mktme_update_key, + .describe = user_describe, + .destroy = mktme_destroy_key, +}; + +/* + * Allocate the global mktme_map structure based on the available keyids. + * Create a cache for the hardware structure. Initialize the encrypt_count + * array to track * VMA's per keyid. Once all that succeeds, register the + * 'mktme' key type. + */ +static int __init init_mktme(void) +{ + int ret; + + /* Verify keys are present */ + if (!(mktme_nr_keyids > 0)) + return -EINVAL; + + if (!mktme_map_alloc()) + return -ENOMEM; + + mktme_prog_cache = KMEM_CACHE(mktme_key_program, SLAB_PANIC); + if (!mktme_prog_cache) + goto free_map; + + if (mktme_alloc_encrypt_array() < 0) + goto free_cache; + + ret = register_key_type(&key_type_mktme); + if (!ret) + return ret; /* SUCCESS */ + + mktme_free_encrypt_array(); +free_cache: + kmem_cache_destroy(mktme_prog_cache); +free_map: + mktme_map_free(); + + return -ENOMEM; +} + +late_initcall(init_mktme); From patchwork Tue Dec 4 07:39:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711217 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AEEF316B1 for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9B7D62A46B for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8FF292A57C; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 284E42A46B for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726085AbeLDHhb (ORCPT ); Tue, 4 Dec 2018 02:37:31 -0500 Received: from mga07.intel.com ([134.134.136.100]:2376 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726027AbeLDHhb (ORCPT ); Tue, 4 Dec 2018 02:37:31 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga105.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="115772840" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga001.jf.intel.com with ESMTP; 03 Dec 2018 23:37:26 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 11/13] keys/mktme: Program memory encryption keys on a system wide basis Date: Mon, 3 Dec 2018 23:39:58 -0800 Message-Id: <72dd5f38c1fdbc4c532f8caf2d2010f1ddfa8439.1543903910.git.alison.schofield@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP The kernel manages the MKTME (Multi-Key Total Memory Encryption) Keys as a system wide single pool of keys. The hardware, however, manages the keys on a per physical package basis. Each physical package maintains a Key Table that all CPU's in that package share. In order to maintain the consistent, system wide view that the kernel requires, program all physical packages during a key program request. Change-Id: I0ff46f37fde47a0305842baeb8ea600b6c568639 Signed-off-by: Alison Schofield --- security/keys/mktme_keys.c | 61 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/security/keys/mktme_keys.c b/security/keys/mktme_keys.c index e615eb58e600..7f113146acf2 100644 --- a/security/keys/mktme_keys.c +++ b/security/keys/mktme_keys.c @@ -21,6 +21,7 @@ #include "internal.h" struct kmem_cache *mktme_prog_cache; /* Hardware programming cache */ +cpumask_var_t mktme_leadcpus; /* one cpu per pkg to program keys */ static const char * const mktme_program_err[] = { "KeyID was successfully programmed", /* 0 */ @@ -59,6 +60,37 @@ static void mktme_destroy_key(struct key *key) key_put_encrypt_ref(mktme_map_keyid_from_key(key)); } +struct mktme_hw_program_info { + struct mktme_key_program *key_program; + unsigned long status; +}; + +/* Program a KeyID on a single package. */ +static void mktme_program_package(void *hw_program_info) +{ + struct mktme_hw_program_info *info = hw_program_info; + int ret; + + ret = mktme_key_program(info->key_program); + if (ret != MKTME_PROG_SUCCESS) + WRITE_ONCE(info->status, ret); +} + +/* Program a KeyID across the entire system. */ +static int mktme_program_system(struct mktme_key_program *key_program, + cpumask_var_t mktme_cpumask) +{ + struct mktme_hw_program_info info = { + .key_program = key_program, + .status = MKTME_PROG_SUCCESS, + }; + get_online_cpus(); + on_each_cpu_mask(mktme_cpumask, mktme_program_package, &info, 1); + put_online_cpus(); + + return info.status; +} + /* Copy the payload to the HW programming structure and program this KeyID */ static int mktme_program_keyid(int keyid, struct mktme_payload *payload) { @@ -84,7 +116,7 @@ static int mktme_program_keyid(int keyid, struct mktme_payload *payload) kprog->key_field_2[i] ^= kern_entropy[i]; } } - ret = mktme_key_program(kprog); + ret = mktme_program_system(kprog, mktme_leadcpus); kmem_cache_free(mktme_prog_cache, kprog); return ret; } @@ -299,6 +331,28 @@ struct key_type key_type_mktme = { .destroy = mktme_destroy_key, }; +static int mktme_build_leadcpus_mask(void) +{ + int online_cpu, mktme_cpu; + int online_pkgid, mktme_pkgid = -1; + + if (!zalloc_cpumask_var(&mktme_leadcpus, GFP_KERNEL)) + return -ENOMEM; + + for_each_online_cpu(online_cpu) { + online_pkgid = topology_physical_package_id(online_cpu); + + for_each_cpu(mktme_cpu, mktme_leadcpus) { + mktme_pkgid = topology_physical_package_id(mktme_cpu); + if (mktme_pkgid == online_pkgid) + break; + } + if (mktme_pkgid != online_pkgid) + cpumask_set_cpu(online_cpu, mktme_leadcpus); + } + return 0; +} + /* * Allocate the global mktme_map structure based on the available keyids. * Create a cache for the hardware structure. Initialize the encrypt_count @@ -323,10 +377,15 @@ static int __init init_mktme(void) if (mktme_alloc_encrypt_array() < 0) goto free_cache; + if (mktme_build_leadcpus_mask() < 0) + goto free_array; + ret = register_key_type(&key_type_mktme); if (!ret) return ret; /* SUCCESS */ + free_cpumask_var(mktme_leadcpus); +free_array: mktme_free_encrypt_array(); free_cache: kmem_cache_destroy(mktme_prog_cache); From patchwork Tue Dec 4 07:39:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711215 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 81DF417D5 for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 706E62A544 for ; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 64B4A2A582; Tue, 4 Dec 2018 07:37:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 924FC2A57C for ; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726082AbeLDHha (ORCPT ); Tue, 4 Dec 2018 02:37:30 -0500 Received: from mga17.intel.com ([192.55.52.151]:16867 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725996AbeLDHh2 (ORCPT ); Tue, 4 Dec 2018 02:37:28 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:27 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="115451411" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga002.jf.intel.com with ESMTP; 03 Dec 2018 23:37:26 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 12/13] keys/mktme: Save MKTME data if kernel cmdline parameter allows Date: Mon, 3 Dec 2018 23:39:59 -0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP MKTME (Multi-Key Total Memory Encryption) key payloads may include data encryption keys, tweak keys, and additional entropy bits. These are used to program the MKTME encryption hardware. By default, the kernel destroys this payload data once the hardware is programmed. However, in order to fully support CPU Hotplug, saving the key data becomes important. The MKTME Key Service cannot allow a new physical package to come online unless it can program the new packages Key Table to match the Key Tables of all existing physical packages. With CPU generated keys (a.k.a. random keys or ephemeral keys) the saving of user key data is not an issue. The kernel and MKTME hardware can generate strong encryption keys without recalling any user supplied data. With USER directed keys (a.k.a. user type) saving the key programming data (data and tweak key) becomes an issue. The data and tweak keys are required to program those keys on a new physical package. In preparation for adding CPU hotplug support: Add an 'mktme_vault' where key data is stored. Add 'mktme_savekeys' kernel command line parameter that directs what key data can be stored. If it is not set, kernel does not store users data key or tweak key. Add 'mktme_bitmap_user_type' to track when USER type keys are in use. If no USER type keys are currently in use, a physical package may be brought online, despite the absence of 'mktme_savekeys'. Change-Id: If57414862f1ac131dd97e29bf4f3937ac33777f6 Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- Documentation/admin-guide/kernel-parameters.rst | 1 + Documentation/admin-guide/kernel-parameters.txt | 11 +++++ arch/x86/mm/mktme.c | 2 + security/keys/mktme_keys.c | 65 +++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst index b8d0bc07ed0a..1b62b86d0666 100644 --- a/Documentation/admin-guide/kernel-parameters.rst +++ b/Documentation/admin-guide/kernel-parameters.rst @@ -120,6 +120,7 @@ parameter is applicable:: Documentation/m68k/kernel-options.txt. MDA MDA console support is enabled. MIPS MIPS architecture is enabled. + MKTME Multi-Key Total Memory Encryption is enabled. MOUSE Appropriate mouse support is enabled. MSI Message Signaled Interrupts (PCI). MTD MTD (Memory Technology Device) support is enabled. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 81d1d5a74728..c777dbf0f75c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2497,6 +2497,17 @@ in the "bleeding edge" mini2440 support kernel at http://repo.or.cz/w/linux-2.6/mini2440.git + mktme_savekeys [X86, MKTME] When CONFIG_X86_INTEL_MKTME is set + this parameter allows the kernel to save the user + specified MKTME key payload. Saving this payload + means that the MKTME Key Service can always allows + the addition of new physical packages. If the + mktme_savekeys parameter is not present, users key + data will not be saved, and new physical packages + may only be added to the system if no user type + MKTME keys are in use. + See Documentation/x86/mktme.rst + mminit_loglevel= [KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this parameter allows control of the logging verbosity for diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index 55d34beb9b81..f96f4f2884e8 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -99,10 +99,12 @@ void mktme_map_set_keyid(int keyid, void *key) mktme_map->mapped_keyids++; } +extern unsigned long *mktme_bitmap_user_type; void mktme_map_free_keyid(int keyid) { mktme_map->key[keyid] = 0; mktme_map->mapped_keyids--; + clear_bit(keyid, mktme_bitmap_user_type); } int mktme_map_keyid_from_key(void *key) diff --git a/security/keys/mktme_keys.c b/security/keys/mktme_keys.c index 7f113146acf2..e9c7d306cba1 100644 --- a/security/keys/mktme_keys.c +++ b/security/keys/mktme_keys.c @@ -23,6 +23,11 @@ struct kmem_cache *mktme_prog_cache; /* Hardware programming cache */ cpumask_var_t mktme_leadcpus; /* one cpu per pkg to program keys */ +/* Kernel command line parameter allows saving of users key payload. */ +static bool mktme_savekeys; +/* Track the existence of user type keys to make package hotplug decisions. */ +unsigned long *mktme_bitmap_user_type; + static const char * const mktme_program_err[] = { "KeyID was successfully programmed", /* 0 */ "Invalid KeyID programming command", /* 1 */ @@ -54,6 +59,9 @@ struct mktme_payload { u8 tweak_key[MKTME_AES_XTS_SIZE]; }; +/* Store keys in this vault if cmdline parameter mktme_savekeys allows */ +struct mktme_payload *mktme_vault; + /* Key Service Method called when Key is garbage collected. */ static void mktme_destroy_key(struct key *key) { @@ -121,6 +129,23 @@ static int mktme_program_keyid(int keyid, struct mktme_payload *payload) return ret; } +static void mktme_load_vault(int keyid, struct mktme_payload *payload) +{ + /* + * Always save the control fields to program hotplugged + * packages with RANDOM, CLEAR, or NO_ENCRYPT type keys. + */ + mktme_vault[keyid].keyid_ctrl = payload->keyid_ctrl; + + /* Only save data and tweak keys if allowed */ + if (mktme_savekeys) { + memcpy(mktme_vault[keyid].data_key, payload->data_key, + MKTME_AES_XTS_SIZE); + memcpy(mktme_vault[keyid].tweak_key, payload->tweak_key, + MKTME_AES_XTS_SIZE); + } +} + /* Key Service Method to update an existing key. */ static int mktme_update_key(struct key *key, struct key_preparsed_payload *prep) @@ -144,11 +169,23 @@ static int mktme_update_key(struct key *key, keyid, ref_count); return -EBUSY; } + + /* Forget if key was user type. */ + clear_bit(keyid, mktme_bitmap_user_type); + ret = mktme_program_keyid(keyid, payload); if (ret != MKTME_PROG_SUCCESS) { pr_debug("%s: %s\n", __func__, mktme_program_err[ret]); ret = -ENOKEY; + goto out; } + + mktme_load_vault(keyid, payload); + + /* Remember if this key is user type. */ + if ((payload->keyid_ctrl & 0xff) == MKTME_KEYID_SET_KEY_DIRECT) + set_bit(keyid, mktme_bitmap_user_type); +out: mktme_map_unlock(); return ret; } @@ -171,6 +208,13 @@ int mktme_instantiate_key(struct key *key, struct key_preparsed_payload *prep) ret = -ENOKEY; goto out; } + + mktme_load_vault(keyid, payload); + + /* Remember if key is user type. */ + if ((payload->keyid_ctrl & 0xff) == MKTME_KEYID_SET_KEY_DIRECT) + set_bit(keyid, mktme_bitmap_user_type); + mktme_map_set_keyid(keyid, key); key_get_encrypt_ref(keyid); out: @@ -380,10 +424,23 @@ static int __init init_mktme(void) if (mktme_build_leadcpus_mask() < 0) goto free_array; + mktme_bitmap_user_type = bitmap_zalloc(mktme_nr_keyids, GFP_KERNEL); + if (!mktme_bitmap_user_type) + goto free_mask; + + mktme_vault = kzalloc(sizeof(mktme_vault[0]) * (mktme_nr_keyids + 1), + GFP_KERNEL); + if (!mktme_vault) + goto free_bitmap; + ret = register_key_type(&key_type_mktme); if (!ret) return ret; /* SUCCESS */ + kfree(mktme_vault); +free_bitmap: + bitmap_free(mktme_bitmap_user_type); +free_mask: free_cpumask_var(mktme_leadcpus); free_array: mktme_free_encrypt_array(); @@ -396,3 +453,11 @@ static int __init init_mktme(void) } late_initcall(init_mktme); + +static int mktme_enable_savekeys(char *__unused) +{ + mktme_savekeys = true; + return 1; +} +__setup("mktme_savekeys", mktme_enable_savekeys); + From patchwork Tue Dec 4 07:40:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10711211 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B293A17D5 for ; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9E7522A53E for ; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 929772A582; Tue, 4 Dec 2018 07:37:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E084B2A544 for ; Tue, 4 Dec 2018 07:37:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726053AbeLDHha (ORCPT ); Tue, 4 Dec 2018 02:37:30 -0500 Received: from mga03.intel.com ([134.134.136.65]:5832 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726027AbeLDHh1 (ORCPT ); Tue, 4 Dec 2018 02:37:27 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 03 Dec 2018 23:37:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,313,1539673200"; d="scan'208";a="107105277" Received: from alison-desk.jf.intel.com (HELO alison-desk) ([10.54.74.53]) by orsmga003.jf.intel.com with ESMTP; 03 Dec 2018 23:37:26 -0800 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: jmorris@namei.org, mingo@redhat.com, hpa@zytor.com, bp@alien8.de, luto@kernel.org, peterz@infradead.org, kirill.shutemov@linux.intel.com, dave.hansen@intel.com, kai.huang@intel.com, jun.nakajima@intel.com, dan.j.williams@intel.com, jarkko.sakkinen@intel.com, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, linux-mm@kvack.org, x86@kernel.org Subject: [RFC v2 13/13] keys/mktme: Support CPU Hotplug for MKTME keys Date: Mon, 3 Dec 2018 23:40:00 -0800 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP The MKTME (Multi-Key Memory Encryption Keys) hardware resides on each physical package. The kernel maintains one Key Table on each physical package and these Key Tables must all remain in sync. (From here on, package means physical package.) Although every CPU on that package has the ability to program the Key Table, the kernel uses one 'lead' cpu per package to program the Key Tables. Typically, keys are programmed one at a time, across all packages, as the 'add key' requests come in from userspace. Some CPU hotplug scenarios are handled quite simply: > Teardown a non lead CPU --> do nothing > Teardown a lead CPU --> pick a new lead CPU > Teardown a lead/last CPU of a package --> forget this package > Startup a CPU in a known package --> do nothing > Startup a CPU in a new package and no keys are programmed --> do nothing Then there is the more interesting case for MKTME: a CPU is starting up for a new package and keys are programmed on the existing packages. The Key Table on the new package will need to be programmed to match the Key Tables on all existing packages. The issue is whether or not the Key Service has the information it needs to program the new Key Table. To address this, a new kernel commandline parameter 'mktme_savekeys' was introduced in a previous patch. It allows the kernel to save the data needed to program keys, beyond their first add key request. When 'mktme_savekeys' is not present, new packages may still be added if all currently programmed keys are not USER type. This means that CPU generated keys are an option for users not wanting to save key data, but who also want to support the addition of new packages. Change-Id: I219192fc59dd9f433963c4959f33d7f013c9f73a Signed-off-by: Alison Schofield Signed-off-by: Kirill A. Shutemov --- security/keys/mktme_keys.c | 135 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 9 deletions(-) diff --git a/security/keys/mktme_keys.c b/security/keys/mktme_keys.c index e9c7d306cba1..fb4d4061d2f3 100644 --- a/security/keys/mktme_keys.c +++ b/security/keys/mktme_keys.c @@ -86,21 +86,29 @@ static void mktme_program_package(void *hw_program_info) /* Program a KeyID across the entire system. */ static int mktme_program_system(struct mktme_key_program *key_program, - cpumask_var_t mktme_cpumask) + cpumask_var_t mktme_cpumask, int hotplug) { struct mktme_hw_program_info info = { .key_program = key_program, .status = MKTME_PROG_SUCCESS, }; - get_online_cpus(); - on_each_cpu_mask(mktme_cpumask, mktme_program_package, &info, 1); - put_online_cpus(); + + if (!hotplug) { + get_online_cpus(); + on_each_cpu_mask(mktme_cpumask, mktme_program_package, + &info, 1); + put_online_cpus(); + } else { + on_each_cpu_mask(mktme_cpumask, mktme_program_package, + &info, 1); + } return info.status; } /* Copy the payload to the HW programming structure and program this KeyID */ -static int mktme_program_keyid(int keyid, struct mktme_payload *payload) +static int mktme_program_keyid(int keyid, struct mktme_payload *payload, + cpumask_var_t mask, int hotplug) { struct mktme_key_program *kprog = NULL; u8 kern_entropy[MKTME_AES_XTS_SIZE]; @@ -124,7 +132,7 @@ static int mktme_program_keyid(int keyid, struct mktme_payload *payload) kprog->key_field_2[i] ^= kern_entropy[i]; } } - ret = mktme_program_system(kprog, mktme_leadcpus); + ret = mktme_program_system(kprog, mktme_leadcpus, hotplug); kmem_cache_free(mktme_prog_cache, kprog); return ret; } @@ -173,7 +181,7 @@ static int mktme_update_key(struct key *key, /* Forget if key was user type. */ clear_bit(keyid, mktme_bitmap_user_type); - ret = mktme_program_keyid(keyid, payload); + ret = mktme_program_keyid(keyid, payload, mktme_leadcpus, 0); if (ret != MKTME_PROG_SUCCESS) { pr_debug("%s: %s\n", __func__, mktme_program_err[ret]); ret = -ENOKEY; @@ -202,7 +210,7 @@ int mktme_instantiate_key(struct key *key, struct key_preparsed_payload *prep) ret = -ENOKEY; goto out; } - ret = mktme_program_keyid(keyid, payload); + ret = mktme_program_keyid(keyid, payload, mktme_leadcpus, 0); if (ret != MKTME_PROG_SUCCESS) { pr_debug("%s: %s\n", __func__, mktme_program_err[ret]); ret = -ENOKEY; @@ -375,6 +383,10 @@ struct key_type key_type_mktme = { .destroy = mktme_destroy_key, }; +/* + * Build mktme_leadcpus mask to include one cpu per physical package. + * The mask is used to program the Key Table on each physical package. + */ static int mktme_build_leadcpus_mask(void) { int online_cpu, mktme_cpu; @@ -397,6 +409,102 @@ static int mktme_build_leadcpus_mask(void) return 0; } +/* A new packages Key Table is programmed with data saved in mktme_vault. */ +static int mktme_program_new_package(cpumask_var_t mask) +{ + struct key *key; + int hotplug = 1; + int keyid, ret; + + /* When a KeyID slot is freed, it's corresponding Key is 0 */ + for (keyid = 1; keyid <= mktme_nr_keyids; keyid++) { + key = mktme_map_key_from_keyid(keyid); + if (!key) + continue; + /* If one key fails to program, fail the entire package. */ + ret = mktme_program_keyid(keyid, &mktme_vault[keyid], + mask, hotplug); + if (ret != MKTME_PROG_SUCCESS) { + pr_debug("%s: %s\n", __func__, mktme_program_err[ret]); + ret = -ENOKEY; + break; + } + } + return ret; +} + +static int mktme_hotplug_cpu_startup(unsigned int cpu) +{ + int lead_cpu, ret = 0; + cpumask_var_t newmask; + int pkgid = topology_physical_package_id(cpu); + + mktme_map_lock(); + + /* Nothing to do if a lead CPU exists for this package. */ + for_each_cpu(lead_cpu, mktme_leadcpus) + if (topology_physical_package_id(lead_cpu) == pkgid) + goto out_unlock; + + /* No keys to program. Just add the new lead CPU to mask. */ + if (!mktme_map_mapped_keyids()) + goto out_add_cpu; + + /* Keys need to be programmed. Confirm programming can be done. */ + if (!mktme_savekeys && + (bitmap_weight(mktme_bitmap_user_type, mktme_nr_keyids))) { + ret = -EPERM; + goto out_unlock; + } + + /* Program only this packages Key Table, not all Key Tables. */ + if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) { + ret = -ENOMEM; + goto out_unlock; + } + cpumask_set_cpu(cpu, newmask); + ret = mktme_program_new_package(newmask); + if (ret < 0) { + free_cpumask_var(newmask); + goto out_unlock; + } + + free_cpumask_var(newmask); +out_add_cpu: + /* Make this cpu a lead cpu for all future Key programming requests. */ + cpumask_set_cpu(cpu, mktme_leadcpus); +out_unlock: + mktme_map_unlock(); + return ret; +} + +static int mktme_hotplug_cpu_teardown(unsigned int cpu) +{ + int pkgid, online_cpu; + + mktme_map_lock(); + /* Teardown cpu is not a lead cpu, nothing to do. */ + if (!cpumask_test_and_clear_cpu(cpu, mktme_leadcpus)) + goto out; + /* + * Teardown cpu is a lead cpu. If the physical package + * is still present, pick a new lead cpu. Beware: the + * teardown cpu is still in the online_cpu mask. Do + * not pick it again. + */ + pkgid = topology_physical_package_id(cpu); + for_each_online_cpu(online_cpu) + if (online_cpu != cpu && + pkgid == topology_physical_package_id(online_cpu)) { + cpumask_set_cpu(online_cpu, mktme_leadcpus); + break; + } +out: + mktme_map_unlock(); + /* Teardowns always succeed. */ + return 0; +} + /* * Allocate the global mktme_map structure based on the available keyids. * Create a cache for the hardware structure. Initialize the encrypt_count @@ -405,7 +513,7 @@ static int mktme_build_leadcpus_mask(void) */ static int __init init_mktme(void) { - int ret; + int ret, cpuhp; /* Verify keys are present */ if (!(mktme_nr_keyids > 0)) @@ -433,10 +541,19 @@ static int __init init_mktme(void) if (!mktme_vault) goto free_bitmap; + cpuhp = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "keys/mktme_keys:online", + mktme_hotplug_cpu_startup, + mktme_hotplug_cpu_teardown); + if (cpuhp < 0) + goto free_vault; + ret = register_key_type(&key_type_mktme); if (!ret) return ret; /* SUCCESS */ + cpuhp_remove_state_nocalls(cpuhp); +free_vault: kfree(mktme_vault); free_bitmap: bitmap_free(mktme_bitmap_user_type);