325 Commits

Author SHA1 Message Date
Paweł Marczewski 2cfdd510dc [LibOS] Remove dynamic linking
After this change, LibOS will no longer perform dynamic linking.
The ELF loading code executes load commands and passes control to
interpreter (ld.so), which handles necessary relocations and
loading additional libraries. In this way, the code resembles what
Linux kernel does when executing a new program.

Before, dynamic linking was necessary for making LibOS entry point
(syscalldb function) available for applications. However, that meant
duplicating the work already done by ld.so, and introduced a lot of
unnecessary complexity. After changing LibOS entry API to use the
GS register, it's possible to omit dynamic linking entirely.

The main function (__load_elf_object()) still needs cleanup and
possibly rewriting from scratch. However, this change prepares
ground for that rewrite.

Summary of changes:

- Remove dynamic relocation step (DO_DYNAMIC_RELOCATE()).
- Don't call __load_elf_object() again for ELFs reported
  via register_library(). We only need to notify GDB about these.
- Remove fields related to dynamic linking from link_map (dynamic
  section address, hashes, etc.), and setup for these fields.
- need_interp(): To check if we need an interpreter, check only if
  the binary requests one (PT_INTERP), instead of traversing the
  dynamic section (before, we ignored dynamic dependencies on LibOS
  itself, but now there shouldn't be any).
- RELOCATE(): always adjust addresses, instead of checking if
  they're already inside the mapped range. I think the previous
  behaviour was a workaround to make repeated relocations work.
- Get rid of load modes that are no longer used (OBJECT_REMAP,
  OBJECT_USER).
- Remove the workaround for repeated relocation in glibc patches
  (R_X86_64_NONE).

Signed-off-by: Paweł Marczewski <pawel@invisiblethingslab.com>
2021-02-18 02:48:02 +01:00
Paweł Marczewski 6ea8e951f0 [LibOS] Use GS register for syscalls
Instead of depending on dynamic linking for LibOS entry point
(syscalldb), we pass a pointer in the shim_tcb structure, so that
the patched code can enter syscall using 'jmp *%gs:<offset>'.

The same applies to the vDSO syscall code that previously needed
an up-to-date pointer to syscalldb function. Now, there is no
need to adjust the values inside the vDSO page.

In addition, this change removes the other two instances where we
import a symbol directly from LibOS: register_library (can be also
done through GS register) and glibc_version (not important because
we build Graphene and glibc together).

This simplifies things because the dynamic linking necessary to
make the syscalldb function available had to be performed by LibOS
itself (in many cases, effectively doing a second pass of dynamic
linking after ld.so). After this change, there will be no need for
LibOS to perform dynamic linking, and the ELF loading code can be
simplified.

Signed-off-by: Paweł Marczewski <pawel@invisiblethingslab.com>
2021-02-15 22:19:28 +01:00
borysp c24bddd5aa [LibOS] Rework signal handling and syscall emulation
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.
2021-02-05 14:11:21 +01:00
borysp bec1d9b4ec [LibOS] Fix LibOS code range checks in shim_signal.c
The old version did not consider e.g. PLT as code.
2021-02-05 14:00:05 +01:00
Li, Xun 1ddfd0e36f [LibOS] Allow but ignore MSG_WAITALL flag in recv 2021-02-03 01:16:43 +01:00
Michał Kowalczyk 5521c70401 [LibOS] Fix 'wence' -> 'whence' typo 2021-02-01 02:36:59 +01:00
Vijay Dhanraj ec4422d415 [Pal,LibOS] Add support for /sys pseudo filesystem
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.
2021-01-28 23:28:29 -08:00
Paweł Marczewski ae8beba1a7 [Pal,Docs] Convert 'info' log level to 'warning'; add description
We seem to be using it for warnings, so it should be less confusing.
This change also adds a description of the levels to documentation.
2021-01-26 21:01:32 +01:00
Stefan Berger 1b8848bdae [LibOS] Align char msg[] in shim_ipc_msg to 16 bytes
The msg field of 'struct shim_ipc_msg' will for example be cast to
'struct shim_ipc_sysv_tellkey*' (in ipc_sysv_tellkey_callback()) and
needs to be properly aligned. There are also casts to other IPC-related
structures that also require alignment.
2021-01-20 23:57:08 +01:00
Paweł Marczewski 17ab04db59 [Pal,LibOS] New logging system
Instead of 'loader.debug_type', introduce 'loader.log_level'
and 'loader.log_file', along with a set of definitions for
logging at a chosen level.

For now, the call sites keep using the legacy macros (SGX_DBG and
debug()), because converting them all will conflict with other
big changes in the code base. The existing LibOS calls are
assumed to be at 'info' level.
2021-01-20 17:27:29 +01:00
Stefan Berger f3c235ac09 [LibOS] Fix __rs_func type to not confuse UBSAN 2021-01-19 18:38:18 +01:00
borysp 287762501b Add infinite loop behind each call to exit syscall
This commit additionally replaces all `while (true) {}` inf loops with
`die_or_inf_loop` which either crashes the process or loops infinitely
and is not an undefined behavior like the original one (C disallows inf
loops without side effects).
2021-01-15 16:35:03 +01:00
borysp d2dea5f4ec [LibOS] Remove types from syscalls debug printing
This commit removes types from syscall argument printing functions as
a preparation for next changes. Now the table with syscall parsers have
all parsing functions embeded directly.
Also some minor cleanups in the same area.
2021-01-14 19:56:30 +01:00
borysp baf96961c9 [LibOS] Make all syscalls really return long
Fixes places missed by commit "[LibOS] Have all syscall functions return
long"
2021-01-14 19:56:30 +01:00
borysp 2f88a6cc8f [LibOS] Remove unused checkpointing functions
Commit "Introduce one, central manifest, zero-config children and
constant MRENCLAVE" removed execve-in-a-new-process, so execve specific
checkpointing functions are not needed anymore (pending_signals,
arguments, environ).
2021-01-13 19:44:18 +01:00
Michał Kowalczyk 3d31f2d18d Introduce one, central manifest, zero-config children and constant MRENCLAVE
This is the next part of the great loader rework, with a lot of breaking changes:

- Complete removal of the "trusted children" thing - now children
  processes can be spawned arbitrarily and from arbitrary mountpoint
  types, without any additional configuration needed.

- There's a new, required option in the manifest: `libos.entrypoint` - it
  specifies the URI to the entry binary in the first process. There's no
  need anymore to name the manifest and the first binary identically.

- On SGX, the main binary is not measured in MRENCLAVE anymore - only
  PAL, LibOS and the manifest are measured. This is enough to bind
  MRENCLAVE to a specific entrypoint user executable if wanted - it
  just has to be mounted as a trusted file.

- All Graphene SGX enclaves have now exactly the same MRENCLAVE. This is
  a hash of a "Graphene stub", which can "fork" into one of two states
  in runtime: initial process or child. The initial process creates a
  new "Graphene namespace" with a clean state, it can also be attested
  remotely (contrary to child processes). The initial process can spawn
  children processes by spawning a Graphene stub and directing it to
  start in the child mode. It then attests it locally, and if
  successful, establishes an encrypted pipe, "connects" to its own
  namespace and treats as trusted (including sending protected files
  key).

- Now, there's only one, central manifest describing the initial state
  of a Graphene instance which can be spawned from it (previously, each
  process required a separate manifest which could have different
  configuration - which wasn't actually supported and didn't make sense
  design-wise). One downside of central manifests is that all processes
  require the same enclave configuration (e.g. size), but that was
  already the case so far because of broken checkpointing code. Also,
  this is only a temporary problem, which will cease to exist after the
  introduction of EDMM.

- `sgx.static_address` was renamed to `sgx.nonpie_binary` and now has to
  be inserted manually by users (`sgx_sign` tools doesn't know about the
  binaries run inside, which can be even provided or generated in
  runtime by the user's workload).

- Caveat: the memory gap for non-PIE executables was removed because it
  requires adding a new option to the manifest to be cleanly
  implemented. This is left for some future loader rework PR.
2021-01-12 19:53:24 +01:00
Stefan Berger a396892060 [LibOS] Have all syscall functions return long
That's how all of them are defined on Linux.
2021-01-12 16:14:32 +01:00
Stefan Berger 8c1fc5168e [LibOS] Rename fs_base to tls_base to be more generic 2020-12-25 00:18:20 +01:00
Stefan Berger b4205008ff [LibOS] Move some x86-specific context registers into own struct 2020-12-23 21:30:23 +01:00
Dmitrii Kuvaiskii 5d7132d22f [LibOS] Remove unused macros in shim_defs.h 2020-12-23 07:46:57 -08:00
Dmitrii Kuvaiskii 3a07d86ccf [LibOS] Save/restore FP/SSE/AVX/... control words on syscalls
Previously, Graphene saved and restored only the GP registers of the
CPU context on entering and leaving syscall emulation in syscalldb().
In reality, the CPU context must also contain FP control word (fpcw)
and the SSE/AVX/... control word (mxcsr). This commit preserves these
control words across app-to-Graphene context switches.

During syscall emulation, Graphene may clobber the FP/SSE/AVX/...
state (except the control words). We rely on the fact that apps do
*not* assume that this state is preserved across syscalls (except
the control words). Thus, it is enough to save/restore only the
control words on each syscall. This commit also removes previous
hack of performing expensive xsave/xrstor instructions on clone().
2020-12-22 23:04:39 +01:00
borysp 989dac6fc8 [Pal] Fix semantics of DkSegmentRegister
On x64 DkSegmentRegister had weird semantics which also disabled some
usages like `0` as fsbase.
2020-12-17 16:18:26 +01:00
Michał Kowalczyk d53729b201 [Pal] Rework manifest loading
This is a major refactor of the way manifests are loaded and handled,
which will be followed by a complete rework of the loader code (which
will include e.g. centralized config).

Changes/fixes:
- Huge part of manifest handling was refactored and untangled.
- Starting without a manifest is now disallowed. This was actually
  accidentally broken for some time and no one complained. It also makes
  little sense in practice and in Graphene's overall design, e.g. it
  conflicts with protected argv.
- Now we only allow starting by giving the executable, not manifest (the
  magic resolution logic was removed).
- Now manifests are sent over pipes between parent and children, instead
  of children finding and loading them on their own. This is a
  preparation for the upcoming centralized manifests change.
- Previously manifests were parsed 2 times on Linux and 3 times on
  Linux-SGX (by untrusted PAL, trusted PAL and LibOS). This is now
  fixed.
- The common `pal_main()` now requires that the backend-specific PAL
  loader loads the manifest before calling it. SGX code already has to
  do it (for proper initialization), so let's unify this interface for
  all PALs.
- Fix for a PAL crash when manifest size was divisible by page size
  (sic!). NULL termination was missing, but most of the time the padding
  to page size saved Graphene from crashing.
2020-12-05 01:46:03 +01:00
Dmitrii Kuvaiskii 38c8004d36 [LibOS] Remove unused flush_handle() and flush_handle_map() 2020-12-04 00:32:46 -08:00
borysp 0c9ed03164 [LibOS] Add opportunistic dentry removal and fix some refcount issues
Previously Graphene never deleted dentries. This commit adds possible
dentry deletion on `unlink` and handle close. It also fixes some
dentry reference counting bugs.
2020-12-02 03:19:54 -08:00
Dmitrii Kuvaiskii a72662ffb2 [LibOS] Refactor and simplify ioctl() emulation 2020-11-23 14:04:24 -08:00
Stefan Berger a01b8743f8 [LibOS] Move CRASH_PROCESS from BUG() into arch-specific header 2020-11-23 22:14:49 +01:00
borysp f1c8512a5e [LibOS] Rename shim_signal_handles to shim_signal_dispositions 2020-11-19 18:35:27 +01:00
borysp 2a95cd5f25 [LibOS] Rework threads implementation
Most important differences from the old version:
- strip global process information from the thread struct into a
  dedicated one,
- a parent is informed about the child death when the whole process
  (the last thread) dies (not on each thread exit),
- all threads have the same parent (spawning thread is NOT the parent of
  the spawned thread),
- a thread is able to wait on children created by another thread,
- a process is able to wait for exited children after execve,
- rewritten `waitid` implementation (no more gotos, supports __WCLONE
  and friends flags),
- added option for syscall restarting, for now used only in `waitid`.

Additionally various bugfixes, cleanups and missing locks added.
2020-11-19 18:35:27 +01:00
borysp 5b4c747edf [LibOS] Allow for stopping IPC helper thread
Sometimes we need to temporarily stop IPC helper thread from receiving
more messages, e.g. when doing execve just before migrating exited (but
not yet waited for) children list.
2020-11-19 18:23:26 +01:00
Paweł Marczewski 883ae10de1 [Pal,LibOS] Clean up includes
* 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).
2020-11-19 14:27:06 +01:00
Paweł Marczewski 1b3de7203e [Pal,LibOS] Introduce stat.h
Keep our own copy of S_* macros.
2020-11-19 14:24:59 +01:00
Paweł Marczewski 38bf50c4c5 [Pal,LibOS] Fix loader.debug_type = file
Logging to file was broken, because the PAL file write operation
required the user to provide an absolute offset, and LibOS always
provided an offset of 0. This worked when logging to stdout, but
in case of a regular file, it kept overwriting the beginning of
file.

To fix that, we introduce a a special DkDebugLog call. This is a
better solution than tracking the file offset manually, because
the offset would need to be synchronized across different threads
and processes, and debug logs should be as simple as possible. At
the same time, we don't want PAL to provide a generic "append to
a file" mechanism, because it makes I/O less deterministic.
2020-11-17 23:56:28 +01:00
borysp b11184534f [LibOS] Always clear SIGSTOP and SIGKILL from signals mask 2020-11-17 02:24:03 +01:00
Dmitrii Kuvaiskii 8eee4a4742 [LibOS,Pal,Examples,GSC,Docs] Move manifest parsing to TOML
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.
2020-11-12 05:45:07 -08:00
Paweł Marczewski a353f54296 [LibOS] Fix fcntl(F_DUPFD) hang
The operation loops indefinitely on error. Instead, it should find
the first free FD, and then try allocating it.

In addition, the right error after exceeding the limit is EMFILE
(however, dup2() is still supposed to return EBADF if asking for
an out-of-range value, as checked by the dup201 LTP test).
2020-11-12 11:55:52 +01:00
borysp 514180bc22 [LibOS] Fix *_event functions
They all lacked error checking and `wait_event` was completely broken:
it was reading from non-blocking pipe and treating EAGAIN as
successfully waited-for event.
2020-11-09 22:46:57 +01:00
Vijay Dhanraj 3fa93cc86f [LibOS,Pal] Add sched_setaffinity/sched_getaffinity syscall support
This patch adds syscall support for setting/getting cpu affinity
of threads.

Co-authored-by: Gary <gordon.king@intel.com>
2020-11-06 22:28:32 +01:00
Dmitrii Kuvaiskii 54ab669ecd [LibOS] Remove unused IPC port types
Previously, IPC_PORT_SERVER meant "listening port", and the actual
communication ports had several types. Only two of these types were
used for differentiation during IPC broadcast (direct-child and
direct-parent types). All other types denoted who is the remote party
this port connects to, but this info is superfluous. So this commit
replaces all these types with a generic IPC_PORT_CONNECTION, and
renames IPC_PORT_SERVER to a more familiar IPC_PORT_LISTENING.
2020-11-05 22:13:46 +01:00
borysp 3014a0dd1c Miscelaneous inline asm fixes
Mostly adds missing "memory" clobber which caused some nasty bugs - gcc
optimized those inline asms and assumed values returned by them never
change.
2020-11-05 13:48:41 +01:00
Dmitrii Kuvaiskii 9b91693497 [LibOS] Remove create_{dir,file,handle}() and refactor create_pipe() 2020-10-31 03:11:22 +01:00
Dmitrii Kuvaiskii 3b02bdc80f [LibOS] Add XSAVE area handling and save/restore it on child thread creation
Previously, LibOS (shim) layer of Graphene didn't support XSAVE area.
The XSAVE area stores FP, XMM, YMM, ZMM, etc. registers and control
states and is handled via FXSAVE/XSAVE and FXRSTOR/XRSTOR x86-64
instructions. This commit is the first step towards adding full-
fledged XSAVE support to LibOS. It adds XSAVE related structs and
functions to LibOS code, and propagates XSAVE regs/states from
parent to child on thread creation via clone() (though not really
correctly). New test `fp_multithread` is added to LibOS regression.

Future commits will add correct XSAVE handling on syscall transitions
and arriving signals.
2020-10-29 07:56:31 -07:00
Li, Xun ea49007aa0 [LibOS] Enhance /dev/null stat
glibc function daemon() checks st_rdev field in struct stat of
/dev/null, which wasn't previously properly filled.
2020-10-27 00:58:43 +01:00
borysp b2f03e0d47 [LibOS] Remove IPC LEASETYPE and accompanying fields
Some structures had a field `lease` which was passed to IPC code, which
shuffled it left and right, but never actually used.
2020-10-22 01:27:38 -07:00
borysp 2c85c91c24 [LibOS] Remove exit code from ipc_port_with_child_fini
If a remote ipc port gets disconnected we assume that remote process
died unexpectedly and mark it as killed with SIGKILL, so it makes no
sense to also keep the exit code.
2020-10-21 21:53:01 +02:00
borysp fffd703b74 [LibOS] Clean up clone and fork implementations
On Linux fork and vfork are just specific cases of clone. This commit
does small cleanup of clone code and deduplicates proces copying code by
always using clone.
2020-10-20 20:40:30 +02:00
borysp 4305f667e1 [LibOS] Remove unneeded tid field of shim_tcb
This field was just cached `tcb->tp->tid`. It was not really needed and
annoying to keep in sync.
2020-10-20 12:59:18 +02:00
borysp 1dc11a6f84 [LibOS] Move locking from shim_internal.h to a dedicated header 2020-10-20 12:59:18 +02:00
borysp 36edd357fa [LibOS] Remove unused functions in shim_internal.h and shim_init.c
Removed:
- `message_confirm` - not used anywhere (and probably won't ever be),
- `SYS_PRINTF` - this was just synonym of `debug` or `warn` (depending
   on the context),
- all other functions that were used only by the two above.
2020-10-16 18:06:22 +02:00
borysp 05a258c95b [LibOS] Consolidate and remove unused code in thread checkpointing 2020-10-15 00:03:44 +02:00