1. ECREATE
Developing an SGX-enabled application is made really easy thanks to the provided SDK. However, there remain some issues with the current iteration of Intel SGX. Being prone to side-channel attacks sadly limits the security offered by the platform, forcing developers to proactively ensure that their programs cannot be attacked. Software Guard Extensions SDK for Windows. in the Apps and FeaturesPrograms and Features list. Uninstall/Update To uninstall/update the Intel® Software Guard Extensions SDK, run Intel(R) SGXWindowsSDK.exe, and select one of the following options listed on the welcome page: 1. Modify – Change installed features or feature. These VMs run on Intel processors with Software Guard Extension (Intel SGX). Intel SGX is the component that allows the increased protection that we light up with confidential computing. Today, Azure offers the DCsv2-Series built on Intel SGX technology for hardware-based enclave creation. You can build secure enclave-based applications to run.
- [Intel SGX Explained p63] Section 5.3.1. Creation
- [Programming References p21] Section 5.3. ECREATE
An enclave is born when the system software issues the ECREATE
instruction, which turns a free EPC page into the SECS for the new enclave.
ECREATE
copies an SECS structure outside the EPC into an SECS page inside the EPC. The internal structure of SECS is not accessible to software.
Software sets the following fields in the source structure: SECS:BASEADDR
, SECS:SIZE
, and ATTRIBUTES
.
ECREATE
validates the information used to initialize the SECS, and results in a page fault (#PF) or general protection fault (#PF) if the information is not valid.ECREATE
will also fault if SECS target page is in use; already valid; outside the EPC; adresses are not aligned; unused PAGEINFO fields are not zero.
2. EADD
- [Intel SGX Explained p64] Section 5.3.2. Loading
- [Programming References p11] Section 5.3. EADD
The system software can use EADD
instructions to load the initial code and data into the enclave. EADD
is used to create both TCS pages and regular pages.
This function copies a source page from non-enclave memory into the EPC, associates the EPC page with an SECS page residing in the EPC, and stores the linear address and security attributes in EPCM.
EADD
reads its input data from a Page Information (PAGEINFO) structure.
The PAGEINFO structure contains
- The virtual address of the EPC page (
LINADDR
) - The virtual address of the non-EPC page whose contents will be copied into the newly allocated EPC page (
SRCPGE
) - A virtual address that resolves to the SECS of the enclave that will own the page (
SECS
). - The virtual address, pointing to a Security Information (SECINFO) structure, which contains the newly allocated EPC page’s access permissions (R, W, X) and its EPCM page type (
RT_REG
orPT_TCS
).
{: .center-image}
EADD
validates its inputs, and modifies the newly allocated EPC page and its EPCM entry.
EADD
ensures
- The EPC page is not allocated to another enclave.
- The page’s virtual address falls within the enclave’s ELRANGE.
- All the reserved fields in SECINFO are set to zero.
2-1. How a free EPC page is selected in SGX simulation mode?
Simulation implementation might be different from hardware implementation. In simulation mode, ECREATE
allocates all EPC pages via mmap()
.
As SGX simulation simulates SGX behavior by software, it copies EPC page data with virtual address. Hence _EADD()
does not have detailed information about picking a physical EPC page.
2.2. How system software selects a EPC page in SGX hardware mode?
SGX simulation code can’t tell EPC page allocation in detail, as it is also a software, so it cannot use the physical address.
To understand actual implementation, I first tried to understand Intel SGX Programming Reference deeply. There is a table explaining inputs for the instruction.
Table. Instruction Operand Encoding{: .center}
Op/En | EAX | RBX | RCX |
---|---|---|---|
IR | EADD (in) | Address of PAGEINFO (in) | Address of the destination EPC page (in) |
As you see the above table, addresses of PAGEINFO and target EPC page should be saved in the register RBX
and RCX
, respectively. The target EPC page is already determined, which means system software is responsible for selecting one. This is also explained in ISCA ‘15 tutorial slide. [link]
{: .center-image width=“600px”}
Then this means I need to search a code that calls EADD
instruction.
Simulation function which calls EADD
instruction is add_enclave_page()
in sdk/simulation/driver_api/driver_api.cpp
. This is a simulation code because it is in simulation
directory.
Then there should be a function with the same name for hardware?
And yes. There is.
Note that PSW (Platform SoftWare) is for actual hardware. It calls ioctl()
, which calls sgx_ioctl_enclave_add_page()
in linux-sgx-driver. linux-sgx-driver is separately provided in [here].
In linux-sgx-driver/isgx_ioctl.c
,
ioctl()
from enclave_creator_hw.cpp
- calls
isgx_ioctl_enclave_add_page()
atlinux-sgx-driver/isgx_ioctl.c:548
- calls
__enclave_add_page()
atlinux-sgx-driver/isgx_ioctl.c:440
- calls
construct_enclave_page
atlinux-sgx-driver/isgx_ioctl.c:122
- calls
isgx_alloc_epc_page()
atlinux-sgx-driver/isgx_page_cache.c:429
- calls
isgx_alloc_epc_page_fast()
atlinux-sgx-driver/isgx_page_cache.c:411
which picks the first entry from driver’s EPC page list.
isgx Linux SGX driver manages EPC page instances by using the linked list(static LIST_HEAD(isgx_free_list)
at isgx_page_cache.c:25
) and the number of free EPC pages(unsigned int isgx_nr_free_epc_pages
at isgx_page_cache.c:31
).
The type of EPC pages is struct isgx_epc_page
, defined as follows.
Is There An Sgx Sdk
Here, pa
is the physical address for the EPC page. How pa
is determined?
Each EPC page that is put into free list is allocated in the function isgx_page_cache_init()
at linux-sgx-driver/isgx_page_cache.c:360
.
Each EPC page has the physical address as start + i
. start
is the first parameter of the function.
The function isgx_page_cache_init()
is called in isgx_init()
at linux-sgx-driver/isgx_main.c:190
.
As shown above, start
is the value of isgx_epc_base
variable.isgx_epc_base
is initialized by the function isgx_init_platform()
at linux-sgx-driver/isgx_main.c:133
.
You can see what isgx_epc_base
value is in your machine, as SGX driver prints it in kernel message buffer by default.
{: .center-image}
My machine tells that 32MiB of EPC is allocated with the physical base memory address 0x80000000
.
All EPC page instance struct isgx_epc_page
has a pa
variable, which contains the physical address of the EPC page, and is initialized as EPC base address + offset.
And, managing page mapping table is also a responsibility of system software. Linux SGX driver insert PTE via calling vm_insert_pfn()
at linux-sgx-driver/isgx_util.c:67
by using epc_page->pa
and expected virtual address enclave_page->addr
as follows.
To be concluded, when a SGX platform is initialized, several EPC page instances (struct isgx_epc_page
) are allocated to represent all EPC pages. System software manages them as a linked list, called isgx_free_list
. When EADD
is called, system software picks a free EPC page instance from the list, and create a page table entry, pointing the physical address that is saved in epc_page->pa
, with the expected virtual address enclave_page->addr
, a part of user enclave’s ELRANGE.
3. EEXTEND
- [Intel SGX Explained p64] Section 5.3.2. Loading
- [Programming References p31] Section 5.3. EEXTEND
While loading an enclave, the system software will also use the EEXTEND
instruction, which updates the enclave’s measurement used in the software attestation process.
It updates the MRENCLAVE measurement register of an SECS with the measurement of an EXTEND string compromising of “EEXTEND” || ENCLAVEOFFSET || PADDING || 256 bytes of the enclave page.
RCX register contains the effective address of the 256 byte region of an EPC page to be measured.
From Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3D, Part 4:Section 39.1.2. EADD and EEXTEND Interaction
Software can measure a 256 byte region as determined by the by the developer by invoking EEXTEND. Thus to measure an entire 4KB page, system software must execute EEXTEND 16 times. Each invocation of EEXTEND adds to the cryptographic log information about which region is being measured and the measurement of the section.
4. EINIT
- [Intel SGX Explained p64] Section 5.3.3. Initialization
- [Programming References p34] Section 5.3. EINIT
This function is the final instruction executed in the enclave build process. After EINIT, the MRENCLAVE measurement is cimplete, and the enclave is ready to start user code execution using EENTER instruction.
When EINIT
completes successfully, it sets the enclave’s INIT attribute to true. This opens the way for ring 3 application software to execute the enclave’s code, using the SGX instructions.
On the other hand, once INIT is set to true, EADD
cannot be invoked on that enclave anymore, so the system software must load all the pages that make up the enclave’s initial state before executing the EINIT
instruction.
References
- Intel Software Guard Extensions Programming Reference. [link]
- Intel SGX Explained. [link]
- Intel SGX Tutorial Slide presented in ISCA 2015.[link]
- Intel SGX SDK Github Repository. [link]
- Intel SGX Linux Driver Github Repository.[link]
License
All source codes are from Intel SGX SDK Github repository and Intel SGX Linux driver Github repository, released under BSD License 2.0 and GNU General Public License 2.0, respectively.
Intel SGX SDK
Copyright (C) 2011-2017 Intel Corporation. All rights reserved.
Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. - Neither the name of the
nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” ANDANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AREDISCLAIMED. IN NO EVENT SHALL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Part 7 of the Intel® Software Guard Extensions (Intel® SGX) tutorial series revisits the enclave interface and adds a small refinement to make it simpler and more efficient. We’ll discuss how the proxy functions marshal data between unprotected memory space and the enclave, and we’ll also discuss one of the advanced features of the Enclave Definition Language (EDL) syntax. You can find a list of all of the published tutorials in the article Introducing the Intel® Software Guard Extensions Tutorial Series. Source code is provided with this installment of the series. With this release we have migrated the application to the 1.7 release of the Intel SGX SDK and also moved our development environment to Microsoft Visual Studio* Professional 2015. When building an enclave using the Intel SGX SDK you define the interface to the enclave in the EDL. The EDL specifies which functions are ECALLs (“enclave calls,” the functions that enter the enclave) and which ones are OCALLs (“outside calls,” the calls to untrusted functions from within the enclave). When the project is built, the Edger8r tool that is included with the Intel SGX SDK parses the EDL file and generates a series of proxy functions. These proxy functions are essentially wrappers around the real functions that are prototyped in the EDL. Each ECALL and OCALL gets a pair of proxy functions: a trusted half and an untrusted half. The trusted functions go into EnclaveProject_t.h and EnclaveProjct_t.c and are included in the Autogenerated Files folder of your enclave project. The untrusted proxies go into EnclaveProject_u.h and EnclaveProject_u.c and are placed in the Autogenerated Files folder of the project that will be interfacing with your enclave. Your program does not call the ECALL and OCALL functions directly; it calls the proxy functions. When you make an ECALL, you call the untrusted proxy function for the ECALL, which in turn calls the trusted proxy function inside the enclave. That proxy then calls the “real” ECALL and the return value propagates back to the untrusted function. This sequence is shown in Figure 1. When you make an OCALL, the sequence is reversed: you call the trusted proxy function for the OCALL, which calls an untrusted proxy function outside the enclave that, in turn, invokes the “real” OCALL. The proxy functions are responsible for: Note that this means that each ECALL or OCALL has potentially two return values. There’s the success of the ECALL or OCALL itself, meaning, were we able to successfully enter or exit the enclave, and then the return value of the function being called in the ECALL or OCALL. The EDL syntax for the ECALL functions ve_lock() and ve_unlock() in our Tutorial Password Manager’s enclave is shown below: And here are the untrusted proxy function prototypes that are generated by the Edger8r tool: Note the additional arguments that have been added to the parameter list for each function and that the functions now return a type of sgx_status_t. Both proxy functions need the enclave identifier, which is passed in the first parameter, eid. The ve_lock() function has no parameters and does not return a value so no further changes are necessary. The ve_unlock() function, however, does both. The second argument to the proxy function is a pointer to an address that will store the return value from the real ve_unlock() function in the enclave, in this case a return value of type int. The actual function parameter, char *password, is included after that. The untrusted portion of an application does not have access to enclave memory. It cannot read from or write to these protected memory pages. This presents some difficulties when the function parameters include pointers. OCALLs are especially problematic, because a memory allocated inside the enclave is not accessible to the OCALL, but even ECALLs can have issues. Enclave memory is mapped into the application’s memory space, so enclave pages can be adjacent to unprotected memory pages. If you pass a pointer to untrusted memory into an enclave, and then fail to do appropriate bounds checking in your enclave, you may inadvertently cross the enclave boundary when reading or writing to that memory in your ECALL. The Intel SGX SDK’s solution to this problem is to copy the contents of data buffers into and out of enclaves, and have the ECALLs and OCALLs operate on these copies of the original memory buffer. When you pass a pointer into an enclave, you specify in the EDL whether the buffer referenced by the pointer is being pass into the call, out of the call, or in both directions, and then you specify the size of the buffer. The proxy functions generated by the Edger8r tool use this information to check that the address range does not cross the enclave boundary, copy the data into or out of the enclave as indicated, and then substitute a pointer to the copy of the buffer in place of the original pointer. This is the slow-and-safe approach to marshaling data and pointers between unprotected memory and enclave memory. However, this approach has drawbacks that may make it undesirable in some cases: There are also cases where you just need to pass a raw pointer into an ECALL and out to an OCALL without it ever being used inside the enclave, such as when passing a function pointer for a callback function straight through to an OCALL. In this case, there is no data buffer per se, just the pointer address itself, and the marshaling functions generated by Edger8r actually get in the way. Fortunately, the EDL language does support passing a raw pointer address into an ECALL or an OCALL, skipping both the boundary checks and the data buffer copy. The A pointer marked with the In the Tutorial Password Manager, the most appropriate place to use the The original EDL for ve_load_vault() and ve_get_vault() looks like this: Rewriting these to specify Notice that we were able to drop the len parameter from ve_load_vault(). As you might recall from Part 4, the issue we had with this function was that although the length of the vault is stored as a variable in the enclave, the proxy functions don’t have access to it. In order for the ECALL’s proxy functions to copy the incoming data buffer, we had to supply the length in the EDL so that the Edger8r tool would know the size of the buffer. With the However, we still send the length as a parameter to ve_get_vault(). This is a safety check to ensure that we don’t accidentally overflow a buffer when fetching the encrypted vault from the enclave. The EDL provides three options for passing pointers into an ECALL or an OCALL: Table 1. Pointer specifiers and their meanings in ECALLs and OCALLs. If you use the direction indicators, the data buffer referenced by your pointer gets copied and you must supply a count so that the Edger8r can determine how many bytes are in the buffer. If you specify The code sample for this part of the series has been updated to build against the Intel SGX SDK version 1.7 using Microsoft Visual Studio 2015. It should still work with the Intel SGX SDK version 1.6 and Visual Studio 2013, but we encourage you to update to the newer release of the Intel SGX SDK. In Part 8 of the series, we’ll integrate the GUI with our application. Stay tuned!The Proxy Functions
Figure 1. Proxy functions for an ECALL.Data Marshaling
Is There An Sgx Sdk App
The Solution: user_check
user_check
parameter tells the Edger8r tool to pass a pointer as it is and assume that the developer has done the proper bounds checking on the address. When you specify user_check
you are essentially trading safety for performance.user_check
does not have a direction (in
or out
) associated with it, because there is no buffer copy taking place. Mixing user_check
with in
or out
will result in an error at compile time. Similarly, you don’t supply a count
or size
parameter, either.user_check
parameter is in the ECALLs that load and store the encrypted password vault. While our design constraints put a practical limit on the size of the vault itself, generally speaking these sorts of bulk reads and writes benefit from allowing the enclave to directly operate on untrusted memory.user_check
results in the following:user_check
option, there is no buffer copy operation, so this problem goes away. The enclave can read directly from untrusted memory, and it can use its internal variable to determine how many bytes to read.Is There An Sgx Sdk Download
Summary
in
, out
, and user_check
. These options are summarized in Table 1.Specifier/Direction ECALL OCALL in The buffer is copied from the application into the enclave. Changes will only affect the buffer inside the enclave. The buffer is copied from the enclave to the application. Changes will only affect the buffer outside the enclave. out A buffer will be allocated inside the enclave and initialized with zeros. It will be copied to the original buffer when the ECALL exits. A buffer will be allocated outside the enclave and initialized with zeros. This untrusted buffer will be copied to the original buffer in the enclave when the OCALL exits. in, out Data is copied back and forth. Data is copied back and forth. user_check The pointer is not checked. The raw address is passed. The pointer is not checked. The raw address is passed. user_check
, the raw pointer is passed to the ECALL or OCALL unaltered.Sample Code
Coming Up Next