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.
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.
Guest and host side communicate via a mutually-distrusted shared block of memory.
This crate provides functionality for the guest to execute arbitary requests by proxying requests to the host via the untrusted block and corresponding functionality for the host to execute the requests contained within the untrusted block.
The sallyport block is a region of memory containing zero or more items. All items contain the following header:
- size:
usize
- kind:
usize
The size parameter includes the full length of the item except the header value. The contents of the item are defined by the value of the kind
parameter. An item with an unknown kind
can be skipped since the length of the item is known from the size
field. The recipient of an item with an unknown kind
MUST NOT try to interpret or modify the contents of the item in any way.
END
:0
SYSCALL
:1
GDBCALL
:2
ENARXCALL
:3
An END
item MUST have a size
of 0
. It has no contents and simply marks the end of items in the block. This communicates the end of the items list to the host. However, the guest MUST NOT rely on the presence of a terminator upon return to the guest.
A SYSCALL
item has the following contents:
nmbr
:usize
- the system call numberarg0
:usize
- the first argumentarg1
:usize
- the second argumentarg2
:usize
- the third argumentarg3
:usize
- the fourth argumentarg4
:usize
- the fifth argumentarg5
:usize
- the sixth argumentret0
:usize
- the first return valueret1
:usize
- the second return valuedata
:...
- data that can be referenced (optional)
A GDBCALL
item has the following contents:
nmbr
:usize
- the GDB call numberarg0
:usize
- the first argumentarg1
:usize
- the second argumentarg2
:usize
- the third argumentarg3
:usize
- the fourth argumentret
:usize
- the return valuedata
:...
- data that can be referenced (optional)
A ENARXCALL
item has the following contents:
nmbr
:usize
- the Enarx call numberarg0
:usize
- the first argumentarg1
:usize
- the second argumentarg2
:usize
- the third argumentarg3
:usize
- the fourth argumentret
:usize
- the return valuedata
:...
- data that can be referenced (optional)
The argument values may contain numeric values. However, all pointers MUST be translated to an offset from the beginning of the data section.
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 allocates space for an item header, syscall number, six arguments, two return values, as many bytes that the workload wants to write as fits in the block and an
END
item header. - The shim writes the item header, argument values and 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 writes to the allocated section. In the case of the
write
syscall, the shim:- Writes the item header with item
kind
set toSyscall
and size equal to 9 + count of allocated bytes to write (syscall number + arguments + return values + data length). - Writes the request
nmbr
equal to the Linux integral value forSYS_write
. - Writes the syscall arguments and return values:
arg0
= The file descriptor to write to.arg1
= The offset starting after the last return value where the bytes have been copied to.arg2
= The number of bytes that thewrite
syscall should emit from the bytes pointed to in the second parameter.arg3
= [NULL
]arg4
= [NULL
]arg5
= [NULL
]ret0
=-ENOSYS
ret1
=0
- Copies the bytes to write into the allocated section.
- Writes the item header with item
- 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.
- Once the syscall is complete, the host-side Enarx code can update the syscall return value section write the syscall return code to it.
- The host-side Enarx code returns control to the shim.
- The shim examines the block and propagates any mutated data back to the protected address space. It may then return control to its workload.
License: Apache-2.0