[RFC PATCH v4 10/12] security/selinux: Add enclave_load() implementation
Stephen Smalley
sds at tycho.nsa.gov
Tue Jun 25 20:34:41 UTC 2019
On 6/19/19 6:23 PM, Sean Christopherson wrote:
> The goal of selinux_enclave_load() is to provide a facsimile of the
> existing selinux_file_mprotect() and file_map_prot_check() policies,
> but tailored to the unique properties of SGX.
>
> For example, an enclave page is technically backed by a MAP_SHARED file,
> but the "file" is essentially shared memory that is never persisted
> anywhere and also requires execute permissions (for some pages).
>
> Enclaves are also less priveleged than normal user code, e.g. SYSCALL
> instructions #UD if attempted in an enclave. For this reason, add SGX
> specific permissions instead of reusing existing permissions such as
> FILE__EXECUTE so that policies can allow running code in an enclave, or
> allow dynamically loading code in an enclave without having to grant the
> same capability to normal user code outside of the enclave.
>
> Intended use of each permission:
>
> - SGX_EXECDIRTY: dynamically load code within the enclave itself
> - SGX_EXECUNMR: load unmeasured code into the enclave, e.g. Graphene
> - SGX_EXECANON: load code from anonymous memory (likely Graphene)
> - SGX_EXECUTE: load an enclave from a file, i.e. normal behavior
>
> Note, equivalents to FILE__READ and FILE__WRITE are intentionally never
> required. Writes to the enclave page are contained to the EPC, i.e.
> never hit the original file, and read permissions have already been
> vetted (or the VMA doesn't have PROT_READ, in which case loading the
> page into the enclave will fail).
>
> Signed-off-by: Sean Christopherson <sean.j.christopherson at intel.com>
> ---
> security/selinux/hooks.c | 55 +++++++++++++++++++++++++++--
> security/selinux/include/classmap.h | 5 +--
> 2 files changed, 55 insertions(+), 5 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index fc239e541b62..8a431168e454 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -6727,6 +6727,12 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
> #endif
>
> #ifdef CONFIG_INTEL_SGX
> +static inline int sgx_has_perm(u32 sid, u32 requested)
> +{
> + return avc_has_perm(&selinux_state, sid, sid,
> + SECCLASS_PROCESS2, requested, NULL);
> +}
> +
> static int selinux_enclave_map(unsigned long prot)
> {
> const struct cred *cred = current_cred();
> @@ -6736,11 +6742,53 @@ static int selinux_enclave_map(unsigned long prot)
> WARN_ON_ONCE(!default_noexec);
>
> if ((prot & PROT_EXEC) && (prot & PROT_WRITE))
> - return avc_has_perm(&selinux_state, sid, sid,
> - SECCLASS_PROCESS2, PROCESS2__SGX_MAPWX,
> - NULL);
> + return sgx_has_perm(sid, PROCESS2__SGX_MAPWX);
> +
> return 0;
> }
> +
> +static int selinux_enclave_load(struct vm_area_struct *vma, unsigned long prot,
> + bool measured)
> +{
> + const struct cred *cred = current_cred();
> + u32 sid = cred_sid(cred);
> + int ret;
> +
> + /* SGX is supported only in 64-bit kernels. */
> + WARN_ON_ONCE(!default_noexec);
> +
> + /* Only executable enclave pages are restricted in any way. */
> + if (!(prot & PROT_EXEC))
> + return 0;
> +
> + /*
> + * WX at load time only requires EXECDIRTY, e.g. to allow W->X. Actual
> + * WX mappings require MAPWX (see selinux_enclave_map()).
> + */
> + if (prot & PROT_WRITE) {
> + ret = sgx_has_perm(sid, PROCESS2__SGX_EXECDIRTY);
> + if (ret)
> + goto out;
> + }
> + if (!measured) {
> + ret = sgx_has_perm(sid, PROCESS2__SGX_EXECUNMR);
> + if (ret)
> + goto out;
> + }
> +
> + if (!vma->vm_file || IS_PRIVATE(file_inode(vma->vm_file)) ||
> + vma->anon_vma)
> + /*
> + * Loading enclave code from an anonymous mapping or from a
> + * modified private file mapping.
> + */
> + ret = sgx_has_perm(sid, PROCESS2__SGX_EXECANON);
> + else
> + /* Loading from a shared or unmodified private file mapping. */
> + ret = file_has_perm(cred, vma->vm_file, FILE__SGX_EXECUTE);
> +out:
> + return ret;
> +}
Same comment on this patch: we might want to generalize the permission
names in hopes of being able to reuse them in the future for similar
constructs on other architectures. SGX -> ENCLAVE throughout?
> #endif
>
> struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
> @@ -6988,6 +7036,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
>
> #ifdef CONFIG_INTEL_SGX
> LSM_HOOK_INIT(enclave_map, selinux_enclave_map),
> + LSM_HOOK_INIT(enclave_load, selinux_enclave_load),
> #endif
> };
>
> diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
> index cfd91e879bdf..baa1757be46a 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -7,7 +7,7 @@
>
> #define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
> "rename", "execute", "quotaon", "mounton", "audit_access", \
> - "open", "execmod"
> + "open", "execmod", "sgx_execute"
>
> #define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
> "listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
> @@ -52,7 +52,8 @@ struct security_class_mapping secclass_map[] = {
> "setsockcreate", "getrlimit", NULL } },
> { "process2",
> { "nnp_transition", "nosuid_transition",
> - "sgx_mapwx", NULL } },
> + "sgx_mapwx", "sgx_execdirty", "sgx_execanon", "sgx_execunmr",
> + NULL } },
> { "system",
> { "ipc_info", "syslog_read", "syslog_mod",
> "syslog_console", "module_request", "module_load", NULL } },
>
More information about the Linux-security-module-archive
mailing list