Change log (most important only):
- unify CPU context structures - now we have only one version -
`PAL_CONTEXT` - which is shared between LibOS and PALs and it should
depend only on the host architecture (not OS),
- syscalls emulation changed:
- dedicated LibOS stack is now used for syscalls emulation,
- removed one indirection level in syscalls table - now it stores
`shim_do_*` functions directly,
- signal handling - completely rewritten:
- all signal queues use proper locking schemes now,
- signals are handled *only* when returning to the user app from LibOS
or PAL,
- nested signals are now possible,
- the app is allowed to jump out of signal handler with the same
sematics as on normal Linux,
- signal altstack is now fully supported,
- syscall restarting is now supported,
- doing a backtrace from the signal handler works properly,
- disallow injecting host-level signals, with one exception, see
`sys.enable_sigterm_injection` manifest option for more details.
This commit also fixes `pseudo_name_ops::list_name()` function pointer
type: `size_t len` argument instead of `int len`. It also adds a
regression test to exercise the newly supported /sys pseudo filesystem.
- 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.
* Make sure "stat.h" and "perm.h" are directly included where
necessary.
* Don't include "perm.h" inside "stat.h" but require it to be
included separately.
* Remove workarounds with __KERNEL__, __GLIBC__, defining pid_t
directly, and reversed include order (system headers before local
ones).
Instead of using S_I* flags, or hardcoded octal literals, use
helpers such as PERM_rwxrwxr_x. These are proposed in a Linux patch
by Ingo Molnar: https://lwn.net/Articles/696231/
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.
Slab memory manager logic uses enlarge_slab_mgr() (renamed to more
accurate maybe_enlarge_slab_mgr()) to allocate a new chunk of memory
for its slab objects. For allocation itself, slab manager must release
the lock before system malloc and then re-acquire it. At this point
other threads may allocate memory for the same slab level. Also,
system malloc may fail to allocate large memory region, and slab logic
will fall back to allocating smaller memory region. These two issues
were not properly handled; this commit fixes these bugs.
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.
Also move parse_size_str() to a more appropriate atoi.c file.
This is in preparation for replacing the old ad-hoc manifest
syntax with the TOML syntax.
I don't know any reason why would stating the file name we're in be
helpful for anything. Moreover, this information was incorrect in a few
cases (copy-paste bugs, probably).
Additionally, a few minor type/formatting fixes included.
Previously, Graphene preallocated 64MB for PAL internal metadata
like trusted/protected files metadata, handles metadata, etc.
If this limit was depleted, Graphene loudly failed, and the user
had no option but to change constant in source code and rebuild
Graphene. This commit adds the manifest option
`loader.pal_internal_mem_size` to allow increasing this limit.
The (((void *) &(arg)) == ((void *) (arg))) trick does not work
with clang, because clang does not accept it as a constant
expression and doesn't allow using it in static_assert.
I was not able to write a generic (any type) IS_ARRAY macro
compatible with static_assert, but here we only need to check for
arrays of chars and uint8_t-s.
In particular, this commit:
- Removes SLAB_DEBUG macros and corresponding code.
- Fixes memory leak in memmgr's enlarge_mem_mgr() by removing
__set_free_mem_area() call.
- Fixes bug of double-free of the very first memmgr area in
destroy_mem_mgr().
- De-duplicates "get new memory object" code by changing
get_mem_obj_from_mgr() to call get_mem_obj_from_mgr_enlarge().
- Simplifies and improves performance of free_mem_obj_to_mgr() since
there is no need to double-check that the object belongs to one of
the memmgr's areas because we already check memory_migrated().
- Fixes bug of free of wrong object in slabmgr's destroy_slab_mgr().
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.
This is the first step in removing this obsolete header.
Additionally, AtomicMath test is removed, as it became obsolete after
these changes (and was relying on undefined behaviors anyway).
Sometimes we need to prevent the compiler from reading or writing to
a memory location twice to prevent certain TOCTOU bugs. This can now
be achieved by using the introduced macros and this commit does so in
enclave_ocalls.c for Linux-SGX.
This commit completely reworks VMA subsystem along with its usages.
New version should be: cleaner (easier to maintain), faster and allow
for bookkeeping requests from Pal.
It also fixes some bugs and inconsistencies found in the process and
changes brk and mmap/munmap implementations (at least partially).
mbedTLS configuration used in Graphene is not thread-safe (because
this would require the use of a threading library like pthread which
is not possible in the LibOS/Pal layers). However, some mbedTLS
functions use shared state, in particular TLS context initialization
functions. This led to data races during encrypted-pipe creation,
since it requires two threads performing a TLS handshake. This commit
refactors TLS init into SSLInit (not thread-safe) and SSLHandshake
(thread-safe) and adds spinlocks around SSLInit to protect the racy
mbedTLS logic.
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.
Previously, Graphene used the notation "pipe:<uint32_t>" to emulate
pipes, socketpairs, and UNIX domain sockets. In particular, pipes
and socketpairs received random integer IDs, and sockets received
deterministic integer IDs. However, 32-bit randomly generated IDs
may collide quite often. Since pipe IDs/names should *not* repeat
(otherwise e.g. derived crypto keys will be reused), this commit
changes pipe IDs (pipeid) from uint32_t to char[96], and pipe IDs
(names) become 256-bit random sequences.