[PATCH for_v23 3/7] x86/sgx: Tweak ADD_PAGE ioctl to allow adding multiple pages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add a nr_pages param to the ioctl for adding pages to the enclave so
that userspace can batch multiple pages in a single syscall.  Update the
offset, src and nr_pages params prior to returning to userspace so that
the caller has sufficient information to analyze failures and can easily
restart the ioctl when appropriate.

Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
---
 arch/x86/include/uapi/asm/sgx.h | 16 ++++----
 arch/x86/kernel/cpu/sgx/ioctl.c | 68 +++++++++++++++++++++++++--------
 2 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
index 67583b046af1..84734229d8dd 100644
--- a/arch/x86/include/uapi/asm/sgx.h
+++ b/arch/x86/include/uapi/asm/sgx.h
@@ -12,8 +12,8 @@
 
 #define SGX_IOC_ENCLAVE_CREATE \
 	_IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create)
-#define SGX_IOC_ENCLAVE_ADD_PAGE \
-	_IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page)
+#define SGX_IOC_ENCLAVE_ADD_PAGES \
+	_IOWR(SGX_MAGIC, 0x01, struct sgx_enclave_add_pages)
 #define SGX_IOC_ENCLAVE_INIT \
 	_IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init)
 #define SGX_IOC_ENCLAVE_SET_ATTRIBUTE \
@@ -29,17 +29,19 @@ struct sgx_enclave_create  {
 };
 
 /**
- * struct sgx_enclave_add_page - parameter structure for the
- *                               %SGX_IOC_ENCLAVE_ADD_PAGE ioctl
- * @offset:	page offset within the enclave
- * @src:	address for the page data
+ * struct sgx_enclave_add_pages - parameter structure for the
+ *                                %SGX_IOC_ENCLAVE_ADD_PAGE ioctl
+ * @offset:	starting page offset within the ELRANGE
+ * @src:	start address for the page data
+ * @nr_pages:	number of pages to add to enclave
  * @secinfo:	address for the SECINFO data
  * @mrmask:	bitmask for the measured 256 byte chunks
  * @reserved:	reserved for future use
  */
-struct sgx_enclave_add_page {
+struct sgx_enclave_add_pages {
 	__u64	offset;
 	__u64	src;
+	__u64	nr_pages;
 	__u64	secinfo;
 	__u16	mrmask;
 	__u8	reserved[6];
diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
index f407dd35f9e3..4597dd8f5c91 100644
--- a/arch/x86/kernel/cpu/sgx/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -360,7 +360,7 @@ static int __sgx_encl_extend(struct sgx_encl *encl,
 }
 
 static int sgx_encl_add_page(struct sgx_encl *encl,
-			     struct sgx_enclave_add_page *addp,
+			     struct sgx_enclave_add_pages *addp,
 			     struct sgx_secinfo *secinfo)
 {
 	struct sgx_encl_page *encl_page;
@@ -443,14 +443,19 @@ static int sgx_encl_add_page(struct sgx_encl *encl,
 }
 
 /**
- * sgx_ioc_enclave_add_page() - The handler for %SGX_IOC_ENCLAVE_ADD_PAGE
- * @filep:	open file to /dev/sgx
- * @arg:	a user pointer to a struct sgx_enclave_add_page instance
+ * sgx_ioc_enclave_add_pages() - The handler for %SGX_IOC_ENCLAVE_ADD_PAGES
+ * @encl:       pointer to an enclave instance (via ioctl() file pointer)
+ * @arg:	a user pointer to a struct sgx_enclave_add_pages instance
  *
- * Add (EADD) a page to an uninitialized enclave, and optionally extend
- * (EEXTEND) the measurement with the contents of the page. A SECINFO for a TCS
- * is required to always contain zero permissions because CPU silently zeros
- * them. Allowing anything else would cause a mismatch in the measurement.
+ * Add (EADD) one or more pages to an uninitialized enclave, and optionally
+ * extend (EEXTEND) the measurement with the contents of the page. The range of
+ * pages must be virtually contiguous. The SECINFO and measurement mask are
+ * applied to all pages, i.e. pages with different properties must be added in
+ * separate calls.
+ *
+ * A SECINFO for a TCS is required to always contain zero permissions because
+ * CPU silently zeros them. Allowing anything else would cause a mismatch in
+ * the measurement.
  *
  * mmap()'s protection bits are capped by the page permissions. For each page
  * address, the maximum protection bits are computed with the following
@@ -467,17 +472,25 @@ static int sgx_encl_add_page(struct sgx_encl *encl,
  * permissions. In effect, this allows mmap() with PROT_NONE to be used to seek
  * an address range for the enclave that can be then populated into SECS.
  *
+ * @arg->addr, @arg->src and @arg->nr_pages are adjusted to reflect the
+ * remaining pages that need to be added to the enclave, e.g. userspace can
+ * re-invoke SGX_IOC_ENCLAVE_ADD_PAGES using the same struct in response to an
+ * ERESTARTSYS error.
+ *
  * Return:
  *   0 on success,
- *   -EINVAL if the SECINFO contains invalid data,
- *   -EACCES if the source page is located in a noexec partition,
+ *   -EINVAL if any input param or the SECINFO contains invalid data,
+ *   -EACCES if an executable source page is located in a noexec partition,
  *   -ENOMEM if any memory allocation, including EPC, fails,
+ *   -ERESTARTSYS if a pending signal is recognized,
  *   -errno otherwise
+
  */
-static long sgx_ioc_enclave_add_page(struct sgx_encl *encl, void __user *arg)
+static long sgx_ioc_enclave_add_pages(struct sgx_encl *encl, void __user *arg)
 {
-	struct sgx_enclave_add_page addp;
+	struct sgx_enclave_add_pages addp;
 	struct sgx_secinfo secinfo;
+	int ret;
 
 	if (!(atomic_read(&encl->flags) & SGX_ENCL_CREATED))
 		return -EINVAL;
@@ -489,7 +502,10 @@ static long sgx_ioc_enclave_add_page(struct sgx_encl *encl, void __user *arg)
 	    !IS_ALIGNED(addp.src, PAGE_SIZE))
 		return -EINVAL;
 
-	if (addp.offset >= encl->size)
+	if (!addp.nr_pages)
+		return -EINVAL;
+
+	if (addp.offset + ((addp.nr_pages - 1) * PAGE_SIZE) >= encl->size)
 		return -EINVAL;
 
 	if (copy_from_user(&secinfo, (void __user *)addp.secinfo,
@@ -499,7 +515,27 @@ static long sgx_ioc_enclave_add_page(struct sgx_encl *encl, void __user *arg)
 	if (sgx_validate_secinfo(&secinfo))
 		return -EINVAL;
 
-	return sgx_encl_add_page(encl, &addp, &secinfo);
+	for ( ; addp.nr_pages > 0; addp.nr_pages--) {
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		if (need_resched())
+			cond_resched();
+
+		ret = sgx_encl_add_page(encl, &addp, &secinfo);
+		if (ret)
+			break;
+
+		addp.offset += PAGE_SIZE;
+		addp.src += PAGE_SIZE;
+	}
+
+	if (copy_to_user(arg, &addp, sizeof(addp)))
+		return -EFAULT;
+
+	return ret;
 }
 
 static int __sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus,
@@ -702,8 +738,8 @@ long sgx_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 	case SGX_IOC_ENCLAVE_CREATE:
 		ret = sgx_ioc_enclave_create(encl, (void __user *)arg);
 		break;
-	case SGX_IOC_ENCLAVE_ADD_PAGE:
-		ret = sgx_ioc_enclave_add_page(encl, (void __user *)arg);
+	case SGX_IOC_ENCLAVE_ADD_PAGES:
+		ret = sgx_ioc_enclave_add_pages(encl, (void __user *)arg);
 		break;
 	case SGX_IOC_ENCLAVE_INIT:
 		ret = sgx_ioc_enclave_init(encl, (void __user *)arg);
-- 
2.22.0




[Index of Archives]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux