It turns out that our guard pages were incorrectly handled (i.e. not re-
added to LibOS VMA list) on SGX when execve was optimized to re-use the
same enclave, which caused exec_same test to crash from time to time
(when ASLR put heap on a guard page).
Static guard pages aren't too useful and introduce unnecessary
complexity to our code, so we decided to just delete them in order to
fix this bug.
SGX_DBG macro disrespects debug logging settings from the manifest, but
fixing this properly is a much bigger task (the whole logging subsystem
should be redesigned).
Previously, `pf_file_read()`/`pf_read()` in Protected Files disallowed
reading less than the requested number of bytes. This is incorrect
semantics, and these functions must return the actually read number of
bytes instead of loudly failing. This bug leads to e.g. errors in
Python scripts (Python's `read()` reads one byte past the end of file
for whatever reason).
Changes:
- `make all` previously rebuilt everything each time, now it
doesn't.
- Using out-of-tree build.
- Unfortunately we have to build the whole LTP now (minus modules),
so the build is slower.
- But: `make -jX` works, previously was broken because of missing
dependencies.
- Not using symlinks as targets anymore - Make is broken and checks
the timestamp of the *destination*, not the symlink itself.
Previously the links were recreated on each `make` call.
- `make regression` printed:
/bin/sh: 1: test: Illegal number:
and now it doesn't.
This commit adds the ability to provision the wrap (master) key for
protected files at runtime (in contrast to previous approach of
hard-coding `protected_files_key` in the manifest as a temporary
solution). This is achieved as follows:
- New PAL API `DkSetProtectedFilesKey()` is added.
- New writable pseudo-file `/dev/attestation/protected_files_key` is
added. It calls `DkSetProtectedFilesKey()` after it was written to.
- New `SECRET_PROVISION_SET_PF_KEY` option is added to the Secret
Provisioning library. If it is set, the library assumes that the
first provisioned secret is the wrap key for PF and writes it into
the new pseudo-file.
The Secret Provisioning example `ra-tls-secret-prov` is updated to
include the new protected-files client. This client receives the wrap
key for PF via secret provisioning and reads & outputs the protected
file `files/input.txt`.
*NOTE*: The current implementation of provisioning the wrap key does
not work for `loader.argv_src_file` and `loader.env_src_file` if they
point to protected files (because provisioning happens after setting
up arguments and environment variables).
The client part of RA-TLS demo only ran outside SGX. This patch optionally
allows the client to run in Graphene SGX as well. This is useful for those
who need to create a secure channel between Graphene SGX processes running
on different machines.
Using Redis 6.0.5 on more recent distros (Fedora 32) avoids linker
issues like the following ones:
/usr/bin/ld: server.o:sds.h:37: multiple definition of `SDS_NOINIT';
quicklist.o:sds.h:37: first defined here
Using the latest busybox 1.32.0 on more recent distros (Fedora 32)
avoids linker issues like the following ones:
/usr/bin/ld: util-linux/lib.a(rdate.o): in function `rdate_main':
rdate.c:(.text.rdate_main+0x150): undefined reference to `stime'
/usr/bin/ld: coreutils/lib.a(date.o): in function `date_main':
date.c:(.text.date_main+0x2a4): undefined reference to `stime'
collect2: error: ld returned 1 exit status
This commit fixes two bugs in Protected Files:
- mbedTLS source of entropy (`mbedtls_entropy_context`) was allocated
on the stack and thus destroyed after return from init function; in
reality, this object must live for the whole duration of execution
(this bug led to spurious segfaults due to overwritten stack).
- MHT nodes of protected files must be updated and flushed to disk in
reverse order of sorting, from bottom layers to upper layers (this
bug led to outdated MHT key/MAC values in resulting encrypted file,
so the file could not be correctly decrypted).
This patch optimizes _DkSystemTimeQuery() using RDTSC instead of
ocall_gettime.
This optimization won't take effect if there is no reliable TSC source
available to use i.e. nonstop/invariant TSC.
The TSC drift is bound by syncing with system clock periodically.
FSGSBASE instructions can get disabled at runtime (e.g. after
suspend+resume with our currently bugged driver) and cause #UD in
enclaves, which can confuse users.
Under SGX PAL, if the CPU doesn't support RDTSC/RDTSCP inside SGX
enclave, Graphene uses trap-and-emulate on these instructions.
Previously, Graphene only emulated RDTSC and not RDTSCP. Moreover,
Graphene emulated RDTSC by simply returning zeros, which could lead
to faults in applications not expecting a zero value. This commit
emulates (imprecisely) both RDTSC and RDTSCP via gettime() syscall.
New LibOS test is added (SGX-only).
Previously, RA-TLS was recommended to be used with LD_PRELOAD trick.
However, LD_PRELOAD is too hacky and shouldn't be used to preload
libraries to an executable (in contrast to its normal use of
replacing functions from one library with another). This commit
removes any mentions of LD_PRELOAD trick from RA-TLS, and
replaces LD_PRELOAD with `dlopen()` in ra-tls-mbedtls example.
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.
Previously, Glibc build produced the following message:
"*** errlist.c count 134 inflated to GLIBC_2.12 count 135 (old
errno.h?)". This message is *not* a Graphene build issue and
may confuse users, so this commit removes it.
Commit 647bca34 ("[Pal/Linux-SGX] Lazily zero-out the heap instead of proactively on init")
changed the old logic of "zero the whole heap during enclave
initialization" to "zero the heap pages on demand". This led to better
start-up times of enclaves (without any significant security drawbacks).
However, this change has a trade-off: some applications (Redis in
particular) have worse run-time performance.
To allow users to choose between faster start-up time vs better
run-time performance, this commit introduces "sgx.zero_heap_on_demand"
manifest option. It is zero by default, meaning zero-out of whole
heap during enclave initialization; i.e., by default enclaves take
longer to start, but have better run-time performance.
Previously, Linux-SGX PAL did not clear SSA.GPRSGX.EXITINFO while in
signal handler (which Graphene enters in response to AEX). Note that
Graphene first checks trustworthy EXITINFO (filled by SGX HW on AEX)
to identify the reason for signal/exception, and only then falls back
to possibly malicious `sgx_raise()` argument (filled by Linux kernel
and propagated by untrusted PAL).
Not clearing EXITINFO led to a subtle racey failure of OpenMP test
(and possibly others): main thread sends SIGCONT async signal to
child thread, and child thread executes forbidden SYSCALL instruction
and gets AEX(SIGILL) at the same time. Now if SIGILL due to SYSCALL
arrives first, EXITINFO is filled with SIGILL information. Then
SIGCONT is queued on the enclave signal stack, in the same SSA (see
`enclave_entry.S:Lsetup_exception_handler`). After SIGILL is
correctly handled using the first signal-stack frame, SIGCONT is
handled next. However, since EXITINFO was not cleared, SIGCONT's
signal-stack frame contains wrong EXITINFO = SIGILL. This confused
Graphene: it tried to handle SIGILL instead of SIGCONT.
This commit fixes this bug by simply clearing EXITINFO after it was
checked once. This works because it is impossible to have two SGX HW
exceptions on the same thread at the same time, so we do not lose any
vital information by clearing EXITINFO.
Previously, Linux-SGX PAL checked RIP of the interrupted normal
context only against the first instruction of the AEP trampoline code
(recall that SGX passes control to AEP on AEX). In Graphene, this is
the asm function `async_exit_pointer()`. However, Linux may deliver
signal (as response to AEX) at any point during AEP trampoline. Thus,
PAL code incorrectly checked RIP and wrongly assumed that there was
no AEX but instead an exception in PAL code itself, which led to rare
Graphene failures. This commit fixes this bug by checking RIP against
the whole range of function `async_exit_pointer()`.
Secret Provisioning provides a simple interface for enclavized
applications to connect to a trusted secret-provisioning service and
securely pass the secrets inside the SGX enclave. The application acts
as a client and the secret-provisioning service as a server. They
establish a TLS session via mutual authentication, where the service
sends a classical X.509 certificate and the application sends an
RA-TLS X.509 certificate. After the service verifies the RA-TLS
certificate and its SGX-related information, it provisions secrets
to the application. The TLS session may continue to be used by the
application and the server after the initial provisioning. Secret
Provisioning feature relies heavily on RA-TLS.
Secret Provisioning is shipped as three libraries:
- secret_prov_attest.so: creates RA-TLS X.509 certificate with SGX
quote embedded and sends it to the secret-provisioning service as
part of mutual attestation of TLS session. Linked into enclavized
applications. Not thread-safe.
- secret_prov_verify_epid.so: establishes a TLS session with mutual
attestation, verifies received RA-TLS certificate, and sends secrets
back to the enclavized application. Linked into secret-provisioning
service. Verifies RA-TLS certificate using EPID-based flows.
Multi-threaded and thread-safe (new thread for each client).
- secret_prov_verify_dcap.so: same as secret_prov_verify_epid.so but
verifies RA-TLS certificate using ECDSA/DCAP-based flows.
Multi-threaded and thread-safe (new thread for each client).
This commit also adds two Secret Provisioning examples, with a minimal
enclavized app, a more complicated enclavized app, and a single
secret-provisioning service. These examples are added to Jenkins.
Previously, Linux-SGX PAL initialized the whole heap to zero from
within the enclave at startup. This led to significant slowdown on
large-sized enclaves. This commit removes the old proactive logic
and instead zeroes-out the heap lazily, when enclave pages are
actually requested. This does not change the security guarantees
because the whole heap is anyway RWX on SGX v1, and the attacker
may exploit app vulnerabilities (if any) by supplying malicious data
within the enclave during runtime.
Previously, Glibc patches were generated with shortened index hashes.
This commit re-generates all Glibc patches with complete index
hashes using `--full-index` option.
This commit also removes mentions of removed old Glibc 2.19 and the
unused Gold ld patch.
This patch fixes the following compile error:
string/memcpy.c: In function \u2018memcpy\u2019:
string/memcpy.c:32:16: warning: dereferencing \u2018void *\u2019 pointer
*d++ = *src++;
^~~~~~
string/memcpy.c:32:14: error: void value not ignored as it ought to be
*d++ = *src++;