Linux-Security-Module Archive on lore.kernel.org
 help / color / Atom feed
From: Alison Schofield <alison.schofield@intel.com>
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: <c14d24b09ee2ae37ea4106726ce8fe2aea31f6c7.1543903910.git.alison.schofield@intel.com> (raw)
In-Reply-To: <cover.1543903910.git.alison.schofield@intel.com>

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 <alison.schofield@intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
---
 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);
-- 
2.14.1


  parent reply index

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-04  7:39 [RFC v2 00/13] Multi-Key Total Memory Encryption API (MKTME) Alison Schofield
2018-12-04  7:39 ` [RFC v2 01/13] x86/mktme: Document the MKTME APIs Alison Schofield
2018-12-05 18:11   ` Andy Lutomirski
2018-12-05 19:22     ` Alison Schofield
2018-12-05 23:35       ` Andy Lutomirski
2018-12-06  8:04   ` Sakkinen, Jarkko
2018-12-04  7:39 ` [RFC v2 02/13] mm: Generalize the mprotect implementation to support extensions Alison Schofield
2018-12-06  8:08   ` Sakkinen, Jarkko
2018-12-04  7:39 ` [RFC v2 03/13] syscall/x86: Wire up a new system call for memory encryption keys Alison Schofield
2018-12-04  7:39 ` [RFC v2 04/13] x86/mm: Add helper functions for MKTME " Alison Schofield
2018-12-04  9:14   ` Peter Zijlstra
2018-12-05  5:49     ` Alison Schofield
2018-12-04 15:35   ` Andy Lutomirski
2018-12-05  5:52     ` Alison Schofield
2018-12-06  8:31   ` Sakkinen, Jarkko
2018-12-04  7:39 ` [RFC v2 05/13] x86/mm: Set KeyIDs in encrypted VMAs Alison Schofield
2018-12-06  8:37   ` Sakkinen, Jarkko
2018-12-04  7:39 ` [RFC v2 06/13] mm: Add the encrypt_mprotect() system call Alison Schofield
2018-12-06  8:38   ` Sakkinen, Jarkko
2018-12-04  7:39 ` [RFC v2 07/13] x86/mm: Add helpers for reference counting encrypted VMAs Alison Schofield
2018-12-04  8:58   ` Peter Zijlstra
2018-12-05  5:28     ` Alison Schofield
2018-12-04  7:39 ` [RFC v2 08/13] mm: Use reference counting for " Alison Schofield
2018-12-04  7:39 ` [RFC v2 09/13] mm: Restrict memory encryption to anonymous VMA's Alison Schofield
2018-12-04  9:10   ` Peter Zijlstra
2018-12-05  5:30     ` Alison Schofield
2018-12-05  9:07       ` Peter Zijlstra
2018-12-04  7:39 ` [RFC v2 10/13] keys/mktme: Add the MKTME Key Service type for memory encryption Alison Schofield
2018-12-06  8:51   ` Sakkinen, Jarkko
2018-12-06  8:54     ` Sakkinen, Jarkko
2018-12-06 15:11     ` Dave Hansen
2018-12-06 22:56       ` Sakkinen, Jarkko
2018-12-04  7:39 ` [RFC v2 11/13] keys/mktme: Program memory encryption keys on a system wide basis Alison Schofield
2018-12-04  9:21   ` Peter Zijlstra
2018-12-04  9:50     ` Kirill A. Shutemov
2018-12-05  5:44       ` Alison Schofield
2018-12-05  5:43     ` Alison Schofield
2018-12-05  9:10       ` Peter Zijlstra
2018-12-05 17:26         ` Alison Schofield
2018-12-04  7:39 ` [RFC v2 12/13] keys/mktme: Save MKTME data if kernel cmdline parameter allows Alison Schofield
2018-12-04  9:22   ` Peter Zijlstra
2018-12-07  2:14   ` Huang, Kai
2018-12-07  3:42     ` Alison Schofield
2018-12-07  6:39     ` Jarkko Sakkinen
2018-12-07  6:45       ` Jarkko Sakkinen
2018-12-07 11:47     ` Kirill A. Shutemov
2018-12-04  7:40 ` Alison Schofield [this message]
2018-12-04  9:28   ` [RFC v2 13/13] keys/mktme: Support CPU Hotplug for MKTME keys Peter Zijlstra
2018-12-05  5:32     ` Alison Schofield
2018-12-04  9:31   ` Peter Zijlstra
2018-12-05  5:36     ` Alison Schofield
2018-12-04  9:25 ` [RFC v2 00/13] Multi-Key Total Memory Encryption API (MKTME) Peter Zijlstra
2018-12-04  9:46   ` Kirill A. Shutemov
2018-12-05 20:32     ` Sakkinen, Jarkko
2018-12-06 11:22       ` Kirill A. Shutemov
2018-12-06 14:59         ` Dave Hansen
2018-12-07 10:12           ` Huang, Kai
2018-12-06 21:23         ` Sakkinen, Jarkko
2018-12-07 11:54           ` Kirill A. Shutemov
2018-12-04 19:19 ` Andy Lutomirski
2018-12-04 20:00   ` Andy Lutomirski
2018-12-04 20:32     ` Dave Hansen
2018-12-05 22:19   ` Sakkinen, Jarkko
2018-12-07  2:05     ` Huang, Kai
2018-12-07  6:48       ` Jarkko Sakkinen
2018-12-07 11:57     ` Kirill A. Shutemov
2018-12-07 21:59       ` Sakkinen, Jarkko
2018-12-07 23:45         ` Sakkinen, Jarkko
2018-12-07 23:48           ` Andy Lutomirski
2018-12-08  1:33           ` Huang, Kai
2018-12-08  3:53             ` Sakkinen, Jarkko
2018-12-12 15:31           ` Sakkinen, Jarkko
2018-12-12 16:29             ` Andy Lutomirski
2018-12-12 16:43               ` Sakkinen, Jarkko
2018-12-12 23:27                 ` Huang, Kai
2018-12-13  5:49                   ` Sakkinen, Jarkko
2018-12-13  5:52                     ` Sakkinen, Jarkko
2018-12-12 23:24               ` Huang, Kai
2018-12-07 23:35       ` Eric Rannaud
2018-12-05 23:49   ` Dave Hansen
2018-12-06  1:09     ` Andy Lutomirski
2018-12-06  1:25       ` Dan Williams
2018-12-06 15:39       ` Dave Hansen
2018-12-06 19:10         ` Andy Lutomirski
2018-12-06 19:31           ` Dave Hansen
2018-12-07  1:55       ` Huang, Kai
2018-12-07  4:23         ` Dave Hansen
2018-12-07 23:53         ` Andy Lutomirski
2018-12-08  1:11           ` Dave Hansen
2018-12-08  2:07           ` Huang, Kai
2018-12-05 20:30 ` Sakkinen, Jarkko

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c14d24b09ee2ae37ea4106726ce8fe2aea31f6c7.1543903910.git.alison.schofield@intel.com \
    --to=alison.schofield@intel.com \
    --cc=bp@alien8.de \
    --cc=dan.j.williams@intel.com \
    --cc=dave.hansen@intel.com \
    --cc=dhowells@redhat.com \
    --cc=hpa@zytor.com \
    --cc=jarkko.sakkinen@intel.com \
    --cc=jmorris@namei.org \
    --cc=jun.nakajima@intel.com \
    --cc=kai.huang@intel.com \
    --cc=keyrings@vger.kernel.org \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=linux-mm@kvack.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-Security-Module Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-security-module/0 linux-security-module/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-security-module linux-security-module/ https://lore.kernel.org/linux-security-module \
		linux-security-module@vger.kernel.org linux-security-module@archiver.kernel.org
	public-inbox-index linux-security-module


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-security-module


AGPL code for this site: git clone https://public-inbox.org/ public-inbox