- Use the same mechanism (debug_map) in Pal/Linux and Pal/Linux-SGX.
Previously, Pal/Linux emulated the _r_debug structure, normally
maintained by ld.so, but that cannot be done in SGX outer PAL,
because it's loaded by ld.so already.
- Maintain the debug maps outside of SGX enclave. This allows
initializing them before enclave start, and potentially makes
them easier to use.
- Initialize PAL debug map before enclave start. Previously, this
was done from inside the enclave, so you couldn't set a
breakpoint too early (e.g. in pal_linux_main).
- Store only load address, without list of sections. This is to
avoid parsing the list of sections just to report them to the
debugger. Unfortunately, the GDB version that we support still
needs these sections, but we can retrieve them in GDB plugin.
- Move Python GDB code related to debug maps to a common file.
GCC (and other compilers, e.g. Clang) provide a stack protector
feature to detect stack corruptions. This is achieved by storing
a 64-bit canary value on the stack frame on function entry and
verifying this value on function exit. Previously, Graphene disabled
stack protector completely. This commit enables it in LibOS and PAL
code (only if `-mstack-protector` feature is supported by compiler).
The stack protector uses a random per-thread canary stored in the
TLS/TCB of each thread. Each PAL implementation must follow the
rule that TLS/TCB is accessed via the GS register and that the offset
of canary in TLS/TCB is 0x8. Since LibOS re-uses TLS/TCB of the PAL,
there is no need for additional enabling at the LibOS layer.
Since `-mstack-protector` feature is architecture-specific, it is
currently enabled only for x86-64 (and above rules on using gs:[0x8]
to access the canary apply only to x86-64).
Co-authored-by: Isaku Yamahata <isaku.yamahata@gmail.com>
The manifest syntax stays exactly the same, including 0 and 1
integers to denote boolean values (this is done for ease of porting
and can be fixed in future commits). The only visible change is
surrounding strings in the manifest with quotes (requirement of
TOML). All manifests and Makefiles of our tests and example apps are
ported to the new TOML syntax. Documentation is updated.
This library will be used to parse Graphene manifest files written
in TOML syntax. We patch the library slightly to remove unsupported
toml_parse_file() and toml_rtod(), as well as errno() handling.
Protected files (PF) are a new type of file that can be specified in
the manifest (SGX only). They are encrypted on disk and transparently
decrypted when accessed by the Graphene payload.
Other features:
- data is integrity protected (tamper resistance)
- file swap protection (a PF can only be accessed when in a specific path)
- transparency (Graphene payload sees PFs as regular files, no need to modify
the payload)
See Linux-SGX/protected-files directory for implementation. PF format is
based on protected files from the SGX SDK:
https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs
The following new manifest elements are added:
sgx.protected_files_key = <16-byte hex value>
sgx.protected_files.<name> = file:<host path>
sgx.protected_files_key specifies the encryption key and is only a temporary
implementation. This key should be provisioned with local/remote attestation
in the future.
Paths specifying PF entries can be files or directories. If a directory is
specified, all files/directories within are registered as protected
recursively (and are expected to be encrypted in the PF format).
Linux-SGX/tools directory contains the pf_crypt utility that converts files
to/from the protected format.
Graphene used its own implementations of memory-handling functions like
memcmp(), memcpy(), etc. These implementations were copied from Glibc
and contained complicated code from year 2004. Modern HW and compilers
do better job at optimizing simple C implementations of these functions.
Thus, this commit replaces old implementations with simple ones taken
from Musl libc and adapted to our code style.
One particular optimization is made to memcpy() on x86-64. memcpy() is
heavily used in Linux-SGX PAL to copy data in/out of SGX enclave.
Experiments with Redis 5.0 show perf improvement of using "rep movsb" at
3-5% for 4KB payloads over the previous implementation based on Glibc.
Although scripts/config.pl has a sane shebang `/usr/bin/env perl`,
we don't provide `/usr/bin/env` in the [nix](https://nixos.org) sandbox.
For other platforms this patch is not necessary; however, it should not
break anything.
Move the Linux x86_64 specific syscall arch_prctrl into a new inline function
pal_set_tcb located in include/arch/x86_64/Linux/pal_host-arch.h. The SGX and
Skeleton builds now also need a pal_host-arch.h file, empty for now.
Previously, Linux-SGX PAL did not encrypt pipe/socketpair
communication (only process checkpoint send/receive was encrypted).
This commit encrypts all pipe/socketpair IPC between threads of
the same enclave and between enclave processes. In particular, all
offsprings of the "first" enclave inherit the same master key and
derive IPC session keys from this master key based on pipe name.
When two pipe/socketpair endpoints are first created, they establish
a TLS-PSK session via intra-enclave handshake (requires a spawn of
an intermediate enclave thread). During clone/fork/exec, endpoints'
TLS contexts are serialized and sent to the child that deserializes
them (using mbedtls_ssl_context_{save,load} functions).
Note that multicast pipes (with more than two communicating entities)
are not supported since TLS protocol doesn't support it.
This commit modifies the PAL `SendHandle` test to correctly test
pipe communication, as well as adds the LibOS `pipe` test.
The DCAP SGX driver works with Flexible Launch Control (FLC) enabled
SGX processors. The FLC feature allows to use arbitrary non-Intel
Launch Enclaves and thus makes the EINITTOKEN struct unnecessary.
This commit skips the step of obtaining the EINITTOKEN struct from
the Launch enclave and instead allows to create a dummy token for
DCAP- and FLC-enabled SGX systems.
Co-authored-by: Dmitrii Kuvaiskii <dmitrii.kuvaiskii@intel.com>
Graphene now moved to mbedTLS version 2.21.0. This new version
decouples the crypto functionality in a separate lib (libmbedcrypto).
This separate lib has its C code and headers under mbedtls/crypto
subdirectory. Previously, we forgot to copy our in-Graphene minimal
config `config.h` into this new subdirectory. This meant that the
crypto lib was built with a default and bloated configuration, not
needed for our Graphene purposes. This commit fixes this.
Previous version of mbedTLS used in Graphene (v2.16.3) is old and
does not have TLS-context serialization functionality. This commit
updates mbedTLS to v2.21.0 (released February 2020); this version
has mbedtls_ssl_session_save() and mbedtls_ssl_session_load() for
TLS context serialization. These functions will be needed for IPC
encryption.
Previously, Graphene with SGX performed self-remote attestation
by retrieving the SGX quote from the Quoting Enclave, sending it
to the Intel Attestation Service via Curl (in an HTTPS request),
and parsing the received from IAS remote-attestation certificate.
This self-attestation functionality is meaningless and is removed.
Moreover, since EPID-based remote attestation requires client key
(Ocp-Apim-Subscription-Key), and this key must be kept secret,
specifying it in the Graphene manifest (as was done previously) is
insecure. Therefore, the whole remote attestation functionality is
moved out of Graphene and to another trusted party (or to the app
on top of Graphene). Only the SGX quote retrieval from the Quoting
Enclave is kept in Graphene.
The current Makefiles are unnecessarily too smart in avoiding
duplication (which is small, I think). As a result, it's hard to
understand what files are listed. Use plain, explicit listing instead.
Also, append .o to objs variables. Usually obj means .o file, not the
base name of file. It was confusing.
Instead of implementing downloading of external resources in every
Makefile again, use one script. This script adds the following
features:
- Always check the download against a known SHA-256 hash.
- Support caching of downloaded resources (set DL_CACHE=/some/dir).
- Allow offline builds if all files are cached. If DL_OFFLINE=true the
build will never attempt to download anything.
Previous commit fixed the dependency on crypto/config.h (it must be
copied into mbedtls include directory). However, config.h with
default and incorrect settings already exists in mbedtls include
dir after its download, and Graphene needs to replace it with our
version of configuration. This commit simply removes default config.h
on first build of mbedTLS to force the dependency introduced in
the previous commit.
Previously, Graphene-SGX did not protect send/recv of checkpoint from
parent to child. This leaked all memory contents of the parent process.
This commit adds TLS-PSK (TLS with Pre-Shared Key) wrapper for process
communication. Graphene-SGX already has the logic for SGX-based local
attestation and generation of the shared key for each parent <-> child
communication channel via Diffie–Hellman key exchange. This commit
uses this pre-shared key to create an mbedTLS-based session based on
UNIX domain socketpair (parent.process.stream <-> child.process.stream).
_DkStreamSecure{Init,Free,Read,Write} internal Linux-SGX PAL functions
are added and used during child process creation and sending of the
parent-generated checkpoint. These functions are backed by crypto-layer
lib_SSL{Init,Free,Read,Write} functions which in turn use mbedTLS.
Configuration of mbedTLS is expanded to support TLS-PSK; note that for
entropy source we use only rdrand instruction inside SGX enclave (i.e.,
no untrusted host-platform sources of entropy). The only ciphersuite
currently supported for IPC is MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256.
This commit adds protection only for checkpoint IPC. After the checkpoint
is sent/received, the parent/child processes downgrade their sockets to
plain non-secure ones (by disabling TLS). This is done because child
may spawn a grandchild that also wants to communicate with grandparent,
but it is impossible for multiple processes to share same TLS context.
Additionally, this commit sanitizes "process" PAL handles during send-
handle checkpoint send (via DkSendHandle): shared key and TLS context
are zeroed out.
Previously, Graphene libraries were built using `wildcard` make function.
The output of this function (list of files) is non-deterministic (list items
can be in any order). This results in different SGX measurements on rebuilds.
In some build environments (e.g., a dedicated Graphene container), it is
important to keep these measurements deterministic. This commit achieves this
by removing wildcards and explicitly specifying required files.
This is the minimalistic implementation of the remote attestation
framework. The framework conducts the following steps during
start-up to verify the authenticity of the SGX platform:
1. Connect to aesmd service to retrieve platform info (targetinfo)
of the Quoting Enclave (QE) before enclave creation.
2. Prepare the SGX report inside enclave (during initialization):
- Read SPID (service provider ID) from sgx.ra_client_spid in
manifest.
- Get an SGX report for local attestation to QE.
- Generate a random 16-byte nonce for freshness.
- Perform an OCALL for retrieving the quote.
3. Gather attestation data (QE report, QE quote, IAS report, signature,
certificate chain) outside of enclave:
- Connect to aesmd to retrieve the QE quote; aesmd also returns
QE report.
- Connect to Intel Attestation Service using curl. A client
subscription key (specified via sgx.ra_client_key in manifest)
is required to authenticate the HTTPS connection.
- Get the IAS report, signature, and certificate chain from IAS.
Print out the attestation result.
- Return all this attestation data back to the enclave.