Merge tag 'x86_sgx_for_6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 SGX updates from Dave HansenL
 "The main content here is adding support for the new EUPDATESVN SGX
  ISA. Before this, folks who updated microcode had to reboot before
  enclaves could attest to the new microcode. The new functionality lets
  them do this without a reboot.

  The rest are some nice, but relatively mundane comment and kernel-doc
  fixups.

  Summary:

   - Allow security version (SVN) updates so enclaves can attest to new
     microcode

   - Fix kernel docs typos"

* tag 'x86_sgx_for_6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/sgx: Fix a typo in the kernel-doc comment for enum sgx_attribute
  x86/sgx: Remove superfluous asterisk from copyright comment in asm/sgx.h
  x86/sgx: Document structs and enums with '@', not '%'
  x86/sgx: Add kernel-doc descriptions for params passed to vDSO user handler
  x86/sgx: Add a missing colon in kernel-doc markup for "struct sgx_enclave_run"
  x86/sgx: Enable automatic SVN updates for SGX enclaves
  x86/sgx: Implement ENCLS[EUPDATESVN]
  x86/sgx: Define error codes for use by ENCLS[EUPDATESVN]
  x86/cpufeatures: Add X86_FEATURE_SGX_EUPDATESVN feature flag
  x86/sgx: Introduce functions to count the sgx_(vepc_)open()
This commit is contained in:
Linus Torvalds
2025-12-02 14:03:05 -08:00
11 changed files with 210 additions and 49 deletions

View File

@@ -499,6 +499,7 @@
#define X86_FEATURE_IBPB_EXIT_TO_USER (21*32+14) /* Use IBPB on exit-to-userspace, see VMSCAPE bug */
#define X86_FEATURE_ABMC (21*32+15) /* Assignable Bandwidth Monitoring Counters */
#define X86_FEATURE_MSR_IMM (21*32+16) /* MSR immediate form instructions */
#define X86_FEATURE_SGX_EUPDATESVN (21*32+17) /* Support for ENCLS[EUPDATESVN] instruction */
#define X86_FEATURE_SDCIAE (21*32+18) /* L3 Smart Data Cache Injection Allocation Enforcement */

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/**
/*
* Copyright(c) 2016-20 Intel Corporation.
*
* Intel Software Guard Extensions (SGX) support.
@@ -28,21 +28,22 @@
#define SGX_CPUID_EPC_MASK GENMASK(3, 0)
enum sgx_encls_function {
ECREATE = 0x00,
EADD = 0x01,
EINIT = 0x02,
EREMOVE = 0x03,
EDGBRD = 0x04,
EDGBWR = 0x05,
EEXTEND = 0x06,
ELDU = 0x08,
EBLOCK = 0x09,
EPA = 0x0A,
EWB = 0x0B,
ETRACK = 0x0C,
EAUG = 0x0D,
EMODPR = 0x0E,
EMODT = 0x0F,
ECREATE = 0x00,
EADD = 0x01,
EINIT = 0x02,
EREMOVE = 0x03,
EDGBRD = 0x04,
EDGBWR = 0x05,
EEXTEND = 0x06,
ELDU = 0x08,
EBLOCK = 0x09,
EPA = 0x0A,
EWB = 0x0B,
ETRACK = 0x0C,
EAUG = 0x0D,
EMODPR = 0x0E,
EMODT = 0x0F,
EUPDATESVN = 0x18,
};
/**
@@ -65,15 +66,19 @@ enum sgx_encls_function {
/**
* enum sgx_return_code - The return code type for ENCLS, ENCLU and ENCLV
* %SGX_EPC_PAGE_CONFLICT: Page is being written by other ENCLS function.
* %SGX_NOT_TRACKED: Previous ETRACK's shootdown sequence has not
* @SGX_EPC_PAGE_CONFLICT: Page is being written by other ENCLS function.
* @SGX_NOT_TRACKED: Previous ETRACK's shootdown sequence has not
* been completed yet.
* %SGX_CHILD_PRESENT SECS has child pages present in the EPC.
* %SGX_INVALID_EINITTOKEN: EINITTOKEN is invalid and enclave signer's
* @SGX_CHILD_PRESENT: SECS has child pages present in the EPC.
* @SGX_INVALID_EINITTOKEN: EINITTOKEN is invalid and enclave signer's
* public key does not match IA32_SGXLEPUBKEYHASH.
* %SGX_PAGE_NOT_MODIFIABLE: The EPC page cannot be modified because it
* @SGX_PAGE_NOT_MODIFIABLE: The EPC page cannot be modified because it
* is in the PENDING or MODIFIED state.
* %SGX_UNMASKED_EVENT: An unmasked event, e.g. INTR, was received
* @SGX_INSUFFICIENT_ENTROPY: Insufficient entropy in RNG.
* @SGX_NO_UPDATE: EUPDATESVN could not update the CPUSVN because the
* current SVN was not newer than CPUSVN. This is the most
* common error code returned by EUPDATESVN.
* @SGX_UNMASKED_EVENT: An unmasked event, e.g. INTR, was received
*/
enum sgx_return_code {
SGX_EPC_PAGE_CONFLICT = 7,
@@ -81,6 +86,8 @@ enum sgx_return_code {
SGX_CHILD_PRESENT = 13,
SGX_INVALID_EINITTOKEN = 16,
SGX_PAGE_NOT_MODIFIABLE = 20,
SGX_INSUFFICIENT_ENTROPY = 29,
SGX_NO_UPDATE = 31,
SGX_UNMASKED_EVENT = 128,
};
@@ -89,7 +96,7 @@ enum sgx_return_code {
/**
* enum sgx_miscselect - additional information to an SSA frame
* %SGX_MISC_EXINFO: Report #PF or #GP to the SSA frame.
* @SGX_MISC_EXINFO: Report #PF or #GP to the SSA frame.
*
* Save State Area (SSA) is a stack inside the enclave used to store processor
* state when an exception or interrupt occurs. This enum defines additional
@@ -105,17 +112,17 @@ enum sgx_miscselect {
#define SGX_SSA_MISC_EXINFO_SIZE 16
/**
* enum sgx_attributes - the attributes field in &struct sgx_secs
* %SGX_ATTR_INIT: Enclave can be entered (is initialized).
* %SGX_ATTR_DEBUG: Allow ENCLS(EDBGRD) and ENCLS(EDBGWR).
* %SGX_ATTR_MODE64BIT: Tell that this a 64-bit enclave.
* %SGX_ATTR_PROVISIONKEY: Allow to use provisioning keys for remote
* enum sgx_attribute - the attributes field in &struct sgx_secs
* @SGX_ATTR_INIT: Enclave can be entered (is initialized).
* @SGX_ATTR_DEBUG: Allow ENCLS(EDBGRD) and ENCLS(EDBGWR).
* @SGX_ATTR_MODE64BIT: Tell that this a 64-bit enclave.
* @SGX_ATTR_PROVISIONKEY: Allow to use provisioning keys for remote
* attestation.
* %SGX_ATTR_KSS: Allow to use key separation and sharing (KSS).
* %SGX_ATTR_EINITTOKENKEY: Allow to use token signing key that is used to
* @SGX_ATTR_KSS: Allow to use key separation and sharing (KSS).
* @SGX_ATTR_EINITTOKENKEY: Allow to use token signing key that is used to
* sign cryptographic tokens that can be passed to
* EINIT as an authorization to run an enclave.
* %SGX_ATTR_ASYNC_EXIT_NOTIFY: Allow enclaves to be notified after an
* @SGX_ATTR_ASYNC_EXIT_NOTIFY: Allow enclaves to be notified after an
* asynchronous exit has occurred.
*/
enum sgx_attribute {
@@ -188,7 +195,7 @@ struct sgx_secs {
/**
* enum sgx_tcs_flags - execution flags for TCS
* %SGX_TCS_DBGOPTIN: If enabled allows single-stepping and breakpoints
* @SGX_TCS_DBGOPTIN: If enabled allows single-stepping and breakpoints
* inside an enclave. It is cleared by EADD but can
* be set later with EDBGWR.
*/
@@ -253,11 +260,11 @@ struct sgx_pageinfo {
/**
* enum sgx_page_type - bits in the SECINFO flags defining the page type
* %SGX_PAGE_TYPE_SECS: a SECS page
* %SGX_PAGE_TYPE_TCS: a TCS page
* %SGX_PAGE_TYPE_REG: a regular page
* %SGX_PAGE_TYPE_VA: a VA page
* %SGX_PAGE_TYPE_TRIM: a page in trimmed state
* @SGX_PAGE_TYPE_SECS: a SECS page
* @SGX_PAGE_TYPE_TCS: a TCS page
* @SGX_PAGE_TYPE_REG: a regular page
* @SGX_PAGE_TYPE_VA: a VA page
* @SGX_PAGE_TYPE_TRIM: a page in trimmed state
*
* Make sure when making changes to this enum that its values can still fit
* in the bitfield within &struct sgx_encl_page
@@ -275,14 +282,14 @@ enum sgx_page_type {
/**
* enum sgx_secinfo_flags - the flags field in &struct sgx_secinfo
* %SGX_SECINFO_R: allow read
* %SGX_SECINFO_W: allow write
* %SGX_SECINFO_X: allow execution
* %SGX_SECINFO_SECS: a SECS page
* %SGX_SECINFO_TCS: a TCS page
* %SGX_SECINFO_REG: a regular page
* %SGX_SECINFO_VA: a VA page
* %SGX_SECINFO_TRIM: a page in trimmed state
* @SGX_SECINFO_R: allow read
* @SGX_SECINFO_W: allow write
* @SGX_SECINFO_X: allow execution
* @SGX_SECINFO_SECS: a SECS page
* @SGX_SECINFO_TCS: a TCS page
* @SGX_SECINFO_REG: a regular page
* @SGX_SECINFO_VA: a VA page
* @SGX_SECINFO_TRIM: a page in trimmed state
*/
enum sgx_secinfo_flags {
SGX_SECINFO_R = BIT(0),

View File

@@ -10,7 +10,7 @@
/**
* enum sgx_page_flags - page control flags
* %SGX_PAGE_MEASURE: Measure the page contents with a sequence of
* @SGX_PAGE_MEASURE: Measure the page contents with a sequence of
* ENCLS[EEXTEND] operations.
*/
enum sgx_page_flags {
@@ -143,6 +143,12 @@ struct sgx_enclave_run;
/**
* typedef sgx_enclave_user_handler_t - Exit handler function accepted by
* __vdso_sgx_enter_enclave()
* @rdi: RDI at the time of EEXIT, undefined on AEX
* @rsi: RSI at the time of EEXIT, undefined on AEX
* @rdx: RDX at the time of EEXIT, undefined on AEX
* @rsp: RSP (untrusted) at the time of EEXIT or AEX
* @r8: R8 at the time of EEXIT, undefined on AEX
* @r9: R9 at the time of EEXIT, undefined on AEX
* @run: The run instance given by the caller
*
* The register parameters contain the snapshot of their values at enclave
@@ -166,7 +172,7 @@ typedef int (*sgx_enclave_user_handler_t)(long rdi, long rsi, long rdx,
* @exception_addr: The address that triggered the exception
* @user_handler: User provided callback run on exception
* @user_data: Data passed to the user handler
* @reserved Reserved for future extensions
* @reserved: Reserved for future extensions
*
* If @user_handler is provided, the handler will be invoked on all return paths
* of the normal flow. The user handler may transfer control, e.g. via a

View File

@@ -80,6 +80,7 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_SGX_LC, X86_FEATURE_SGX },
{ X86_FEATURE_SGX1, X86_FEATURE_SGX },
{ X86_FEATURE_SGX2, X86_FEATURE_SGX1 },
{ X86_FEATURE_SGX_EUPDATESVN, X86_FEATURE_SGX1 },
{ X86_FEATURE_SGX_EDECCSSA, X86_FEATURE_SGX1 },
{ X86_FEATURE_XFD, X86_FEATURE_XSAVES },
{ X86_FEATURE_XFD, X86_FEATURE_XGETBV1 },

View File

@@ -43,6 +43,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_PER_THREAD_MBA, CPUID_ECX, 0, 0x00000010, 3 },
{ X86_FEATURE_SGX1, CPUID_EAX, 0, 0x00000012, 0 },
{ X86_FEATURE_SGX2, CPUID_EAX, 1, 0x00000012, 0 },
{ X86_FEATURE_SGX_EUPDATESVN, CPUID_EAX, 10, 0x00000012, 0 },
{ X86_FEATURE_SGX_EDECCSSA, CPUID_EAX, 11, 0x00000012, 0 },
{ X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 },
{ X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 },

View File

@@ -14,7 +14,7 @@ u64 sgx_attributes_reserved_mask;
u64 sgx_xfrm_reserved_mask = ~0x3;
u32 sgx_misc_reserved_mask;
static int sgx_open(struct inode *inode, struct file *file)
static int __sgx_open(struct inode *inode, struct file *file)
{
struct sgx_encl *encl;
int ret;
@@ -41,6 +41,23 @@ static int sgx_open(struct inode *inode, struct file *file)
return 0;
}
static int sgx_open(struct inode *inode, struct file *file)
{
int ret;
ret = sgx_inc_usage_count();
if (ret)
return ret;
ret = __sgx_open(inode, file);
if (ret) {
sgx_dec_usage_count();
return ret;
}
return 0;
}
static int sgx_release(struct inode *inode, struct file *file)
{
struct sgx_encl *encl = file->private_data;

View File

@@ -765,6 +765,7 @@ void sgx_encl_release(struct kref *ref)
WARN_ON_ONCE(encl->secs.epc_page);
kfree(encl);
sgx_dec_usage_count();
}
/*

View File

@@ -233,4 +233,9 @@ static inline int __eaug(struct sgx_pageinfo *pginfo, void *addr)
return __encls_2(EAUG, pginfo, addr);
}
/* Attempt to update CPUSVN at runtime. */
static inline int __eupdatesvn(void)
{
return __encls_ret_1(EUPDATESVN, "");
}
#endif /* _X86_ENCLS_H */

View File

@@ -16,6 +16,7 @@
#include <linux/vmalloc.h>
#include <asm/msr.h>
#include <asm/sgx.h>
#include <asm/archrandom.h>
#include "driver.h"
#include "encl.h"
#include "encls.h"
@@ -917,6 +918,106 @@ int sgx_set_attribute(unsigned long *allowed_attributes,
}
EXPORT_SYMBOL_GPL(sgx_set_attribute);
/* Counter to count the active SGX users */
static int sgx_usage_count;
/**
* sgx_update_svn() - Attempt to call ENCLS[EUPDATESVN].
*
* This instruction attempts to update CPUSVN to the
* currently loaded microcode update SVN and generate new
* cryptographic assets.
*
* Return:
* * %0: - Success or not supported
* * %-EAGAIN: - Can be safely retried, failure is due to lack of
* * entropy in RNG
* * %-EIO: - Unexpected error, retries are not advisable
*/
static int sgx_update_svn(void)
{
int ret;
/*
* If EUPDATESVN is not available, it is ok to
* silently skip it to comply with legacy behavior.
*/
if (!cpu_feature_enabled(X86_FEATURE_SGX_EUPDATESVN))
return 0;
/*
* EPC is guaranteed to be empty when there are no users.
* Ensure we are on our first user before proceeding further.
*/
WARN(sgx_usage_count, "Elevated usage count when calling EUPDATESVN\n");
for (int i = 0; i < RDRAND_RETRY_LOOPS; i++) {
ret = __eupdatesvn();
/* Stop on success or unexpected errors: */
if (ret != SGX_INSUFFICIENT_ENTROPY)
break;
}
switch (ret) {
case 0:
/*
* SVN successfully updated.
* Let users know when the update was successful.
*/
pr_info("SVN updated successfully\n");
return 0;
case SGX_NO_UPDATE:
/*
* SVN update failed since the current SVN is
* not newer than CPUSVN. This is the most
* common case and indicates no harm.
*/
return 0;
case SGX_INSUFFICIENT_ENTROPY:
/*
* SVN update failed due to lack of entropy in DRNG.
* Indicate to userspace that it should retry.
*/
return -EAGAIN;
default:
break;
}
/*
* EUPDATESVN was called when EPC is empty, all other error
* codes are unexpected.
*/
ENCLS_WARN(ret, "EUPDATESVN");
return -EIO;
}
/* Mutex to ensure no concurrent EPC accesses during EUPDATESVN */
static DEFINE_MUTEX(sgx_svn_lock);
int sgx_inc_usage_count(void)
{
int ret;
guard(mutex)(&sgx_svn_lock);
if (!sgx_usage_count) {
ret = sgx_update_svn();
if (ret)
return ret;
}
sgx_usage_count++;
return 0;
}
void sgx_dec_usage_count(void)
{
guard(mutex)(&sgx_svn_lock);
sgx_usage_count--;
}
static int __init sgx_init(void)
{
int ret;

View File

@@ -102,6 +102,9 @@ static inline int __init sgx_vepc_init(void)
}
#endif
int sgx_inc_usage_count(void);
void sgx_dec_usage_count(void);
void sgx_update_lepubkeyhash(u64 *lepubkeyhash);
#endif /* _X86_SGX_H */

View File

@@ -255,10 +255,11 @@ static int sgx_vepc_release(struct inode *inode, struct file *file)
xa_destroy(&vepc->page_array);
kfree(vepc);
sgx_dec_usage_count();
return 0;
}
static int sgx_vepc_open(struct inode *inode, struct file *file)
static int __sgx_vepc_open(struct inode *inode, struct file *file)
{
struct sgx_vepc *vepc;
@@ -273,6 +274,23 @@ static int sgx_vepc_open(struct inode *inode, struct file *file)
return 0;
}
static int sgx_vepc_open(struct inode *inode, struct file *file)
{
int ret;
ret = sgx_inc_usage_count();
if (ret)
return ret;
ret = __sgx_vepc_open(inode, file);
if (ret) {
sgx_dec_usage_count();
return ret;
}
return 0;
}
static long sgx_vepc_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{