요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
===============================
Software Guard eXtensions (SGX)
===============================
Overview
========
Software Guard eXtensions (SGX) hardware enables for user space applications
to set aside private memory regions of code and data:
* Privileged (ring-0) ENCLS functions orchestrate the construction of the
regions.
* Unprivileged (ring-3) ENCLU functions allow an application to enter and
execute inside the regions.
These memory regions are called enclaves. An enclave can be only entered at a
fixed set of entry points. Each entry point can hold a single hardware thread
at a time. While the enclave is loaded from a regular binary file by using
ENCLS functions, only the threads inside the enclave can access its memory. The
region is denied from outside access by the CPU, and encrypted before it leaves
from LLC.
The support can be determined by
``grep sgx /proc/cpuinfo``
SGX must both be supported in the processor and enabled by the BIOS. If SGX
appears to be unsupported on a system which has hardware support, ensure
support is enabled in the BIOS. If a BIOS presents a choice between "Enabled"
and "Software Enabled" modes for SGX, choose "Enabled".
Enclave Page Cache
==================
SGX utilizes an *Enclave Page Cache (EPC)* to store pages that are associated
with an enclave. It is contained in a BIOS-reserved region of physical memory.
Unlike pages used for regular memory, pages can only be accessed from outside of
the enclave during enclave construction with special, limited SGX instructions.
Only a CPU executing inside an enclave can directly access enclave memory.
However, a CPU executing inside an enclave may access normal memory outside the
enclave.
The kernel manages enclave memory similar to how it treats device memory.
Enclave Page Types
------------------
**SGX Enclave Control Structure (SECS)**
Enclave's address range, attributes and other global data are defined
by this structure.
**Regular (REG)**
Regular EPC pages contain the code and data of an enclave.
**Thread Control Structure (TCS)**
Thread Control Structure pages define the entry points to an enclave and
track the execution state of an enclave thread.
**Version Array (VA)**
Version Array pages contain 512 slots, each of which can contain a version
number for a page evicted from the EPC.
Enclave Page Cache Map
----------------------
The processor tracks EPC pages in a hardware metadata structure called the
*Enclave Page Cache Map (EPCM)*. The EPCM contains an entry for each EPC page
which describes the owning enclave, access rights and page type among the other
things.
EPCM permissions are separate from the normal page tables. This prevents the
kernel from, for instance, allowing writes to data which an enclave wishes to
remain read-only. EPCM permissions may only impose additional restrictions on
top of normal x86 page permissions.
For all intents and purposes, the SGX architecture allows the processor to
invalidate all EPCM entries at will. This requires that software be prepared to
handle an EPCM fault at any time. In practice, this can happen on events like
power transitions when the ephemeral key that encrypts enclave memory is lost.
Application interface
=====================
Enclave build functions
-----------------------
In addition to the traditional compiler and linker build process, SGX has a
separate enclave “build” process. Enclaves must be built before they can be
executed (entered). The first step in building an enclave is opening the
**/dev/sgx_enclave** device. Since enclave memory is protected from direct
access, special privileged instructions are then used to copy data into enclave
pages and establish enclave page permissions.
.. kernel-doc:: arch/x86/kernel/cpu/sgx/ioctl.c
:functions: sgx_ioc_enclave_create
sgx_ioc_enclave_add_pages
sgx_ioc_enclave_init
sgx_ioc_enclave_provision
Enclave runtime management
--------------------------
Systems supporting SGX2 additionally support changes to initialized
enclaves: modifying enclave page permissions and type, and dynamically
adding and removing of enclave pages. When an enclave accesses an address
within its address range that does not have a backing page then a new
regular page will be dynamically added to the enclave. The enclave is
still required to run EACCEPT on the new page before it can be used.
.. kernel-doc:: arch/x86/kernel/cpu/sgx/ioctl.c
:functions: sgx_ioc_enclave_restrict_permissions
sgx_ioc_enclave_modify_types
sgx_ioc_enclave_remove_pages
Enclave vDSO
------------
Entering an enclave can only be done through SGX-specific EENTER and ERESUME
functions, and is a non-trivial process. Because of the complexity of
transitioning to and from an enclave, enclaves typically utilize a library to
handle the actual transitions. This is roughly analogous to how glibc
implementations are used by most applications to wrap system calls.
Another crucial characteristic of enclaves is that they can generate exceptions
as part of their normal operation that need to be handled in the enclave or are
unique to SGX.
Instead of the traditional signal mechanism to handle these exceptions, SGX
can leverage special exception fixup provided by the vDSO. The kernel-provided
vDSO function wraps low-level transitions to/from the enclave like EENTER and
ERESUME. The vDSO function intercepts exceptions that would otherwise generate
a signal and return the fault information directly to its caller. This avoids
the need to juggle signal handlers.
.. kernel-doc:: arch/x86/include/uapi/asm/sgx.h
:functions: vdso_sgx_enter_enclave_t
ksgxd
=====
SGX support includes a kernel thread called *ksgxd*.
EPC sanitization
----------------
ksgxd is started when SGX initializes. Enclave memory is typically ready
for use when the processor powers on or resets. However, if SGX has been in
use since the reset, enclave pages may be in an inconsistent state. This might
occur after a crash and kexec() cycle, for instance. At boot, ksgxd
reinitializes all enclave pages so that they can be allocated and re-used.
The sanitization is done by going through EPC address space and applying the
EREMOVE function to each physical page. Some enclave pages like SECS pages have
hardware dependencies on other pages which prevents EREMOVE from functioning.
Executing two EREMOVE passes removes the dependencies.
Page reclaimer
--------------
Similar to the core kswapd, ksgxd, is responsible for managing the
overcommitment of enclave memory. If the system runs out of enclave memory,
*ksgxd* “swaps” enclave memory to normal memory.
Launch Control
==============
SGX provides a launch control mechanism. After all enclave pages have been
copied, kernel executes EINIT function, which initializes the enclave. Only after
this the CPU can execute inside the enclave.
EINIT function takes an RSA-3072 signature of the enclave measurement. The function
checks that the measurement is correct and signature is signed with the key
hashed to the four **IA32_SGXLEPUBKEYHASH{0, 1, 2, 3}** MSRs representing the
SHA256 of a public key.
Those MSRs can be configured by the BIOS to be either readable or writable.
Linux supports only writable configuration in order to give full control to the
kernel on launch control policy. Before calling EINIT function, the driver sets
the MSRs to match the enclave's signing key.
Encryption engines
==================
In order to conceal the enclave data while it is out of the CPU package, the
memory controller has an encryption engine to transparently encrypt and decrypt
enclave memory.
In CPUs prior to Ice Lake, the Memory Encryption Engine (MEE) is used to
encrypt pages leaving the CPU caches. MEE uses a n-ary Merkle tree with root in
SRAM to maintain integrity of the encrypted data. This provides integrity and
anti-replay protection but does not scale to large memory sizes because the time
required to update the Merkle tree grows logarithmically in relation to the
memory size.
CPUs starting from Icelake use Total Memory Encryption (TME) in the place of
MEE. TME-based SGX implementations do not have an integrity Merkle tree, which
means integrity and replay-attacks are not mitigated. B, it includes
additional changes to prevent cipher text from being returned and SW memory
aliases from being created.
DMA to enclave memory is blocked by range registers on both MEE and TME systems
(SDM section 41.10).
Usage Models
============
Shared Library
--------------
Sensitive data and the code that acts on it is partitioned from the application
into a separate library. The library is then linked as a DSO which can be loaded
into an enclave. The application can then make individual function calls into
the enclave through special SGX instructions. A run-time within the enclave is
configured to marshal function parameters into and out of the enclave and to
call the correct library function.
Application Container
---------------------
An application may be loaded into a container enclave which is specially
configured with a library OS and run-time which permits the application to run.
The enclave run-time and library OS work together to execute the application
when a thread enters the enclave.
Impact of Potential Kernel SGX Bugs
===================================
EPC leaks
---------
When EPC page leaks happen, a WARNING like this is shown in dmesg:
"EREMOVE returned ... and an EPC page was leaked. SGX may become unusable..."
This is effectively a kernel use-after-free of an EPC page, and due
to the way SGX works, the bug is detected at freeing. Rather than
adding the page back to the pool of available EPC pages, the kernel
intentionally leaks the page to avoid additional errors in the future.
When this happens, the kernel will likely soon leak more EPC pages, and
SGX will likely become unusable because the memory available to SGX is
limited. However, while this may be fatal to SGX, the rest of the kernel
is unlikely to be impacted and should continue to work.
As a result, when this happens, user should stop running any new
SGX workloads, (or just any new workloads), and migrate all valuable
workloads. Although a machine reboot can recover all EPC memory, the bug
should be reported to Linux developers.
Virtual EPC
===========
The implementation has also a virtual EPC driver to support SGX enclaves
in guests. Unlike the SGX driver, an EPC page allocated by the virtual
EPC driver doesn't have a specific enclave associated with it. This is
because KVM doesn't track how a guest uses EPC pages.
As a result, the SGX core page reclaimer doesn't support reclaiming EPC
pages allocated to KVM guests through the virtual EPC driver. If the
user wants to deploy SGX applications both on the host and in guests
on the same machine, the user should reserve enough EPC (by taking out
total virtual EPC size of all SGX VMs from the physical EPC size) for
host SGX applications so they can run with acceptable performance.
Architectural behavior is to restore all EPC pages to an uninitialized
state also after a guest reboot. Because this state can be reached only
through the privileged ``ENCLS[EREMOVE]`` instruction, ``/dev/sgx_vepc``
provides the ``SGX_IOC_VEPC_REMOVE_ALL`` ioctl to execute the instruction
on all pages in the virtual EPC.
``EREMOVE`` can fail for three reasons. Userspace must pay attention
to expected failures and handle them as follows:
1. Page removal will always fail when any thread is running in the
enclave to which the page belongs. In this case the ioctl will
return ``EBUSY`` independent of whether it has successfully removed
some pages; userspace can avoid these failures by preventing execution
of any vcpu which maps the virtual EPC.
2. Page removal will cause a general protection fault if two calls to
``EREMOVE`` happen concurrently for pages that refer to the same
"SECS" metadata pages. This can happen if there are concurrent
invocations to ``SGX_IOC_VEPC_REMOVE_ALL``, or if a ``/dev/sgx_vepc``
file descriptor in the guest is closed at the same time as
``SGX_IOC_VEPC_REMOVE_ALL``; it will also be reported as ``EBUSY``.
This can be avoided in userspace by serializing calls to the ioctl()
and to close(), but in general it should not be a problem.
3. Finally, page removal will fail for SECS metadata pages which still
have child pages. Child pages can be removed by executing
``SGX_IOC_VEPC_REMOVE_ALL`` on all ``/dev/sgx_vepc`` file descriptors
mapped into the guest. This means that the ioctl() must be called
twice: an initial set of calls to remove child pages and a subsequent
set of calls to remove SECS pages. The second set of calls is only
required for those mappings that returned a nonzero value from the
first call. It indicates a bug in the kernel or the userspace client
if any of the second round of ``SGX_IOC_VEPC_REMOVE_ALL`` calls has
a return code other than 0.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
SGX enclave 개요와 지원 확인
1-33이 문서는 `SPDX-License-Identifier: GPL-2.0`으로 배포됩니다. Software Guard eXtensions(SGX) hardware는 userspace application이 code와 data를 위한 private memory region을 따로 마련할 수 있게 합니다.
- privileged ring-0 `ENCLS` function이 region 구성을 지휘합니다.
- unprivileged ring-3 `ENCLU` function이 application의 region 진입과 내부 실행을 허용합니다.
이 memory region을 enclave라고 합니다. enclave는 고정된 entry point 집합으로만 진입할 수 있으며 entry point마다 hardware thread 하나만 동시에 머물 수 있습니다.
enclave는 일반 binary file에서 `ENCLS` function으로 load되지만 enclave 안의 thread만 그 memory에 access할 수 있습니다. CPU가 외부 access를 차단하고 LLC 밖으로 나가기 전에 memory를 encrypt합니다.
SGX 지원은 다음 명령으로 확인합니다.
``grep sgx /proc/cpuinfo``
processor가 SGX를 지원하고 BIOS에서도 활성화해야 합니다. hardware 지원 system에서 SGX가 보이지 않으면 BIOS 설정을 확인하십시오. BIOS가 `Enabled`와 `Software Enabled`를 제시하면 `Enabled`를 선택합니다.
EPC page type과 EPCM
34-83SGX는 enclave와 연결된 page를 Enclave Page Cache(EPC)에 저장합니다. EPC는 BIOS가 예약한 physical memory region에 있습니다. 일반 memory page와 달리 enclave 구성 중 special·limited SGX instruction을 사용할 때만 enclave 밖에서 access할 수 있습니다.
enclave 내부를 실행하는 CPU만 enclave memory에 직접 access할 수 있지만, enclave 내부 CPU는 enclave 밖의 normal memory에도 access할 수 있습니다. kernel은 enclave memory를 device memory와 비슷하게 관리합니다.
| page type | 역할 |
|---|---|
| SGX Enclave Control Structure(`SECS`) | enclave address range, attribute와 기타 global data를 정의합니다. |
| Regular(`REG`) | enclave의 code와 data를 담습니다. |
| Thread Control Structure(`TCS`) | enclave entry point를 정의하고 enclave thread execution state를 추적합니다. |
| Version Array(`VA`) | EPC에서 evict된 page의 version number를 담을 수 있는 slot 512개를 제공합니다. |
processor는 Enclave Page Cache Map(EPCM)이라는 hardware metadata structure로 EPC page를 추적합니다. EPC page마다 owning enclave, access right, page type 등을 설명하는 entry가 있습니다.
EPCM permission은 normal page table과 별개입니다. 예를 들어 enclave가 read-only로 유지하려는 data에 kernel이 write를 허용하지 못하게 합니다. EPCM permission은 normal x86 page permission에 추가 제한만 부과할 수 있습니다.
SGX architecture에서 processor는 언제든 모든 EPCM entry를 invalidate할 수 있으므로 software는 언제든 EPCM fault를 처리할 준비가 되어야 합니다. 실제로 enclave memory를 encrypt하는 ephemeral key가 사라지는 power transition 같은 event에서 발생할 수 있습니다.
enclave build와 SGX2 runtime 관리
84-117전통적인 compiler·linker 과정과 별도로 SGX에는 enclave build 과정이 있습니다. enclave는 실행, 즉 진입 전에 build해야 합니다. 첫 단계는 `/dev/sgx_enclave` device를 여는 것입니다. enclave memory에는 직접 access할 수 없으므로 special privileged instruction으로 data를 enclave page에 복사하고 page permission을 설정합니다.
`arch/x86/kernel/cpu/sgx/ioctl.c`의 kernel-doc가 다음 build function을 설명합니다.
- `sgx_ioc_enclave_create`
- `sgx_ioc_enclave_add_pages`
- `sgx_ioc_enclave_init`
- `sgx_ioc_enclave_provision`
SGX2 system은 initialized enclave의 page permission과 type 변경, page의 동적 추가·삭제도 지원합니다. enclave address range 안에서 backing page가 없는 address에 access하면 새 regular page가 동적으로 추가됩니다. 사용하려면 enclave가 새 page에서 `EACCEPT`를 실행해야 합니다.
같은 source file의 kernel-doc가 runtime function `sgx_ioc_enclave_restrict_permissions`, `sgx_ioc_enclave_modify_types`, `sgx_ioc_enclave_remove_pages`를 설명합니다.
enclave vDSO와 exception fixup
118-140enclave 진입은 SGX 전용 `EENTER`와 `ERESUME` function으로만 가능하며 과정이 복잡합니다. 그래서 enclave는 일반적으로 library를 사용해 실제 transition을 처리합니다. application이 system call을 감싸기 위해 glibc 구현을 사용하는 것과 비슷합니다.
enclave는 정상 동작 중에도 enclave 내부에서 처리해야 하거나 SGX에 고유한 exception을 만들 수 있습니다.
전통적인 signal mechanism 대신 SGX는 vDSO가 제공하는 special exception fixup을 활용할 수 있습니다. kernel 제공 vDSO function은 `EENTER`·`ERESUME` 같은 low-level transition을 감싸고, signal을 만들 exception을 가로채 fault 정보를 caller에게 직접 반환합니다. signal handler를 복잡하게 다룰 필요가 없습니다.
`arch/x86/include/uapi/asm/sgx.h`의 kernel-doc가 `vdso_sgx_enter_enclave_t`를 설명합니다.
ksgxd의 EPC sanitization과 reclaim
141-166SGX 지원에는 `ksgxd`라는 kernel thread가 포함됩니다.
`ksgxd`는 SGX 초기화 때 시작됩니다. processor power-on 또는 reset 직후에는 보통 enclave memory를 사용할 준비가 되어 있지만, reset 뒤 SGX를 사용한 적이 있으면 crash와 `kexec()` cycle 등으로 enclave page가 일관되지 않은 상태일 수 있습니다. boot 때 `ksgxd`가 모든 enclave page를 재초기화해 다시 allocate하고 사용할 수 있게 합니다.
EPC address space를 순회하며 physical page마다 `EREMOVE`를 적용해 sanitize합니다. SECS page처럼 다른 page와 hardware dependency가 있는 page에서는 `EREMOVE`가 동작하지 않을 수 있으므로 두 번 통과해 dependency를 제거합니다.
core `kswapd`와 비슷하게 `ksgxd`는 enclave memory overcommit을 관리합니다. system에서 enclave memory가 부족해지면 enclave memory를 normal memory로 swap합니다.
launch control과 memory encryption
167-206모든 enclave page를 복사한 뒤 kernel은 enclave를 initialize하는 `EINIT`을 실행합니다. 그 뒤에야 CPU가 enclave 내부에서 실행할 수 있습니다.
`EINIT`은 enclave measurement의 RSA-3072 signature를 받습니다. measurement가 올바르고 signature가 public key의 SHA256을 나타내는 네 `IA32_SGXLEPUBKEYHASH{0, 1, 2, 3}` MSR에 hash된 key로 signed되었는지 확인합니다.
BIOS는 이 MSR을 readable 또는 writable로 설정할 수 있습니다. Linux는 launch-control policy를 kernel이 완전히 제어하도록 writable configuration만 지원합니다. driver는 `EINIT` 전에 MSR을 enclave signing key에 맞춥니다.
CPU package 밖에서 enclave data를 감추기 위해 memory controller의 encryption engine이 enclave memory를 투명하게 encrypt·decrypt합니다.
Ice Lake 이전 CPU는 cache 밖으로 나가는 page를 Memory Encryption Engine(MEE)으로 encrypt합니다. MEE는 SRAM에 root가 있는 n-ary Merkle tree로 encrypted data의 integrity를 유지합니다. integrity와 anti-replay protection을 제공하지만 memory size에 따라 tree update 시간이 logarithmic하게 늘어 큰 memory로 확장하기 어렵습니다.
Icelake 이후 CPU는 MEE 대신 Total Memory Encryption(TME)을 사용합니다. TME 기반 SGX에는 integrity Merkle tree가 없어 integrity와 replay attack을 완화하지 못합니다. 대신 cipher text 반환과 software memory alias 생성을 막는 추가 변경이 포함됩니다.
MEE와 TME system 모두 range register로 enclave memory에 대한 DMA를 차단합니다. SDM section 41.10을 참고하십시오.
SGX usage model
207-227Shared Library model에서는 sensitive data와 이를 처리하는 code를 application에서 별도 library로 분리합니다. library를 DSO로 link해 enclave에 load하고, application이 special SGX instruction으로 enclave 내부 function을 개별 호출합니다. enclave runtime이 parameter를 marshal하고 올바른 library function을 호출합니다.
Application Container model에서는 application을 library OS와 runtime으로 특별히 구성한 container enclave에 load합니다. thread가 enclave에 들어오면 enclave runtime과 library OS가 함께 application을 실행합니다.
kernel SGX bug가 만드는 EPC leak
228-253EPC page leak이 발생하면 dmesg에 다음과 같은 WARNING이 표시됩니다.
`EREMOVE returned ... and an EPC page was leaked. SGX may become unusable...`
이는 사실상 EPC page에 대한 kernel use-after-free이며 SGX 동작 방식 때문에 free 시점에 bug가 발견됩니다. kernel은 page를 available EPC pool에 되돌리지 않고 향후 추가 오류를 막기 위해 의도적으로 leak시킵니다.
이후 EPC page가 더 많이 leak될 가능성이 높고 SGX memory가 제한되어 있으므로 SGX를 사용하지 못하게 될 수 있습니다. SGX에는 치명적일 수 있지만 나머지 kernel에는 영향이 적어 계속 동작할 가능성이 높습니다.
이 상황이 발생하면 새 SGX workload, 또는 모든 새 workload 실행을 중단하고 가치 있는 workload를 migration해야 합니다. reboot하면 EPC memory 전체를 복구할 수 있지만 bug는 Linux developer에게 보고해야 합니다.
guest용 virtual EPC와 전체 제거 ioctl
254-302구현에는 guest의 SGX enclave를 지원하는 virtual EPC driver도 있습니다. SGX driver와 달리 virtual EPC driver가 allocate한 EPC page에는 특정 enclave가 연결되지 않습니다. KVM이 guest의 EPC page 사용 방식을 추적하지 않기 때문입니다.
따라서 SGX core page reclaimer는 virtual EPC driver를 통해 KVM guest에 allocate된 EPC page를 reclaim하지 않습니다. 같은 machine의 host와 guest에서 SGX application을 함께 배포하려면 physical EPC size에서 모든 SGX VM의 total virtual EPC size를 뺀 만큼을 host용으로 예약해 허용 가능한 성능을 확보해야 합니다.
guest reboot 뒤에도 모든 EPC page를 uninitialized state로 복원하는 것이 architectural behavior입니다. 이 state는 privileged `ENCLS[EREMOVE]`로만 만들 수 있으므로 `/dev/sgx_vepc`는 모든 virtual EPC page에 instruction을 실행하는 `SGX_IOC_VEPC_REMOVE_ALL` ioctl을 제공합니다.
`EREMOVE`는 세 가지 이유로 실패할 수 있으며 userspace는 다음처럼 처리해야 합니다.
- page가 속한 enclave에서 thread가 실행 중이면 제거는 항상 실패합니다. 일부 page를 이미 제거했더라도 ioctl은 `EBUSY`를 반환합니다. virtual EPC를 mapping한 vcpu 실행을 막아 피할 수 있습니다.
- 같은 SECS metadata page를 참조하는 page에 두 `EREMOVE` call이 동시에 실행되면 general protection fault가 발생하고 `EBUSY`로 보고됩니다. `SGX_IOC_VEPC_REMOVE_ALL` 동시 호출이나 guest의 `/dev/sgx_vepc` file descriptor close와 ioctl이 겹칠 때 발생할 수 있습니다. ioctl과 `close()`를 serialize해 피할 수 있습니다.
- child page가 남은 SECS metadata page는 제거에 실패합니다. guest에 mapping된 모든 `/dev/sgx_vepc` file descriptor에서 `SGX_IOC_VEPC_REMOVE_ALL`을 실행해 child page를 제거해야 합니다. 첫 호출에서 nonzero를 반환한 mapping에 두 번째 호출을 수행해 SECS page를 제거합니다. 두 번째 round의 return code가 0이 아니면 kernel 또는 userspace client bug입니다.
요약과 해설
sgx.rst:1-302SGX는 CPU가 외부 access를 차단하고 cache 밖에서 encrypt하는 EPC에 enclave code와 data를 둡니다. `/dev/sgx_enclave` ioctl로 build하고 vDSO wrapper로 `EENTER`·`ERESUME` 및 exception fixup을 처리합니다.
`ksgxd`는 EPC를 sanitize하고 overcommit을 reclaim합니다. guest virtual EPC는 reclaim 대상이 아니며 reboot 복원을 위해 `/dev/sgx_vepc`의 `SGX_IOC_VEPC_REMOVE_ALL`을 dependency 순서에 맞춰 호출해야 합니다.