From patchwork Fri Sep 7 22:34:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592645 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 4CECF14E2 for ; Fri, 7 Sep 2018 22:33:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3CAE52B030 for ; Fri, 7 Sep 2018 22:33:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 30E782B12D; Fri, 7 Sep 2018 22:33:49 +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 CF1102B030 for ; Fri, 7 Sep 2018 22:33:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726434AbeIHDQz (ORCPT ); Fri, 7 Sep 2018 23:16:55 -0400 Received: from mga06.intel.com ([134.134.136.31]:35244 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726431AbeIHDQz (ORCPT ); Fri, 7 Sep 2018 23:16:55 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:33:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="261683969" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by fmsmga006.fm.intel.com with ESMTP; 07 Sep 2018 15:33:44 -0700 Date: Fri, 7 Sep 2018 15:34:26 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 02/12] mm: Generalize the mprotect implementation to support extensions Message-ID: <2dcbb08ed8804e02538a73ee05a4283c54180e36.1536356108.git.alison.schofield@intel.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) 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. Signed-off-by: Alison Schofield --- mm/mprotect.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mm/mprotect.c b/mm/mprotect.c index 68dc476310c0..56e64ef7931e 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -35,6 +35,8 @@ #include "internal.h" +#define NO_PKEY -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) @@ -402,9 +404,9 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, } /* - * pkey==-1 when doing a legacy mprotect() + * When pkey==NO_PKEY 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; @@ -528,7 +530,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_PKEY); } #ifdef CONFIG_ARCH_HAS_PKEYS @@ -536,7 +538,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 Fri Sep 7 22:34: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: 10592649 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 05DCA14E2 for ; Fri, 7 Sep 2018 22:34:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E8C962B030 for ; Fri, 7 Sep 2018 22:34:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DC9002B12D; Fri, 7 Sep 2018 22:34:20 +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 7BA742B030 for ; Fri, 7 Sep 2018 22:34:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726498AbeIHDR1 (ORCPT ); Fri, 7 Sep 2018 23:17:27 -0400 Received: from mga11.intel.com ([192.55.52.93]:6493 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726431AbeIHDR0 (ORCPT ); Fri, 7 Sep 2018 23:17:26 -0400 X-Amp-Result: UNKNOWN X-Amp-Original-Verdict: FILE UNKNOWN X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:34:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="260815502" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by fmsmga005.fm.intel.com with ESMTP; 07 Sep 2018 15:34:12 -0700 Date: Fri, 7 Sep 2018 15:34:54 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 03/12] syscall/x86: Wire up a new system call for memory encryption keys Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) 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 --- 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 3ed377d0c46c..7dc0ed3a182e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -904,6 +904,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, int serial); /* * Architecture-specific system calls diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 42990676a55e..d2cb0af68160 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -734,9 +734,11 @@ __SYSCALL(__NR_pkey_free, sys_pkey_free) __SYSCALL(__NR_statx, sys_statx) #define __NR_io_pgetevents 292 __SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents) +#define __NR_encrypt_mprotect 293 +__SYSCALL(__NR_encrypt_mprotect, sys_encrypt_mprotect) #undef __NR_syscalls -#define __NR_syscalls 293 +#define __NR_syscalls 294 /* * 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 Fri Sep 7 22:36:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592653 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 0445B1515 for ; Fri, 7 Sep 2018 22:35:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E774C2B030 for ; Fri, 7 Sep 2018 22:35:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DAFF82B2ED; Fri, 7 Sep 2018 22:35: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 43E322B030 for ; Fri, 7 Sep 2018 22:35:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726561AbeIHDSi (ORCPT ); Fri, 7 Sep 2018 23:18:38 -0400 Received: from mga18.intel.com ([134.134.136.126]:12494 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726284AbeIHDSi (ORCPT ); Fri, 7 Sep 2018 23:18:38 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:35:30 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="71260822" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by orsmga007.jf.intel.com with ESMTP; 07 Sep 2018 15:35:29 -0700 Date: Fri, 7 Sep 2018 15:36:12 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 04/12] x86/mm: Add helper functions to manage memory encryption keys Message-ID: <28a55df5da1ecfea28bac588d3ac429cf1419b42.1536356108.git.alison.schofield@intel.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Define a global mapping structure to track the mapping of userspace keys to hardware keyids in MKTME (Multi-Key Total Memory Encryption). This data will be used for the memory encryption system call and the kernel key service API. Implement helper functions to access this mapping structure and make them visible to the MKTME Kernel Key Service: security/keys/mktme_keys Signed-off-by: Alison Schofield --- arch/x86/include/asm/mktme.h | 11 ++++++ arch/x86/mm/mktme.c | 85 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/arch/x86/include/asm/mktme.h b/arch/x86/include/asm/mktme.h index dbfbd955da98..f6acd551457f 100644 --- a/arch/x86/include/asm/mktme.h +++ b/arch/x86/include/asm/mktme.h @@ -13,6 +13,17 @@ 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_get_free_keyid(void); +extern void mktme_map_clear_keyid(int keyid); +extern void mktme_map_set_keyid(int keyid, unsigned int serial); +extern int mktme_map_keyid_from_serial(unsigned int serial); +extern unsigned int mktme_map_serial_from_keyid(int keyid); + extern struct page_ext_operations page_mktme_ops; #define page_keyid page_keyid diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index 660caf6a5ce1..5246d8323359 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -63,6 +63,91 @@ int vma_keyid(struct vm_area_struct *vma) return (prot & mktme_keyid_mask) >> mktme_keyid_shift; } +/* + * struct mktme_mapping and the mktme_map_* functions manage the mapping + * of userspace keys to hardware keyids in MKTME. They are used by the + * the encrypt_mprotect system call and the MKTME Key Service API. + */ +struct mktme_mapping { + struct mutex lock; /* protect this map & HW state */ + unsigned int mapped_keyids; + unsigned int serial[]; +}; + +struct mktme_mapping *mktme_map; + +static inline long mktme_map_size(void) +{ + long size = 0; + + size += sizeof(mktme_map); + size += sizeof(mktme_map->serial[0]) * mktme_nr_keyids; + return size; +} + +int mktme_map_alloc(void) +{ + mktme_map = kzalloc(mktme_map_size(), GFP_KERNEL); + if (!mktme_map) + return 0; + mutex_init(&mktme_map->lock); + return 1; +} + +void mktme_map_free(void) +{ + kfree(mktme_map); +} + +void mktme_map_lock(void) +{ + mutex_lock(&mktme_map->lock); +} + +void mktme_map_unlock(void) +{ + mutex_unlock(&mktme_map->lock); +} + +void mktme_map_set_keyid(int keyid, unsigned int serial) +{ + mktme_map->serial[keyid] = serial; + mktme_map->mapped_keyids++; +} + +void mktme_map_clear_keyid(int keyid) +{ + mktme_map->serial[keyid] = 0; + mktme_map->mapped_keyids--; +} + +unsigned int mktme_map_serial_from_keyid(int keyid) +{ + return mktme_map->serial[keyid]; +} + +int mktme_map_keyid_from_serial(unsigned int serial) +{ + int i; + + for (i = 1; i < mktme_nr_keyids; i++) + if (mktme_map->serial[i] == serial) + return i; + return 0; +} + +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->serial[i] == 0) + return i; + } + return 0; +} + void prep_encrypted_page(struct page *page, int order, int keyid, bool zero) { int i; From patchwork Fri Sep 7 22:36:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592657 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 0B78F14E2 for ; Fri, 7 Sep 2018 22:35:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EF6242B030 for ; Fri, 7 Sep 2018 22:35:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E0BC02B2ED; Fri, 7 Sep 2018 22:35:46 +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 7EEB42B030 for ; Fri, 7 Sep 2018 22:35:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726495AbeIHDSx (ORCPT ); Fri, 7 Sep 2018 23:18:53 -0400 Received: from mga12.intel.com ([192.55.52.136]:59480 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726284AbeIHDSx (ORCPT ); Fri, 7 Sep 2018 23:18:53 -0400 X-Amp-Result: UNKNOWN X-Amp-Original-Verdict: FILE UNKNOWN X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:35:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="84055650" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by fmsmga002.fm.intel.com with ESMTP; 07 Sep 2018 15:35:45 -0700 Date: Fri, 7 Sep 2018 15:36:27 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 05/12] x86/mm: Add a helper function to set keyid bits in encrypted VMA's Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Store the memory encryption keyid in the upper bits of vm_page_prot that match position of keyid, bits 51:46, in a PTE. Signed-off-by: Alison Schofield --- arch/x86/include/asm/mktme.h | 3 +++ arch/x86/mm/mktme.c | 15 +++++++++++++++ include/linux/mm.h | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/arch/x86/include/asm/mktme.h b/arch/x86/include/asm/mktme.h index f6acd551457f..b707f800b68f 100644 --- a/arch/x86/include/asm/mktme.h +++ b/arch/x86/include/asm/mktme.h @@ -13,6 +13,9 @@ extern phys_addr_t mktme_keyid_mask; extern int mktme_nr_keyids; extern int mktme_keyid_shift; +/* Set the encryption keyid bits in a VMA */ +extern void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid); + /* Manage mappings between hardware keyids and userspace keys */ extern int mktme_map_alloc(void); extern void mktme_map_free(void); diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index 5246d8323359..5ee7f37e9cd0 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -63,6 +63,21 @@ int vma_keyid(struct vm_area_struct *vma) return (prot & mktme_keyid_mask) >> mktme_keyid_shift; } +/* Set the encryption keyid bits in a VMA */ +void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid) +{ + int oldkeyid = vma_keyid(vma); + pgprotval_t newprot; + + if (newkeyid == oldkeyid) + 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); +} + /* * struct mktme_mapping and the mktme_map_* functions manage the mapping * of userspace keys to hardware keyids in MKTME. They are used by the diff --git a/include/linux/mm.h b/include/linux/mm.h index a4ce26aa0b65..ac85c0805761 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2799,5 +2799,9 @@ 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) {} +#endif /* CONFIG_X86_INTEL_MKTME */ #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ From patchwork Fri Sep 7 22:37:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592667 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 2DF5714E2 for ; Fri, 7 Sep 2018 22:36:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1E0A52B030 for ; Fri, 7 Sep 2018 22:36:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 126832B2ED; Fri, 7 Sep 2018 22:36:52 +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 A0AB32B030 for ; Fri, 7 Sep 2018 22:36:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726452AbeIHDT6 (ORCPT ); Fri, 7 Sep 2018 23:19:58 -0400 Received: from mga09.intel.com ([134.134.136.24]:25505 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726378AbeIHDT6 (ORCPT ); Fri, 7 Sep 2018 23:19:58 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:36:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="71508767" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by orsmga008.jf.intel.com with ESMTP; 07 Sep 2018 15:36:27 -0700 Date: Fri, 7 Sep 2018 15:37:10 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 07/12] x86/mm: Add helper functions to track encrypted VMA's Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) 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, VMA's using each keyid need to be tracked. This tracking allows the Kernel 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 atomic encrypt_count array to track the number of VMA's oustanding for each encryption keyid. Implement helper functions to manipulate this encrypt_count array. Signed-off-by: Alison Schofield --- arch/x86/include/asm/mktme.h | 7 +++++++ arch/x86/mm/mktme.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/mm.h | 2 ++ 3 files changed, 48 insertions(+) diff --git a/arch/x86/include/asm/mktme.h b/arch/x86/include/asm/mktme.h index b707f800b68f..5f3fa0c39c1c 100644 --- a/arch/x86/include/asm/mktme.h +++ b/arch/x86/include/asm/mktme.h @@ -16,6 +16,13 @@ extern int mktme_keyid_shift; /* Set the encryption keyid bits in a VMA */ extern void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid); +/* Manage the references to outstanding VMA's per encryption key */ +extern int vma_alloc_encrypt_array(void); +extern void vma_free_encrypt_array(void); +extern int vma_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); + /* Manage mappings between hardware keyids and userspace keys */ extern int mktme_map_alloc(void); extern void mktme_map_free(void); diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index 5ee7f37e9cd0..5690ef51a79a 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -163,6 +163,45 @@ int mktme_map_get_free_keyid(void) return 0; } +/* + * Helper functions manage the encrypt_count[] array that tracks the + * VMA's outstanding for each encryption 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. + */ +atomic_t *encrypt_count; + +int vma_alloc_encrypt_array(void) +{ + encrypt_count = kcalloc(mktme_nr_keyids, sizeof(atomic_t), GFP_KERNEL); + if (!encrypt_count) + return -ENOMEM; + return 0; +} + +void vma_free_encrypt_array(void) +{ + kfree(encrypt_count); +} + +int vma_read_encrypt_ref(int keyid) +{ + return atomic_read(&encrypt_count[keyid]); +} + +void vma_get_encrypt_ref(struct vm_area_struct *vma) +{ + if (vma_keyid(vma)) + atomic_inc(&encrypt_count[vma_keyid(vma)]); +} + +void vma_put_encrypt_ref(struct vm_area_struct *vma) +{ + if (vma_keyid(vma)) + atomic_dec(&encrypt_count[vma_keyid(vma)]); +} + void prep_encrypted_page(struct page *page, int order, int keyid, bool zero) { int i; diff --git a/include/linux/mm.h b/include/linux/mm.h index 0f9422c7841e..b217c699dbab 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2803,6 +2803,8 @@ static inline void setup_nr_node_ids(void) {} #ifndef CONFIG_X86_INTEL_MKTME static inline void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid) {} +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 Fri Sep 7 22:37:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592663 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 DA2181515 for ; Fri, 7 Sep 2018 22:36:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C6FFB2B030 for ; Fri, 7 Sep 2018 22:36:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B8AFB2B2ED; Fri, 7 Sep 2018 22:36:45 +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 39AF32B030 for ; Fri, 7 Sep 2018 22:36:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726444AbeIHDTw (ORCPT ); Fri, 7 Sep 2018 23:19:52 -0400 Received: from mga12.intel.com ([192.55.52.136]:59582 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726378AbeIHDTw (ORCPT ); Fri, 7 Sep 2018 23:19:52 -0400 X-Amp-Result: UNKNOWN X-Amp-Original-Verdict: FILE UNKNOWN X-Amp-File-Uploaded: False Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:36:43 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="84055823" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by fmsmga002.fm.intel.com with ESMTP; 07 Sep 2018 15:36:43 -0700 Date: Fri, 7 Sep 2018 15:37:25 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 08/12] mm: Track VMA's in use for each memory encryption keyid Message-ID: <3c891d076a376c8cff04403e90d04cf98b203960.1536356108.git.alison.schofield@intel.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Keep track of the VMA's oustanding for each memory encryption keyid. The count is used by the MKTME (Multi-Key Total Memory Encryption) Key Service to determine when it is safe to reprogram a hardware encryption key. Approach here is to do gets and puts on the encryption reference wherever kmem_cache_alloc/free's of vma_area_cachep's are executed. A couple of these locations will not be hit until cgroup support is added. One of these locations should never hit, so use a VM_WARN_ON. Signed-off-by: Alison Schofield --- arch/x86/mm/mktme.c | 2 ++ kernel/fork.c | 2 ++ mm/mmap.c | 12 ++++++++++++ mm/nommu.c | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/arch/x86/mm/mktme.c b/arch/x86/mm/mktme.c index 5690ef51a79a..8a7c326d4546 100644 --- a/arch/x86/mm/mktme.c +++ b/arch/x86/mm/mktme.c @@ -72,10 +72,12 @@ void mprotect_set_encrypt(struct vm_area_struct *vma, int newkeyid) if (newkeyid == oldkeyid) 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); } /* diff --git a/kernel/fork.c b/kernel/fork.c index e5e7a220a124..2d0e507bde7c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -459,6 +459,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, if (!tmp) goto fail_nomem; *tmp = *mpnt; + vma_get_encrypt_ref(tmp); /* Track encrypted vma's */ INIT_LIST_HEAD(&tmp->anon_vma_chain); retval = vma_dup_policy(mpnt, tmp); if (retval) @@ -539,6 +540,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, fail_nomem_anon_vma_fork: mpol_put(vma_policy(tmp)); fail_nomem_policy: + vma_put_encrypt_ref(tmp); /* Track encrypted vma's */ kmem_cache_free(vm_area_cachep, tmp); fail_nomem: retval = -ENOMEM; diff --git a/mm/mmap.c b/mm/mmap.c index 4c604eb644b4..7390b8b69fd6 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -182,6 +182,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) if (vma->vm_file) fput(vma->vm_file); mpol_put(vma_policy(vma)); + vma_put_encrypt_ref(vma); kmem_cache_free(vm_area_cachep, vma); return next; } @@ -913,6 +914,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, anon_vma_merge(vma, next); mm->map_count--; mpol_put(vma_policy(next)); + vma_put_encrypt_ref(next); kmem_cache_free(vm_area_cachep, next); /* * In mprotect's case 6 (see comments on vma_merge), @@ -1744,6 +1746,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, goto unacct_error; } + vma_get_encrypt_ref(vma); vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; @@ -1839,6 +1842,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, unmap_and_free_vma: vma->vm_file = NULL; fput(file); + vma_put_encrypt_ref(vma); /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); @@ -2653,6 +2657,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT); } + vma_get_encrypt_ref(new); err = vma_dup_policy(vma, new); if (err) goto out_free_vma; @@ -2686,6 +2691,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, out_free_mpol: mpol_put(vma_policy(new)); out_free_vma: + vma_put_encrypt_ref(new); kmem_cache_free(vm_area_cachep, new); return err; } @@ -3007,6 +3013,7 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla return -ENOMEM; } + vma_get_encrypt_ref(vma); INIT_LIST_HEAD(&vma->anon_vma_chain); vma->vm_mm = mm; vma->vm_ops = &anon_vm_ops; @@ -3229,6 +3236,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, new_vma->vm_pgoff = pgoff; if (vma_dup_policy(vma, new_vma)) goto out_free_vma; + vma_get_encrypt_ref(new_vma); INIT_LIST_HEAD(&new_vma->anon_vma_chain); if (anon_vma_clone(new_vma, vma)) goto out_free_mempol; @@ -3243,6 +3251,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, out_free_mempol: mpol_put(vma_policy(new_vma)); + vma_put_encrypt_ref(new_vma); out_free_vma: kmem_cache_free(vm_area_cachep, new_vma); out: @@ -3372,6 +3381,9 @@ static struct vm_area_struct *__install_special_mapping( if (unlikely(vma == NULL)) return ERR_PTR(-ENOMEM); + /* Do not expect a memory encrypted vma here */ + VM_WARN_ON(vma_keyid(vma)); + INIT_LIST_HEAD(&vma->anon_vma_chain); vma->vm_mm = mm; vma->vm_start = addr; diff --git a/mm/nommu.c b/mm/nommu.c index 73f66e81cfb0..85f04c174638 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -769,6 +769,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) if (vma->vm_file) fput(vma->vm_file); put_nommu_region(vma->vm_region); + vma_put_encrypt_ref(vma); kmem_cache_free(vm_area_cachep, vma); } @@ -1215,6 +1216,7 @@ unsigned long do_mmap(struct file *file, if (!vma) goto error_getting_vma; + vma_get_encrypt_ref(vma); region->vm_usage = 1; region->vm_flags = vm_flags; region->vm_pgoff = pgoff; @@ -1375,6 +1377,7 @@ unsigned long do_mmap(struct file *file, kmem_cache_free(vm_region_jar, region); if (vma->vm_file) fput(vma->vm_file); + vma_put_encrypt_ref(vma); kmem_cache_free(vm_area_cachep, vma); return ret; @@ -1486,6 +1489,7 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, *new = *vma; *region = *vma->vm_region; new->vm_region = region; + vma_get_encrypt_ref(new); npages = (addr - vma->vm_start) >> PAGE_SHIFT; From patchwork Fri Sep 7 22:37: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: 10592671 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 DEBB214E2 for ; Fri, 7 Sep 2018 22:37:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CE112292AC for ; Fri, 7 Sep 2018 22:37:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C1DD12B2D7; Fri, 7 Sep 2018 22:37:10 +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 42A12292AC for ; Fri, 7 Sep 2018 22:37:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726495AbeIHDUR (ORCPT ); Fri, 7 Sep 2018 23:20:17 -0400 Received: from mga06.intel.com ([134.134.136.31]:35542 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726010AbeIHDUR (ORCPT ); Fri, 7 Sep 2018 23:20:17 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga104.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:37:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="89921676" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by orsmga002.jf.intel.com with ESMTP; 07 Sep 2018 15:37:09 -0700 Date: Fri, 7 Sep 2018 15:37:51 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 09/12] mm: Restrict memory encryption to anonymous VMA's Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) 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 --- mm/mprotect.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mm/mprotect.c b/mm/mprotect.c index 6c2e1106525c..3384b755aad1 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -311,6 +311,24 @@ unsigned long change_protection(struct vm_area_struct *vma, unsigned long start, return pages; } +/* + * 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, @@ -491,6 +509,10 @@ 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 Fri Sep 7 22:38:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592675 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 BCF1314E2 for ; Fri, 7 Sep 2018 22:37:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC214292AC for ; Fri, 7 Sep 2018 22:37:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A042F2B2D7; Fri, 7 Sep 2018 22:37:38 +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 487A2292AC for ; Fri, 7 Sep 2018 22:37:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726434AbeIHDUp (ORCPT ); Fri, 7 Sep 2018 23:20:45 -0400 Received: from mga18.intel.com ([134.134.136.126]:12679 "EHLO mga18.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726010AbeIHDUp (ORCPT ); Fri, 7 Sep 2018 23:20:45 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:37:37 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="231141235" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by orsmga004.jf.intel.com with ESMTP; 07 Sep 2018 15:37:27 -0700 Date: Fri, 7 Sep 2018 15:38:10 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 10/12] x86/pconfig: Program memory encryption keys on a system-wide basis Message-ID: <0947e4ad711e8b7c1f581a446e808f514620b49b.1536356108.git.alison.schofield@intel.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) 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. Signed-off-by: Alison Schofield --- arch/x86/include/asm/intel_pconfig.h | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/intel_pconfig.h b/arch/x86/include/asm/intel_pconfig.h index 3cb002b1d0f9..d3bf0a297e89 100644 --- a/arch/x86/include/asm/intel_pconfig.h +++ b/arch/x86/include/asm/intel_pconfig.h @@ -3,6 +3,7 @@ #include #include +#include enum pconfig_target { INVALID_TARGET = 0, @@ -47,19 +48,48 @@ struct mktme_key_program { u8 key_field_2[64]; } __packed __aligned(256); -static inline int mktme_key_program(struct mktme_key_program *key_program) +struct mktme_key_program_info { + struct mktme_key_program *key_program; + unsigned long status; +}; + +static void mktme_package_program(void *key_program_info) { + struct mktme_key_program_info *info = key_program_info; unsigned long rax = MKTME_KEY_PROGRAM; + asm volatile(PCONFIG + : "=a" (rax), "=b" (info->key_program) + : "0" (rax), "1" (info->key_program) + : "memory", "cc"); + + if (rax != MKTME_PROG_SUCCESS) + WRITE_ONCE(info->status, rax); +} + +/* + * MKTME keys are managed as a system-wide single pool of keys. + * In the hardware, each physical package maintains a separate key + * table. Program all physical packages with the same key info to + * maintain that system-wide kernel view. + */ +static inline int mktme_key_program(struct mktme_key_program *key_program, + cpumask_var_t mktme_cpumask) +{ + struct mktme_key_program_info info = { + .key_program = key_program, + .status = MKTME_PROG_SUCCESS, + }; + if (!pconfig_target_supported(MKTME_TARGET)) return -ENXIO; - asm volatile(PCONFIG - : "=a" (rax), "=b" (key_program) - : "0" (rax), "1" (key_program) - : "memory", "cc"); + get_online_cpus(); + on_each_cpu_mask(mktme_cpumask, mktme_package_program, + &info, 1); + put_online_cpus(); - return rax; + return info.status; } #endif /* _ASM_X86_INTEL_PCONFIG_H */ From patchwork Fri Sep 7 22:38:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592679 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 786731515 for ; Fri, 7 Sep 2018 22:37:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 64A1529BFA for ; Fri, 7 Sep 2018 22:37:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 574662B5E0; Fri, 7 Sep 2018 22:37:57 +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 1469A29BFA for ; Fri, 7 Sep 2018 22:37:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727142AbeIHDVD (ORCPT ); Fri, 7 Sep 2018 23:21:03 -0400 Received: from mga09.intel.com ([134.134.136.24]:25605 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727125AbeIHDVD (ORCPT ); Fri, 7 Sep 2018 23:21:03 -0400 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:37:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="88621452" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by orsmga001.jf.intel.com with ESMTP; 07 Sep 2018 15:37:54 -0700 Date: Fri, 7 Sep 2018 15:38:36 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 11/12] keys/mktme: Add a new key service type for memory encryption keys Message-ID: <1a14a6feb02f968c5e6b98360f6f16106b633b58.1536356108.git.alison.schofield@intel.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) 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 software keys to hardware keyids and 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-keys.txt Signed-off-by: Alison Schofield --- arch/x86/Kconfig | 1 + include/keys/mktme-type.h | 28 +++++ security/keys/Kconfig | 11 ++ security/keys/Makefile | 1 + security/keys/mktme_keys.c | 278 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 319 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 023a22568c06..50d8aa6a58e9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1527,6 +1527,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..bebe74cb2b51 --- /dev/null +++ b/include/keys/mktme-type.h @@ -0,0 +1,28 @@ +/* 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 option: userkey=, tweak=, entropy=. + */ +#define MKTME_AES_XTS_SIZE 16 + +enum mktme_alg { + MKTME_ALG_AES_XTS_128, +}; + +const char *const mktme_alg_names[] = { + [MKTME_ALG_AES_XTS_128] = "aes_xts_128", +}; + +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 ef1581b337a3..2d9f9a82cb8a 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.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..dcbce7194647 --- /dev/null +++ b/security/keys/mktme_keys.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-3.0 + +/* Documentation/x86/mktme-keys.txt */ + +#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 struct */ +cpumask_var_t mktme_cpumask; /* one cpu per pkg to program keys */ + +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 */ +}; + +/* If a key is available, program and add the key to the software map. */ +static int mktme_program_key(key_serial_t serial, + struct mktme_key_program *kprog) +{ + int keyid, ret; + + keyid = mktme_map_get_free_keyid(); + if (keyid == 0) + return -EDQUOT; + + kprog->keyid = keyid; + ret = mktme_key_program(kprog, mktme_cpumask); + if (ret == MKTME_PROG_SUCCESS) + mktme_map_set_keyid(keyid, serial); + else + pr_debug("mktme: %s [%d]\n", mktme_program_err[ret], ret); + + return ret; +} + +enum mktme_opt_id { + OPT_ERROR = -1, + OPT_USERKEY, + OPT_TWEAK, + OPT_ENTROPY, + OPT_ALGORITHM, +}; + +static const match_table_t mktme_token = { + {OPT_USERKEY, "userkey=%s"}, + {OPT_TWEAK, "tweak=%s"}, + {OPT_ENTROPY, "entropy=%s"}, + {OPT_ALGORITHM, "algorithm=%s"}, + {OPT_ERROR, NULL} + +}; + +/* + * Algorithm AES-XTS 128 is the only supported encryption algorithm. + * CPU Generated Key: requires user supplied entropy and accepts no + * other options. + * User Supplied Key: requires user supplied tweak key and accepts + * no other options. + */ +static int mktme_check_options(struct mktme_key_program *kprog, + unsigned long token_mask) +{ + if (!token_mask) + return -EINVAL; + + kprog->keyid_ctrl |= MKTME_AES_XTS_128; + + if (!test_bit(OPT_USERKEY, &token_mask)) { + if ((!test_bit(OPT_ENTROPY, &token_mask)) || + (test_bit(OPT_TWEAK, &token_mask))) + return -EINVAL; + + kprog->keyid_ctrl |= MKTME_KEYID_SET_KEY_RANDOM; + } + if (test_bit(OPT_USERKEY, &token_mask)) { + if ((test_bit(OPT_ENTROPY, &token_mask)) || + (!test_bit(OPT_TWEAK, &token_mask))) + return -EINVAL; + + kprog->keyid_ctrl |= MKTME_KEYID_SET_KEY_DIRECT; + } + return 0; +} + +/* + * Parse the options and begin to fill in the key programming struct kprog. + * Check the lengths of incoming data and push data directly into kprog fields. + */ +static int mktme_get_options(char *options, struct mktme_key_program *kprog) +{ + int len = MKTME_AES_XTS_SIZE / 2; + substring_t args[MAX_OPT_ARGS]; + unsigned long token_mask = 0; + enum mktme_alg alg; + 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_USERKEY: + if (strlen(args[0].from) != MKTME_AES_XTS_SIZE) + return -EINVAL; + ret = hex2bin(kprog->key_field_1, args[0].from, len); + if (ret < 0) + return -EINVAL; + break; + + case OPT_TWEAK: + if (strlen(args[0].from) != MKTME_AES_XTS_SIZE) + return -EINVAL; + ret = hex2bin(kprog->key_field_2, args[0].from, len); + if (ret < 0) + return -EINVAL; + break; + + case OPT_ENTROPY: + if (strlen(args[0].from) != MKTME_AES_XTS_SIZE) + return -EINVAL; + /* Applied to both CPU-generated data and tweak keys */ + ret = hex2bin(kprog->key_field_1, args[0].from, len); + ret = hex2bin(kprog->key_field_2, args[0].from, len); + if (ret < 0) + return -EINVAL; + break; + + case OPT_ALGORITHM: + alg = match_string(mktme_alg_names, + ARRAY_SIZE(mktme_alg_names), + args[0].from); + if (alg != MKTME_ALG_AES_XTS_128) + return -EINVAL; + break; + + default: + return -EINVAL; + } + } + return mktme_check_options(kprog, token_mask); +} + +/* Key Service Command: Creates a software key and programs hardware */ +int mktme_instantiate(struct key *key, struct key_preparsed_payload *prep) +{ + struct mktme_key_program *kprog = NULL; + size_t datalen = prep->datalen; + char *options; + int ret = 0; + + 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'; + + kprog = kmem_cache_zalloc(mktme_prog_cache, GFP_KERNEL); + if (!kprog) { + kzfree(options); + return -ENOMEM; + } + ret = mktme_get_options(options, kprog); + if (ret < 0) + goto out; + + mktme_map_lock(); + ret = mktme_program_key(key->serial, kprog); + mktme_map_unlock(); +out: + kzfree(options); + kmem_cache_free(mktme_prog_cache, kprog); + return ret; +} + +struct key_type key_type_mktme = { + .name = "mktme", + .instantiate = mktme_instantiate, + .describe = user_describe, +}; + +/* + * Build mktme_cpumask to include one cpu per physical package. + * The mask is used in mktme_key_program() when the hardware key + * table is programmed on a per package basis. + */ +static int mktme_build_cpumask(void) +{ + int online_cpu, mktme_cpu; + int online_pkgid, mktme_pkgid = -1; + + if (!zalloc_cpumask_var(&mktme_cpumask, GFP_KERNEL)) + return -ENOMEM; + + for_each_online_cpu(online_cpu) { + online_pkgid = topology_physical_package_id(online_cpu); + + for_each_cpu(mktme_cpu, mktme_cpumask) { + 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_cpumask); + } + return 0; +} + +/* + * Allocate the global key map structure based on the available keyids + * at boot time. Create a cache and a cpu_mask to use for programming + * the hardware. 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 (vma_alloc_encrypt_array() < 0) + goto free_cache; + + if (mktme_build_cpumask() < 0) + goto free_array; + + ret = register_key_type(&key_type_mktme); + if (!ret) + return ret; + + free_cpumask_var(mktme_cpumask); +free_array: + vma_free_encrypt_array(); +free_cache: + kmem_cache_destroy(mktme_prog_cache); +free_map: + mktme_map_free(); + + return -ENOMEM; +} + +late_initcall(init_mktme); From patchwork Fri Sep 7 22:39:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alison Schofield X-Patchwork-Id: 10592683 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 A1C7E14E2 for ; Fri, 7 Sep 2018 22:38:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 910232B627 for ; Fri, 7 Sep 2018 22:38:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8497F2B630; Fri, 7 Sep 2018 22:38:24 +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 09D972B627 for ; Fri, 7 Sep 2018 22:38:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726486AbeIHDVb (ORCPT ); Fri, 7 Sep 2018 23:21:31 -0400 Received: from mga12.intel.com ([192.55.52.136]:59726 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726355AbeIHDVb (ORCPT ); Fri, 7 Sep 2018 23:21:31 -0400 X-Amp-Result: UNKNOWN X-Amp-Original-Verdict: FILE UNKNOWN X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 07 Sep 2018 15:38:22 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,344,1531810800"; d="scan'208";a="261684753" Received: from alison-desk.jf.intel.com ([10.54.74.53]) by fmsmga006.fm.intel.com with ESMTP; 07 Sep 2018 15:38:22 -0700 Date: Fri, 7 Sep 2018 15:39:04 -0700 From: Alison Schofield To: dhowells@redhat.com, tglx@linutronix.de Cc: Kai Huang , Jun Nakajima , Kirill Shutemov , Dave Hansen , Jarkko Sakkinen , jmorris@namei.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, linux-mm@kvack.org Subject: [RFC 12/12] keys/mktme: Do not revoke in use memory encryption keys Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP The MKTME key service maps userspace keys to hardware keyids. Those keys are used in a new system call that encrypts memory. The keys need to be tightly controlled. One example is that userspace keys should not be revoked while the hardware keyid slot is still in use. The KEY_FLAG_KEEP bit offers good control. The mktme service uses that flag to prevent userspace keys from going away without proper synchronization with the mktme service type. The problem is that we need a safe and synchronous way to revoke keys. The way .revoke methods function now, the key service type is called late in the revoke process for cleanup after the fact. The mktme key service has no means to consider and perhaps reject the revoke request. This proposal inserts the MKTME revoke call earlier into the existing keyctl path. If it is safe to revoke the key, MKTME key service will turn off KEY_FLAG_KEEP and let the revoke continue and succeed. Otherwise, not safe, KEY_FLAG_KEEP stays on, which causes the normal path of revoke to fail. For the MKTME Key Service, a revoke may be done safely when there are no outstanding memory mappings encrypted with the key being revoked. Signed-off-by: Alison Schofield --- security/keys/internal.h | 6 ++++++ security/keys/keyctl.c | 7 +++++++ security/keys/mktme_keys.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/security/keys/internal.h b/security/keys/internal.h index 9f8208dc0e55..9fb871522efe 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -316,4 +316,10 @@ static inline void key_check(const struct key *key) #endif +#ifdef CONFIG_MKTME_KEYS +extern void mktme_revoke_key(struct key *key); +#else +static inline void mktme_revoke_key(struct key *key) {} +#endif /* CONFIG_MKTME_KEYS */ + #endif /* _INTERNAL_H */ diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 1ffe60bb2845..86d2596ff275 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -363,6 +363,9 @@ long keyctl_update_key(key_serial_t id, * and any links to the key will be automatically garbage collected after a * certain amount of time (/proc/sys/kernel/keys/gc_delay). * + * The MKTME key service type checks if a memory encryption key is in use + * before allowing a revoke to proceed. + * * Keys with KEY_FLAG_KEEP set should not be revoked. * * If successful, 0 is returned. @@ -387,6 +390,10 @@ long keyctl_revoke_key(key_serial_t id) key = key_ref_to_ptr(key_ref); ret = 0; + + if (strcmp(key->type->name, "mktme") == 0) + mktme_revoke_key(key); + if (test_bit(KEY_FLAG_KEEP, &key->flags)) ret = -EPERM; else diff --git a/security/keys/mktme_keys.c b/security/keys/mktme_keys.c index dcbce7194647..c665be860538 100644 --- a/security/keys/mktme_keys.c +++ b/security/keys/mktme_keys.c @@ -31,6 +31,52 @@ static const char * const mktme_program_err[] = { "Failure to access key table", /* 5 */ }; +static int mktme_clear_programmed_key(int keyid) +{ + struct mktme_key_program *kprog = NULL; + int ret; + + kprog = kmem_cache_zalloc(mktme_prog_cache, GFP_KERNEL); + if (!kprog) + return -ENOMEM; + + kprog->keyid = keyid; + kprog->keyid_ctrl = MKTME_KEYID_CLEAR_KEY; + ret = mktme_key_program(kprog, mktme_cpumask); + if (ret == MKTME_PROG_SUCCESS) + mktme_map_clear_keyid(keyid); + else + pr_debug("mktme: %s [%d]\n", mktme_program_err[ret], ret); + + kmem_cache_free(mktme_prog_cache, kprog); + return ret; +} + +/* + * If the key is not in use, clear the hardware programming and + * allow the revoke to continue by clearing KEY_FLAG_KEEP. + */ +void mktme_revoke_key(struct key *key) +{ + int keyid, vma_count; + + mktme_map_lock(); + keyid = mktme_map_keyid_from_serial(key->serial); + if (keyid <= 0) + goto out; + + vma_count = vma_read_encrypt_ref(keyid); + if (vma_count > 0) { + pr_debug("mktme not freeing keyid[%d] encrypt_count[%d]\n", + keyid, vma_count); + goto out; + } + if (!mktme_clear_programmed_key(keyid)) + clear_bit(KEY_FLAG_KEEP, &key->flags); +out: + mktme_map_unlock(); +} + /* If a key is available, program and add the key to the software map. */ static int mktme_program_key(key_serial_t serial, struct mktme_key_program *kprog) @@ -193,6 +239,7 @@ int mktme_instantiate(struct key *key, struct key_preparsed_payload *prep) mktme_map_lock(); ret = mktme_program_key(key->serial, kprog); + set_bit(KEY_FLAG_KEEP, &key->flags); mktme_map_unlock(); out: kzfree(options);