mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-02 16:44:59 +00:00
x86/sgx: Add SGX_IOC_ENCLAVE_CREATE
Add an ioctl() that performs the ECREATE function of the ENCLS instruction, which creates an SGX Enclave Control Structure (SECS). Although the SECS is an in-memory data structure, it is present in enclave memory and is not directly accessible by software. Co-developed-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> Tested-by: Jethro Beekman <jethro@fortanix.com> Link: https://lkml.kernel.org/r/20201112220135.165028-13-jarkko@kernel.org
This commit is contained in:
parent
3fe0778eda
commit
888d249117
@ -323,6 +323,7 @@ Code Seq# Include File Comments
|
|||||||
<mailto:tlewis@mindspring.com>
|
<mailto:tlewis@mindspring.com>
|
||||||
0xA3 90-9F linux/dtlk.h
|
0xA3 90-9F linux/dtlk.h
|
||||||
0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
|
0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
|
||||||
|
0xA4 00-1F uapi/asm/sgx.h <mailto:linux-sgx@vger.kernel.org>
|
||||||
0xAA 00-3F linux/uapi/linux/userfaultfd.h
|
0xAA 00-3F linux/uapi/linux/userfaultfd.h
|
||||||
0xAB 00-1F linux/nbd.h
|
0xAB 00-1F linux/nbd.h
|
||||||
0xAC 00-1F linux/raw.h
|
0xAC 00-1F linux/raw.h
|
||||||
|
25
arch/x86/include/uapi/asm/sgx.h
Normal file
25
arch/x86/include/uapi/asm/sgx.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
|
/*
|
||||||
|
* Copyright(c) 2016-20 Intel Corporation.
|
||||||
|
*/
|
||||||
|
#ifndef _UAPI_ASM_X86_SGX_H
|
||||||
|
#define _UAPI_ASM_X86_SGX_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
|
#define SGX_MAGIC 0xA4
|
||||||
|
|
||||||
|
#define SGX_IOC_ENCLAVE_CREATE \
|
||||||
|
_IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sgx_enclave_create - parameter structure for the
|
||||||
|
* %SGX_IOC_ENCLAVE_CREATE ioctl
|
||||||
|
* @src: address for the SECS page data
|
||||||
|
*/
|
||||||
|
struct sgx_enclave_create {
|
||||||
|
__u64 src;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_X86_SGX_H */
|
@ -1,4 +1,5 @@
|
|||||||
obj-y += \
|
obj-y += \
|
||||||
driver.o \
|
driver.o \
|
||||||
encl.o \
|
encl.o \
|
||||||
|
ioctl.o \
|
||||||
main.o
|
main.o
|
||||||
|
@ -88,10 +88,22 @@ static unsigned long sgx_get_unmapped_area(struct file *file,
|
|||||||
return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
|
return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
|
||||||
|
unsigned long arg)
|
||||||
|
{
|
||||||
|
return sgx_ioctl(filep, cmd, arg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct file_operations sgx_encl_fops = {
|
static const struct file_operations sgx_encl_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = sgx_open,
|
.open = sgx_open,
|
||||||
.release = sgx_release,
|
.release = sgx_release,
|
||||||
|
.unlocked_ioctl = sgx_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sgx_compat_ioctl,
|
||||||
|
#endif
|
||||||
.mmap = sgx_mmap,
|
.mmap = sgx_mmap,
|
||||||
.get_unmapped_area = sgx_get_unmapped_area,
|
.get_unmapped_area = sgx_get_unmapped_area,
|
||||||
};
|
};
|
||||||
|
@ -9,8 +9,11 @@
|
|||||||
#include <linux/rwsem.h>
|
#include <linux/rwsem.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include <uapi/asm/sgx.h>
|
||||||
#include "sgx.h"
|
#include "sgx.h"
|
||||||
|
|
||||||
|
long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||||
|
|
||||||
int sgx_drv_init(void);
|
int sgx_drv_init(void);
|
||||||
|
|
||||||
#endif /* __ARCH_X86_SGX_DRIVER_H__ */
|
#endif /* __ARCH_X86_SGX_DRIVER_H__ */
|
||||||
|
@ -46,6 +46,7 @@ static vm_fault_t sgx_vma_fault(struct vm_fault *vmf)
|
|||||||
struct sgx_encl_page *entry;
|
struct sgx_encl_page *entry;
|
||||||
unsigned long phys_addr;
|
unsigned long phys_addr;
|
||||||
struct sgx_encl *encl;
|
struct sgx_encl *encl;
|
||||||
|
unsigned long pfn;
|
||||||
vm_fault_t ret;
|
vm_fault_t ret;
|
||||||
|
|
||||||
encl = vma->vm_private_data;
|
encl = vma->vm_private_data;
|
||||||
@ -61,6 +62,13 @@ static vm_fault_t sgx_vma_fault(struct vm_fault *vmf)
|
|||||||
|
|
||||||
phys_addr = sgx_get_epc_phys_addr(entry->epc_page);
|
phys_addr = sgx_get_epc_phys_addr(entry->epc_page);
|
||||||
|
|
||||||
|
/* Check if another thread got here first to insert the PTE. */
|
||||||
|
if (!follow_pfn(vma, addr, &pfn)) {
|
||||||
|
mutex_unlock(&encl->lock);
|
||||||
|
|
||||||
|
return VM_FAULT_NOPAGE;
|
||||||
|
}
|
||||||
|
|
||||||
ret = vmf_insert_pfn(vma, addr, PFN_DOWN(phys_addr));
|
ret = vmf_insert_pfn(vma, addr, PFN_DOWN(phys_addr));
|
||||||
if (ret != VM_FAULT_NOPAGE) {
|
if (ret != VM_FAULT_NOPAGE) {
|
||||||
mutex_unlock(&encl->lock);
|
mutex_unlock(&encl->lock);
|
||||||
|
@ -26,9 +26,16 @@ struct sgx_encl_page {
|
|||||||
struct sgx_encl *encl;
|
struct sgx_encl *encl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum sgx_encl_flags {
|
||||||
|
SGX_ENCL_IOCTL = BIT(0),
|
||||||
|
SGX_ENCL_DEBUG = BIT(1),
|
||||||
|
SGX_ENCL_CREATED = BIT(2),
|
||||||
|
};
|
||||||
|
|
||||||
struct sgx_encl {
|
struct sgx_encl {
|
||||||
unsigned long base;
|
unsigned long base;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
unsigned long flags;
|
||||||
unsigned int page_cnt;
|
unsigned int page_cnt;
|
||||||
unsigned int secs_child_cnt;
|
unsigned int secs_child_cnt;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
123
arch/x86/kernel/cpu/sgx/ioctl.c
Normal file
123
arch/x86/kernel/cpu/sgx/ioctl.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Copyright(c) 2016-20 Intel Corporation. */
|
||||||
|
|
||||||
|
#include <asm/mman.h>
|
||||||
|
#include <linux/mman.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/hashtable.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/ratelimit.h>
|
||||||
|
#include <linux/sched/signal.h>
|
||||||
|
#include <linux/shmem_fs.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
#include "driver.h"
|
||||||
|
#include "encl.h"
|
||||||
|
#include "encls.h"
|
||||||
|
|
||||||
|
static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
|
||||||
|
{
|
||||||
|
struct sgx_epc_page *secs_epc;
|
||||||
|
struct sgx_pageinfo pginfo;
|
||||||
|
struct sgx_secinfo secinfo;
|
||||||
|
unsigned long encl_size;
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
/* The extra page goes to SECS. */
|
||||||
|
encl_size = secs->size + PAGE_SIZE;
|
||||||
|
|
||||||
|
secs_epc = __sgx_alloc_epc_page();
|
||||||
|
if (IS_ERR(secs_epc))
|
||||||
|
return PTR_ERR(secs_epc);
|
||||||
|
|
||||||
|
encl->secs.epc_page = secs_epc;
|
||||||
|
|
||||||
|
pginfo.addr = 0;
|
||||||
|
pginfo.contents = (unsigned long)secs;
|
||||||
|
pginfo.metadata = (unsigned long)&secinfo;
|
||||||
|
pginfo.secs = 0;
|
||||||
|
memset(&secinfo, 0, sizeof(secinfo));
|
||||||
|
|
||||||
|
ret = __ecreate((void *)&pginfo, sgx_get_epc_virt_addr(secs_epc));
|
||||||
|
if (ret) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secs->attributes & SGX_ATTR_DEBUG)
|
||||||
|
set_bit(SGX_ENCL_DEBUG, &encl->flags);
|
||||||
|
|
||||||
|
encl->secs.encl = encl;
|
||||||
|
encl->base = secs->base;
|
||||||
|
encl->size = secs->size;
|
||||||
|
|
||||||
|
/* Set only after completion, as encl->lock has not been taken. */
|
||||||
|
set_bit(SGX_ENCL_CREATED, &encl->flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
sgx_free_epc_page(encl->secs.epc_page);
|
||||||
|
encl->secs.epc_page = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sgx_ioc_enclave_create() - handler for %SGX_IOC_ENCLAVE_CREATE
|
||||||
|
* @encl: An enclave pointer.
|
||||||
|
* @arg: The ioctl argument.
|
||||||
|
*
|
||||||
|
* Allocate kernel data structures for the enclave and invoke ECREATE.
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* - 0: Success.
|
||||||
|
* - -EIO: ECREATE failed.
|
||||||
|
* - -errno: POSIX error.
|
||||||
|
*/
|
||||||
|
static long sgx_ioc_enclave_create(struct sgx_encl *encl, void __user *arg)
|
||||||
|
{
|
||||||
|
struct sgx_enclave_create create_arg;
|
||||||
|
void *secs;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (test_bit(SGX_ENCL_CREATED, &encl->flags))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (copy_from_user(&create_arg, arg, sizeof(create_arg)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
secs = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||||
|
if (!secs)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (copy_from_user(secs, (void __user *)create_arg.src, PAGE_SIZE))
|
||||||
|
ret = -EFAULT;
|
||||||
|
else
|
||||||
|
ret = sgx_encl_create(encl, secs);
|
||||||
|
|
||||||
|
kfree(secs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct sgx_encl *encl = filep->private_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (test_and_set_bit(SGX_ENCL_IOCTL, &encl->flags))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case SGX_IOC_ENCLAVE_CREATE:
|
||||||
|
ret = sgx_ioc_enclave_create(encl, (void __user *)arg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENOIOCTLCMD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_bit(SGX_ENCL_IOCTL, &encl->flags);
|
||||||
|
return ret;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user