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.
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.
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
write
syscall. - The shim traps all syscalls, and notices this is a
write
syscall. - The shim writes an empty
Block
onto 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
Message
header to be aRequest
variant. In the case of thewrite
syscall, the shim:- Sets the request
num
to 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 theBlock
where the bytes have been copied to.arg[2]
= The number of bytes that thewrite
syscall 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
'sMessage
header. - Once the syscall is complete, the host-side Enarx code can update the
Block
's header and set it to aReply
variant of theMessage
union and write the syscall return code to it. - The host-side Enarx code returns control to the shim.
- The shim examines the
Reply
in theMessage
header of theBlock
and propagates any mutated data back to the protected address space. It may then return control to its workload.
License: Apache-2.0