From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754278AbdCHSuS (ORCPT ); Wed, 8 Mar 2017 13:50:18 -0500 Received: from mail.kernel.org ([198.145.29.136]:49168 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751160AbdCHStw (ORCPT ); Wed, 8 Mar 2017 13:49:52 -0500 MIME-Version: 1.0 From: Andy Lutomirski Date: Wed, 8 Mar 2017 10:48:33 -0800 X-Gmail-Original-Message-ID: Message-ID: Subject: SGX notes from KS/LPC To: intel-sgx-kernel-dev@ml01.01.org Cc: Jethro Beekman , Josh Triplett , "linux-kernel@vger.kernel.org" , X86 ML , Borislav Petkov , Jarkko Sakkinen Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi- Here are my notes on SGX issues from KS/LPC. It seems that I never emailed it out to a public list -- oops. It may contain any number of typos or outright errors. +++ cut here +++ === Background and terminology === An enclave is an SGX enclave. Once launched, unless the enclave is explicitly debuggable, the enclave's data cannot be seen by the OS. An "ordinary enclave" is an enclave without the PROVISIONKEY, EINITTOKENKEY, or any reserved attributes set. I expect the vast majority of enclaves developed by ISVs to be ordinary enclaves. A "special enclave" is any enclave that isn't an ordinary enclave. A "launch enclave" is a special enclave that has EINITTOKENKEY set. Launch enclaves are unusual in that a launch enclave can *only* be run if it is signed by the private key associated with SGXLEPUBKEYHASH -- a launch enclave cannot chain to another launch enclave by creating an EINITTOKEN authorizing it. (I'm not sure why this is the case, but that's what the SDM says.) "Flexible launch control" is the Intel feature that adds SGXLEPUBKEYHASH. === Goals for upstream Linux SGX support === I consider the following to be fairly strong requirements: * Linux SGX support should be useful to normal people. This means that it should be convenient for developers to create, run, and distribute enclaves and to recompile and use other developers' enclaves. Doing so should not require paying a fee or signing a contract in the general case. There must not be any conditions incompatible with the use of open source enclaves. * System owners, admins, distributions, and designers of embedded systems should be able to apply reasonable policies that restrict what enclaves may be run on their systems. * Software should be portable across systems to a reasonable extent. This means that software should run on any machine with the appropriate hardware and kernel as long as that machine's policy permits the software to work. In the context of SGX with flexible launch control, it should be at least inconvenient and maybe even impossible for an ISV to ship software signed by a particular launch enclave such that an end user cannot run the software without trusting the launch enclave. See below. === Recommendations === Linux should not support SGX on non-flexible-launch-control systems except as outlined below. As it stands, it is impossible to write a Linux SGX driver that can be used in any meaningful way by open source developers. I doubt that any upstream maintainers are willing to participate in the existing licensing process. I am certainly not willing to participate on my own behalf. On flexible launch control systems, SGX should be supported, but I think that the existing proposed API workflow for loading an enclave should change. I'll call the current proposal "user-provided EINITTOKEN". It works like this: A user program bundles a launch enclave and asks the kernel to launch it. Then the user program asks the launch enclave to generate an EINITTOKEN for the normal enclave it wants to use. If the launch enclave approves the request, it gives the user program an EINITTOKEN. Then the user program asks the kernel to launch the normal enclave and supplies the EINITTOKEN to the kernel. The kernel launches the enclave. I suggest an alternative that I'll call "kernel-provided EINITTOKEN". In this model, a user program supplies a normal enclave to the kernel and does *not* supply EINITTOKEN. The kernel applies its own policy, if any, to decide whether to accept the enclave. Here are some reasons that I think kernel-provided EINITTOKEN will work much better for Linux: * Portability: Suppose an ISV ships a program (e.g. Chrome) that bundles a normal enclave. That ISV will sign the enclave. If they want the enclave to run on a system using, say, Red Hat's launch policy, they'll arrange for Red Hat to accept their signing key. Under the user-provided EINITTOKEN model, they will ship a Red Hat-provided launch enclave that accepts their key. They'll use this launch enclave at run tiem to generate their EINITTOKEN. This has major problems: * It may be incompatible with fully open-source software. If the ISV doesn't have the source to Red Hat's launch enclave, they are forced to bundle a binary blob and to give that blob access to their address space. (In the Red Hat example, I imagine that source would be available, but this nonetheless imposes an unpleasant auditing requirement on the ISV.) * It is non-portable. If a Debian user wants to run Chrome, they'll need to ensure that their system policy accepts Chrome's enclave. This is fine, but even if they do so, Chrome still won't work unless Debian or the user also accepts the Red Hat launch enclave that Chrome bundles. The user may not want to do this. I expect that distributions like Debian are unwilling to grant blanket trust to other vendors' launch enclaves. In the kernel-provided EINITTOKEN model, this is a non-issue: the launch enclave will be provided by the system and non-Red Hat users will simply provide a different launch enclave. * Performance: Imagine that a program like Chrome bundles an enclave. The first time any user runs Chrome, an EINITTOKEN will need to be generated. Once this happens, in the user-provided EINITTOKEN model, if a different user runs Chrome, they'll have to generate their own EINITTOKEN. In the kernel-provided EINITTOKEN model, the kernel can maintain a simple cache of EINITTOKENs and the second user's launch of Chrome can be faster. * Simplicity of SGXLEPUBKEYHASH handling: with user-provided EINITTOKEN, the kernel has to check that it considers the launch enclave's signer to be acceptable and update SGXLEPUBKEYHASH accordingly. Then, when the normal enclave is launched, the kernel needs to make sure that the correct SGXLEPUBKEYHASH is set so that the CPU will accept the EINITTOKEN. * Security: there is no hardware mechanism that guarantees EINITTOKEN freshness. This means that, if the kernel policy is changed by the system owner, old EINITTOKENs are still accepted by the hardware. As a result, for kernel policy to work properly, the kernel cannot trust a user-provided EINITTOKEN as an indication that an enclave is acceptable. * Flexibility: the kernel may want to enforce policies that are not directly enforceable by launch enclaves. For example, different users may be granted permission to use different sets of enclaves. Alternatively, the kernel may want to revoke permission to use certain enclaves. As a practical matter, this means that the kernel may need to enforce its own policy when the user asks it to do EINIT, which means that the kernel needs to do most of the work anyway. I'm inclined to suggest that normal users not be permitted to run launch enclaves directly, mainly because, in the kernel-provided EINITTOKEN model, I don't see the point. If users can do this, they might do it by rote even if they don't need to, this breaking portability. I think that, in the first version at least, only root should be able to run provisioning enclaves. This is because I don't fully understand the provisioning workflow and because there are potential privacy implications to allowing unprivileged users to obtain a provisioning key. I think that the kernel should reject enclaves that have reserved attributes set. I don't see how the driver could handle such enclaves correctly without knowing their semantics. (For example, an enclave with the EINITTOKEN attribute set is launched differently from other enclaves.) Since it's currently quite awkward for the kernel to run CPL3 code, which it would need to do to easily invoke a launch enclave, I hereby volunteer to make it possible for the kernel to do this. === Virtualization considerations === At some point, someone will need to decide what restrictions if any KVM should impose on its guests' use of SGX. For example, should KVM limit the set of SGXLEPUBKEYHASH values that its guests can use? Should KVM intercept EINIT and filter enclaves directly? === Support for non-flexible-launch-control CPUs (e.g. Skylake) === If there's a way to make Skylake work similarly to flexible launch control systems under a kernel-provided EINITTOKEN model, I think that such a mechanism could be acceptable upstream. For example, if Intel provided a signed enclave that could be distributed in linux-firmware.git that would allow the kernel to enforce its own launch policy and generate the requisite EINITTOKEN values in a comparably flexible and unrestrictive manner, I can see this being acceptable upstream. I'm not sure that upstream would want to support this on CPUs that are capable of flexible launch control but have it locked by firmware. I think we want to very strongly discourage firmware from locking the SGXLEPUBKEYHASH registers. === Launch policies that the kernel should provide === The kernel's launch policy should be configurable by some reasonable means. One of the options should be "launch any normal enclave". Another should probably be "accept launch enclaves provided by root (e.g. in /lib/firmware) that match one of the following SGXLEPUBKEYHASH values). I can imagine use cases for another policy like "launch the following enclaves, listed by hash". === A security flaw that Intel should seriously consider fixing === SGX, as presently designed, has what I consider to be a significant design flaw that is relevant in multi-tenant installations. Specifically, suppose a single cloud CPU hosts VMs from two unrelated tenants, A and B. A uses SGX to protect its data. If B is able to obtain a dump of A's storage, B may obtain an enclave that belongs to A along with data sealed by that enclave. While B cannot directly unseal A's data, there is no existing mechanism that can usefully prevent B from running A's enclave and using that enclave's API to manipulate A's data. This could be mitigated in future SGX revisions by adding an additional personalization parameter to EINIT. This parameter would be mixed in to the SGX key derivation process such that enclaves initialized using different personalization keys would obtain different outputs from EGETKEY. A hypervisor would trap EINIT, replace the personalization key with KDF(guest's requested personalization key, tenant-specific personalization secret). The result would be that one tenant on a machine would be unable to use another tenant's enclaves unless the hypervisor were compromised.