From: Alison Schofield <alison.schofield@xxxxxxxxx> The MKTME encryption hardware resides on each physical package. The encryption hardware includes 'Key Tables' that must be programmed identically across all physical packages in the platform. Although every CPU in a package can program its key table, the kernel uses one lead CPU per package for programming. CPU Hotplug Teardown -------------------- MKTME manages CPU hotplug teardown to make sure the ability to program all packages is preserved when MKTME keys are present. When MKTME keys are not currently programmed, simply allow the teardown, and set "mktme_allow_keys" to false. This will force a re-evaluation of the platform topology before the next key creation. If this CPU teardown mattered, MKTME key service will report an error and fail to create the key. (User can online that CPU and try again) When MKTME keys are currently programmed, allow teardowns of non 'lead CPU's' and of CPUs where another, core sibling CPU, can take over as lead. Do not allow teardown of any lead CPU that would render a hardware key table unreachable! CPU Hotplug Startup ------------------- CPUs coming online are of interest to the key service, but since the service never needs to block a CPU startup event, nor does it need to prepare for an onlining CPU, a callback is not implemented. MKTME will catch the availability of the new CPU, if it is needed, at the next key creation time. If keys are not allowed, that new CPU will be part of the topology evaluation to determine if keys should now be allowed. Signed-off-by: Alison Schofield <alison.schofield@xxxxxxxxx> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> --- security/keys/mktme_keys.c | 51 +++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/security/keys/mktme_keys.c b/security/keys/mktme_keys.c index 734e1d28eb24..3dfc0647f1e5 100644 --- a/security/keys/mktme_keys.c +++ b/security/keys/mktme_keys.c @@ -102,9 +102,9 @@ void mktme_percpu_ref_release(struct percpu_ref *ref) return; } percpu_ref_exit(ref); - spin_lock_irqsave(&mktme_map_lock, flags); + spin_lock_irqsave(&mktme_lock, flags); mktme_release_keyid(keyid); - spin_unlock_irqrestore(&mktme_map_lock, flags); + spin_unlock_irqrestore(&mktme_lock, flags); } enum mktme_opt_id { @@ -506,9 +506,46 @@ static int mktme_alloc_pconfig_targets(void) return 0; } +static int mktme_cpu_teardown(unsigned int cpu) +{ + int new_leadcpu, ret = 0; + unsigned long flags; + + /* Do not allow key programming during cpu hotplug event */ + spin_lock_irqsave(&mktme_lock, flags); + + /* + * When no keys are in use, allow the teardown, and set + * mktme_allow_keys to FALSE. That forces an evaluation + * of the topology before the next key creation. + */ + if (!mktme_map->mapped_keyids) { + mktme_allow_keys = false; + goto out; + } + /* Teardown CPU is not a lead CPU. Allow teardown. */ + if (!cpumask_test_cpu(cpu, mktme_leadcpus)) + goto out; + + /* Teardown CPU is a lead CPU. Look for a new lead CPU. */ + new_leadcpu = cpumask_any_but(topology_core_cpumask(cpu), cpu); + + if (new_leadcpu < nr_cpumask_bits) { + /* New lead CPU found. Update the programming mask */ + __cpumask_clear_cpu(cpu, mktme_leadcpus); + __cpumask_set_cpu(new_leadcpu, mktme_leadcpus); + } else { + /* New lead CPU not found. Do not allow CPU teardown */ + ret = -1; + } +out: + spin_unlock_irqrestore(&mktme_lock, flags); + return ret; +} + static int __init init_mktme(void) { - int ret; + int ret, cpuhp; /* Verify keys are present */ if (mktme_nr_keyids < 1) @@ -553,10 +590,18 @@ static int __init init_mktme(void) if (!mktme_key_store) goto free_bitmap; + cpuhp = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, + "keys/mktme_keys:online", + NULL, mktme_cpu_teardown); + if (cpuhp < 0) + goto free_store; + ret = register_key_type(&key_type_mktme); if (!ret) return ret; /* SUCCESS */ + cpuhp_remove_state_nocalls(cpuhp); +free_store: kfree(mktme_key_store); free_bitmap: bitmap_free(mktme_bitmap_user_type); -- 2.20.1