sallyport
API for the hypervisor-microkernel boundary
sallyport is a protocol crate for proxying service requests (such as syscalls) from an Enarx Keep
to the host. A sally port is a secure gateway through
which a defending army might "sally forth" from the protection of their fortification.
An astute reader may notice that sallyport is a thin layer around the Linux syscall ABI as it is
predicated on the conveyance of a service request number (such as rax for x86_64) as well as the
maximum number (6) of syscall parameter registers:
| Architecture | arg 1 | arg 2 | arg 3 | arg 4 | arg 5 | arg 6 |
|---|---|---|---|---|---|---|
| x86_64 | rdi | rsi | rdx | r10 | r8 | r9 |
The above table was taken from the syscall(2) man page
Note that sallyport is meant to generalize over all architectures that Enarx anticipates proxying
syscalls to, not just x86_64 which was listed in the above table for illustration purposes.
Usage
sallyport works by providing the host with the most minimal register context it requires to
perform the syscall on the Keep's behalf. In doing so, the host can immediately call the desired
syscall without any additional logic required. This "register context" is known as a Message in
sallyport parlance.
The Message union has two representations:
Request: The register context needed to perform a request or syscall. This includes an identifier and up to the 6 maximum syscall parameter registers expected by the Linux syscall ABI.Reply: A response from the host. This representation exists to cater to how each architecture indicates a return value.
The Message union serves as the header for a Block struct, which will be examined next.
The Block struct is a page-sized buffer which must be written to a page that is accessible
to both the host and the Keep to facilitate request proxying. The region of memory that is
left over after storing the Message header on the block should be used for storing additional
parameters that must be shared with the host so it can complete the service request. In the
context of a syscall, this would be the sequence bytes to be written with a write syscall.
If the Keep forms a request that requires additional parameter data to be written to the Block,
the register context must reflect this. For example, the second parameter to the write syscall
is a pointer to the string of bytes to be written. In this case, the Keep must ensure the
second register parameter points to the location where the bytes have been written within the Block,
NOT a pointer to its protected address space. Furthermore, once the request has been proxied, it is
the Keep's responsibility to propagate any potentially modified data back to its protected pages.
Example
Here's an example of how the sallyport protocol might be used to proxy a syscall between
the host and a protected virtual machine:
- The workload within the Keep makes a
writesyscall. - The shim traps all syscalls, and notices this is a
writesyscall. - The shim writes an empty
Blockonto the page it shares with the untrusted host. - The shim copies the bytes that the workload wants to write onto the data region of the
Block. It is now accessible to the host. - The shim modifies the
Messageheader to be aRequestvariant. In the case of thewritesyscall, the shim:- Sets the request
numto the Linux integral value forSYS_write. - Furnishes the register context's syscall arguments:
arg[0]= The file descriptor to write to.arg[1]= The address within theBlockwhere the bytes have been copied to.arg[2]= The number of bytes that thewritesyscall should emit from the bytes pointed to in the second parameter.
- Sets the request
- The shim yields control to the untrusted host, in which host-side Enarx code realizes it must proxy a syscall.
- The host-side Enarx code can invoke the syscall immediately using the values in the
Block'sMessageheader. - Once the syscall is complete, the host-side Enarx code can update the
Block's header and set it to aReplyvariant of theMessageunion and write the syscall return code to it. - The host-side Enarx code returns control to the shim.
- The shim examines the
Replyin theMessageheader of theBlockand propagates any mutated data back to the protected address space. It may then return control to its workload.
License: Apache-2.0