Re: [PATCH 5/6] intel_sgx: driver documentation

From: Andy Lutomirski
Date: Thu May 05 2016 - 20:53:01 EST


On Thu, May 5, 2016 at 3:45 PM, Jarkko Sakkinen
<jarkko.sakkinen@xxxxxxxxxxxxxxx> wrote:
> On Mon, Apr 25, 2016 at 01:01:06PM -0700, Andy Lutomirski wrote:
>> On 04/25/2016 10:34 AM, Jarkko Sakkinen wrote:
>> >+SGX_IOCTL_ENCLAVE_INIT
>> >+
>> >+Initializes an enclave given by SIGSTRUCT and EINITTOKEN. Executes EINIT leaf
>> >+instruction that will check that the measurement matches the one SIGSTRUCT and
>> >+EINITTOKEN. EINITTOKEN is a data blob given by a special enclave called Launch
>> >+Enclave and it is signed with a CPU's Launch Key.
>> >
>>
>> Having thought about this for ten minutes, I have the following thought:
>>
>> I think that we should seriously consider not allowing user code to supply
>> EINITTOKEN at all. Here's why:
>>
>> 1. The nominal purpose of this thing is "launch control." I think that the
>> decision of whether to launch an enclave belongs in the kernel to the extent
>> that the kernel has the ability to control this.
>
> I'm not sure why you would want to do this especially when you can use
> your own key pair for launch control in future.

Here are my thoughts. There are a few ways the system (firmware, MSR,
and Intel policy) could be configured:

+++ status quo +++

Applications that ship enclaves come bundled with signatures and
possibly certificate chains. They call into some SDK API to request
launch permission. The SDK says "ok". Then the application asks the
SDK to launch it. It's entirely unclear to me how Intel distributes
the LE versions that make this work on Windows. I'm guessing they're
bundled in the SDK, but for all I know, they're in the kernel.

I think that Linux should possibly refuse to support this mode
upstream. If Linux were to support it, then it might actually match
ISV-expected behavior better if the LE was bundled with the kernel --
after all, the ISV already has very little visibility into where the
LE comes from, and it seems more like a system policy thing.

+++ current Skylakes with hypothetical Intel "launch anything" policy +++

If the combination of Intel policy and firmware configuration were to
allow anything to launch, then the OS should either impose its own
policy or allow anything to launch. I can easily imagine the
implementation of this involving a channel by which the kernel proves
to the LE that firmware/platform config is intended to allow "launch
anything". In this case, I think this belongs either in the kernel or
in a privileged daemon, and putting it in the kernel is probably much
more straightforward. In any event, applications shouldn't need to
worry about the nitty gritty details of where exactly their EINITTOKEN
comes from.

+++ future chips with unlocked IA32_SGXLEPUBKEYHASH +++

The firmware policy really is "launch anything" in this case, and it's
the kernel's job to restrict that further if it likes (by programming
the MSRs and/or filtering EINIT). I think that the most natural way
to implement this would be for the kernel to implement whatever policy
it likes and to either ship an LE that accepts anything as part of the
kernel image that's signed by a key where everyone knows the *private*
key or to generate a random key pair at build time, build the enclave
along with the kernel, and include the public key and the LE in the
kernel image. In either case, I don't think that apps should need to
ship this special LE -- the kernel should handle it.

If admins want to impose additional launch policy, then by all means
Linux should offer that. I'm just not at all convinced that fiddling
with the MSRs in new and complicated ways is the right way to do that
-- I think the kernel should implement more advanced policy by
filtering EINIT.

Keep in mind that, if the kernel is compromised, then the attacker can
launch anything no matter what the kernel tries to do because the
attacker controls the MSRs.

+++ future chips with IA32_SGXLEPUBKEYHASH set to a non-default value +++

I don't see a valid use case for this other than snake oil. One may
well exist, but, if so, it hasn't been explained to me. If someone
comes up with one, then, by all means, we could support it in the
kernel. Nonetheless, an SGX-aware app that is designed to work under
the status quo policy or in a "launch anything" regime should still
work if the special local policy intends for it to work, and I don't
think that app should need to possess a copy of the bespoke signed LE
in order to function. IOW, to allow the same app to run here if
policy is okay with it, I think we *have* to delegate EINITTOKEN
generation to something other than the SGX-using app.



My intuition is that either the Windows approach to this is going to
end up being a mess and very unpleasant for ISVs to work with or that
Windows will move to a configuration in which EINITTOKEN generation is
delegated to the kernel or to a privileged daemon that ships with the
OS. I think that Linux should do that as well to avoid
unpleasantness. If Linux ends up being easier to develop SGX
applications on than Windows, then that's means that Linux did
something right.

Also, in the unlocked-MSR case, I think that the kernel *must*
implement EINIT filtering. The kernel should not allow an untrusted
LE to run, because that LE might leak the raw EGETKEY output to a
malicious party, and the implications of that might not be so nice.
This is yet another argument in favor of having the kernel supply the
LE so that the kernel can trust the LE. (Obviously, extracting raw
*debug* EGETKEY output is possible even on Windows on current systems,
but that raw output isn't particularly useful.)

>
> This would degrade the security of the SGX to the level of the running
> kernel binary.

How so? SGX is supposed to be secure even under the assumption that
anyone can launch anything they want and even under the assumption
that the kernel is malicious. If SGX fails at that, then it would be
odd to blame kernel policy for that.


--Andy