Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
3741: Syscall TCB Reduction/Syscall Dispatching Rewrite r=anakrish a=anakrish Syscalls are routed directly to their implementations rather than via a switch-case. This has the following benefits: - Reduced TCB Switch-case causes all the syscalls to be retained in an enclave. Routing directly allows the linker to eliminate those syscalls that are not used by an enclave. For example echo enclave reports only the following syscalls: ❯ objdump -t echo_enc | grep oe_SYS_ 000000000003002b l F .text 00000000000000bc oe_SYS_clock_gettime_impl 00000000000300e7 l F .text 00000000000000c6 oe_SYS_gettimeofday_impl 0000000000067e10 l F .text 000000000000005f oe_SYS_futex_impl - Syscall callgraphs can be analyzed easily. Since syscall implementations are directly called rather than via a switch-case, the static callgraphs are simpler and more accurate. ❯ callgraph.py echo_enc oe_SYS_gettimeofday_impl oe_SYS_gettimeofday_impl 0x300e7 /home/anakrish/work/syscall/libc/syscalls.c:75 └── __clock_gettime 0x67d97 /home/anakrish/work/syscall/3rdparty/musl/musl/src/time/clock_gettime.c:25 └── time 0x67d3f /home/anakrish/work/syscall/3rdparty/musl/musl/src/time/time.c:4 └── x509_get_current_time 0x38ff8 /home/anakrish/work/syscall/3rdparty/mbedtls/mbedtls/library/x509.c:929 ├── mbedtls_x509_time_is_past 0x3927a /home/anakrish/work/syscall/3rdparty/mbedtls/mbedtls/library/x509.c:994 │ ├── x509_crt_verifycrl 0x36d69 /home/anakrish/work/syscall/3rdparty/mbedtls/mbedtls/library/x509_crt.c:1832 │ │ └── x509_crt_verify_chain 0x37491 /home/anakrish/work/syscall/3rdparty/mbedtls/mbedtls/library/x509_crt.c:2288 │ │ └── mbedtls_x509_crt_verify_restartable 0x37a3f /home/anakrish/work/syscall/3rdparty/mbedtls/mbedtls/library/x509_crt.c:2562 │ │ └── mbedtls_x509_crt_verify 0x379e4 /home/anakrish/work/syscall/3rdparty/mbedtls/mbedtls/library - It is possible to figure out the list of syscalls retained in an enclave via: `objdump -t enclave-filename | grep oe_SYS_` Details - Syscalls are most often performed by libc (in our case MUSL) rather than the user code. A syscall in MUSL of the form syscall(SYS_open, a, b) is converted to oe_SYS_open_impl(a, b) avoiding the dispatch via switch-case. This is accomplished by patching musl/src/internal/syscall.h. Note: OE currently (prior to this PR) relies on SYSCALL_NO_INLINE define to get MUSL to not use SYSCALL instruction and instead call `syscall` function for dispatching syscalls. SYSCALL_NO_INLINE macro has been removed in newer versions of MUSL and MUSL no longer provides the above customization that we want. Therefore we'd anyways have to patch musl/src/internal/syscall.h when we upgrade MUSL. - The existing switch-case based dispatching have been retained for - use by libOS. It may turn out that libOS does not need the switch-case based dispatching at which point we can remove it. - the case where user code directly makes a syscall instead relying of MUSL. Such cases ought to be quite rare. - Syscall implementations are declared WEAK so that they can be overridden. This is intended for use by tests and not by users. This provides a (cleaner IMO) alternative to syscall hooks. The syscall function names have oe_SYS_ prefix and the chance of user accidentally overriding a syscall implementation is quite low. The chance can be further minimized by obfuscating the prefix. - N_M (N or More) syscalls. Some syscalls take N or more parameters. Such syscalls are declared and defined using the N_M macros. E.g: OE_DEFINE_SYSCALL2_M(Sys_open) Sys_open is called with atleast 2 parameters; but sometimes with 3. There is no easy way to capture this in C. It C++ it is possible to provide overloads and capture all the calling patterns. As a reasonable alternative, we declare SYS_open to take 2 or more parameters. Tracking such syscalls will allows us in future to make sure that OE implementations of syscalls do indeed consume all the supplied parameters. MUSL sometimes calls certain syscalls with syscall_cp macro which always supplies 6 parameters to the syscall - the original supplied parameters followed by zeros. It is not clear why MUSL does this. But this has the consequence that syscalls that are called thus must be declared using the N_M macros. Signed-off-by: Anand Krishnamoorthi <[email protected]> Co-authored-by: Anand Krishnamoorthi <[email protected]>
- Loading branch information