diff mbox series

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

Message ID 20191009044241.3591-4-sean.j.christopherson@intel.com (mailing list archive)
State New, archived
Headers show
Series x86/sgx: Improve add pages ioctl | expand

Commit Message

Sean Christopherson Oct. 9, 2019, 4:42 a.m. UTC
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@intel.com>
---
 arch/x86/include/uapi/asm/sgx.h | 16 ++++----
 arch/x86/kernel/cpu/sgx/ioctl.c | 68 +++++++++++++++++++++++++--------
 2 files changed, 61 insertions(+), 23 deletions(-)

Comments

Jarkko Sakkinen Oct. 14, 2019, 9:32 p.m. UTC | #1
On Tue, Oct 08, 2019 at 09:42:37PM -0700, Sean Christopherson wrote:
> 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@intel.com>

Please provide a more robust API. Now you decrease the robustness.

E.g.

struct sgx_enclave_add_page_desc {
        __u64   offset;
        __u16   mrmask;
        __u8    reserved[6];
};

struct sgx_enclave_add_page {
        __u64   src;
        __u64   secinfo;
        __u64   nr_pages;
        __u64   pages;
};

/Jarkko
Jarkko Sakkinen Oct. 14, 2019, 9:35 p.m. UTC | #2
On Tue, Oct 15, 2019 at 12:32:55AM +0300, Jarkko Sakkinen wrote:
> On Tue, Oct 08, 2019 at 09:42:37PM -0700, Sean Christopherson wrote:
> > 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@intel.com>
> 
> Please provide a more robust API. Now you decrease the robustness.
> 
> E.g.
> 
> struct sgx_enclave_add_page_desc {
>         __u64   offset;
>         __u16   mrmask;
>         __u8    reserved[6];
> };
> 
> struct sgx_enclave_add_page {
>         __u64   src;
>         __u64   secinfo;
>         __u64   nr_pages;
>         __u64   pages;
> };

If you want to decrease robustness, this would need to be taken as part
of v23 review. It is too big design change to managed like this. I'm
not opionated here. This is just wrong order of doing things.

/Jarkko
Sean Christopherson Oct. 14, 2019, 11:31 p.m. UTC | #3
On Tue, Oct 15, 2019 at 12:35:46AM +0300, Jarkko Sakkinen wrote:
> On Tue, Oct 15, 2019 at 12:32:55AM +0300, Jarkko Sakkinen wrote:
> > On Tue, Oct 08, 2019 at 09:42:37PM -0700, Sean Christopherson wrote:
> > > 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@intel.com>
> > 
> > Please provide a more robust API. Now you decrease the robustness.
> > 
> > E.g.
> > 
> > struct sgx_enclave_add_page_desc {
> >         __u64   offset;
> >         __u16   mrmask;
> >         __u8    reserved[6];
> > };
> > 
> > struct sgx_enclave_add_page {
> >         __u64   src;
> >         __u64   secinfo;
> >         __u64   nr_pages;
> >         __u64   pages;
> > };
> 
> If you want to decrease robustness, this would need to be taken as part
> of v23 review. It is too big design change to managed like this. I'm
> not opionated here. This is just wrong order of doing things.

I don't mind taking this to v23 review, but what do you mean by robustness
in this context?
Jarkko Sakkinen Oct. 16, 2019, 10:17 a.m. UTC | #4
On Mon, Oct 14, 2019 at 04:31:28PM -0700, Sean Christopherson wrote:
> I don't mind taking this to v23 review, but what do you mean by robustness
> in this context?

I think I kind of got this together API-wise:

#define SGX_ENCLAVE_ADD_PAGES_MEASURE 1

struct sgx_enclave_add_pages {
	__u64 src;
	__u64 offset;
	__u64 length;
	__u64 secinfo;
};

Length can be anything as long as low 8 bits are zero. The area
defined by offset and length is measured when
SGX_ENCLAVE_ADD_PAGES_MEASURE is set to 1.

I think this is the most sane API so far and does fulfill Jethro's
concerns why he originally wanted mrmask. I think this what most
users would find the most intuitive API.

Jethro, do you think you could live with this?

/Jarkko
Jarkko Sakkinen Oct. 16, 2019, 10:19 a.m. UTC | #5
On Wed, Oct 16, 2019 at 01:17:23PM +0300, Jarkko Sakkinen wrote:
> On Mon, Oct 14, 2019 at 04:31:28PM -0700, Sean Christopherson wrote:
> > I don't mind taking this to v23 review, but what do you mean by robustness
> > in this context?
> 
> I think I kind of got this together API-wise:
> 
> #define SGX_ENCLAVE_ADD_PAGES_MEASURE 1
> 
> struct sgx_enclave_add_pages {
> 	__u64 src;
> 	__u64 offset;
> 	__u64 length;
> 	__u64 secinfo;
> };
> 
> Length can be anything as long as low 8 bits are zero. The area
> defined by offset and length is measured when
> SGX_ENCLAVE_ADD_PAGES_MEASURE is set to 1.
> 
> I think this is the most sane API so far and does fulfill Jethro's
> concerns why he originally wanted mrmask. I think this what most
> users would find the most intuitive API.
> 
> Jethro, do you think you could live with this?

This just a version of Sean's API but with sane defaults for mrmask.

/Jarkko
Jarkko Sakkinen Oct. 16, 2019, 10:29 a.m. UTC | #6
On Wed, Oct 16, 2019 at 01:19:56PM +0300, Jarkko Sakkinen wrote:
> On Wed, Oct 16, 2019 at 01:17:23PM +0300, Jarkko Sakkinen wrote:
> > On Mon, Oct 14, 2019 at 04:31:28PM -0700, Sean Christopherson wrote:
> > > I don't mind taking this to v23 review, but what do you mean by robustness
> > > in this context?
> > 
> > I think I kind of got this together API-wise:
> > 
> > #define SGX_ENCLAVE_ADD_PAGES_MEASURE 1
> > 
> > struct sgx_enclave_add_pages {
> > 	__u64 src;
> > 	__u64 offset;
> > 	__u64 length;
> > 	__u64 secinfo;
> > };
> > 
> > Length can be anything as long as low 8 bits are zero. The area
> > defined by offset and length is measured when
> > SGX_ENCLAVE_ADD_PAGES_MEASURE is set to 1.
> > 
> > I think this is the most sane API so far and does fulfill Jethro's
> > concerns why he originally wanted mrmask. I think this what most
> > users would find the most intuitive API.
> > 
> > Jethro, do you think you could live with this?
> 
> This just a version of Sean's API but with sane defaults for mrmask.

Now that mrmask is rendered out the general idea of defining continuous
regions rather than scattered arrays of descriptors is superior. And it
is also obvious that a single page ioctl would be ugly glitch even if it
wouldn't cause harm.

/Jarkko
Jarkko Sakkinen Oct. 21, 2019, 11:24 a.m. UTC | #7
On Wed, Oct 16, 2019 at 01:29:12PM +0300, Jarkko Sakkinen wrote:
> On Wed, Oct 16, 2019 at 01:19:56PM +0300, Jarkko Sakkinen wrote:
> > On Wed, Oct 16, 2019 at 01:17:23PM +0300, Jarkko Sakkinen wrote:
> > > On Mon, Oct 14, 2019 at 04:31:28PM -0700, Sean Christopherson wrote:
> > > > I don't mind taking this to v23 review, but what do you mean by robustness
> > > > in this context?
> > > 
> > > I think I kind of got this together API-wise:
> > > 
> > > #define SGX_ENCLAVE_ADD_PAGES_MEASURE 1
> > > 
> > > struct sgx_enclave_add_pages {
> > > 	__u64 src;
> > > 	__u64 offset;
> > > 	__u64 length;
> > > 	__u64 secinfo;
> > > };

Offset would be split as 48:8:8 aka PAGE_INDEX:MRSTART:FLAGS
Length would be split as 48:8:8 aka NR_PAGES:MREND:0

Forgot from my earlier description that measurement starting
point would better to be also after the page start but with
this bit presentation everything can be cleanly described.

/Jarkko
diff mbox series

Patch

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);