Hi Jarkko
On Sun, 13 Mar 2022 21:58:51 -0500, Jarkko Sakkinen <jarkko@xxxxxxxxxx>
wrote:
On Mon, Mar 14, 2022 at 04:50:56AM +0200, Jarkko Sakkinen wrote:
On Mon, Mar 14, 2022 at 04:49:37AM +0200, Jarkko Sakkinen wrote:
> On Fri, Mar 11, 2022 at 09:53:29AM -0800, Reinette Chatre wrote:
>
> > I saw Haitao's note that EMODPE requires "Read access permitted by
enclave".
> > This motivates that EMODPR->PROT_NONE should not be allowed since
it would
> > not be possible to relax permissions (run EMODPE) after that. Even
so, I
> > also found in the SDM that EACCEPT has the note "Read access
permitted
> > by enclave". That seems to indicate that EMODPR->PROT_NONE is not
practical
> > from that perspective either since the enclave will not be able to
> > EACCEPT the change. Does that match your understanding?
>
> Yes, PROT_NONE should not be allowed.
>
> This is however the real problem.
>
> The current kernel patch set has inconsistent API and EMODPR ioctl is
> simply unacceptable. It also requires more concurrency management
from
> user space run-time, which would be heck a lot easier to do in the
kernel.
>
> If you really want EMODPR as ioctl, then for consistencys sake, then
EAUG
> should be too. Like this when things go opposite directions, this
patch set
> plain and simply will not work out.
>
> I would pick EAUG's strategy from these two as it requires half the
back
> calls to host from an enclave. I.e. please combine mprotect() and
EMODPR,
> either in the #PF handler or as part of mprotect(), which ever suits
you
> best.
>
> I'll try demonstrate this with two examples.
>
> mmap() could go something like this() (simplified):
> 1. Execution #UD's to SYSCALL.
> 2. Host calls enclave's mmap() handler with mmap() parameters.
> 3. Enclave up-calls host's mmap().
> 4. Loops the range with EACCEPTCOPY.
>
> mprotect() has to be done like this:
> 1. Execution #UD's to SYSCALL.
> 2. Host calls enclave's mprotect() handler.
> 3. Enclave up-calls host's mprotect().
> 4. Enclave up-calls host's ioctl() to SGX_IOC_ENCLAVE_PERMISSIONS.
I assume up-calls here are ocalls as we call them in our implementation,
which are the calls enclave make to untrusted side via EEXIT.
If so, can your implementation combine this two up-calls into one, then
host side just do ioctl() and mprotect to kernel? If so, would that
address your concern about extra up-calls?
> 3. Loops the range with EACCEPT.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5. Loops the range with EACCEPT + EMODPE.
> This is just terrible IMHO. I hope these examples bring some insight.
E.g. in Enarx we have to add a special up-call (so called enarxcall in
intermediate that we call sallyport, which provides shared buffer to
communicate with the enclave) just for reseting the range with PROT_READ.
Feel very redundant, adds ugly cruft and is completely opposite strategy
to
what you've chosen to do with EAUG, which is I think correct choice as
far
as API is concerned.
The problem with EMODPR on #PF is that kernel needs to know what
permissions requested from enclave at the time of #PF. So enclave has to
make at least one call to kernel (again via ocall in our case, I assume
up-call in your case) to make the change.
Enclave runtime may not know the permissions until upper layer application
code (JIT or some kind of code loader) make the decision to change it. And
the ocalls/up-calls can only be done at that time, not upfront, like mmap
that is only used to reserve ranges.
I also see this model as consistent to what kernel does for regular memory
mappings: adding physical pages on #PF or pre-fault and changing PTE
permissions only after mprotect is called.
I would agree/prefer mprotect and the ioctl() for EMODPR be combined, but
Reinette pointed out some issues above on managing VMAs and handling
errors in that approach.
BR
Haitao