diff mbox series

[v38,17/24] x86/sgx: ptrace() support for the SGX driver

Message ID 20200915112842.897265-18-jarkko.sakkinen@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series Intel SGX foundations | expand

Commit Message

Jarkko Sakkinen Sept. 15, 2020, 11:28 a.m. UTC
Add VMA callbacks for ptrace() that can be used with debug enclaves.
With debug enclaves data can be read and write the memory word at a time
by using ENCLS(EDBGRD) and ENCLS(EDBGWR) leaf instructions.

Acked-by: Jethro Beekman <jethro@fortanix.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 arch/x86/kernel/cpu/sgx/encl.c | 87 ++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

Comments

Borislav Petkov Sept. 22, 2020, 3:44 p.m. UTC | #1
> Subject: Re: [PATCH v38 17/24] x86/sgx: ptrace() support for the SGX driver
			     ... x86/sgx: Add ptrace() support...

subject needs a verb.

On Tue, Sep 15, 2020 at 02:28:35PM +0300, Jarkko Sakkinen wrote:
> Add VMA callbacks for ptrace() that can be used with debug enclaves.
> With debug enclaves data can be read and write the memory word at a time

I think you wanna say here

"... data can be read and/or written a memory word at a time by using..."

> by using ENCLS(EDBGRD) and ENCLS(EDBGWR) leaf instructions.
> 
> Acked-by: Jethro Beekman <jethro@fortanix.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>  arch/x86/kernel/cpu/sgx/encl.c | 87 ++++++++++++++++++++++++++++++++++
>  1 file changed, 87 insertions(+)
> 
> diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
> index 11ec2df59b54..7f8df2c8ef35 100644
> --- a/arch/x86/kernel/cpu/sgx/encl.c
> +++ b/arch/x86/kernel/cpu/sgx/encl.c
> @@ -333,10 +333,97 @@ static int sgx_vma_mprotect(struct vm_area_struct *vma,
>  	return mprotect_fixup(vma, pprev, start, end, newflags);
>  }
>  
> +static int sgx_edbgrd(struct sgx_encl *encl, struct sgx_encl_page *page,
> +		      unsigned long addr, void *data)
> +{
> +	unsigned long offset = addr & ~PAGE_MASK;
> +	int ret;
> +
> +
> +	ret = __edbgrd(sgx_get_epc_addr(page->epc_page) + offset, data);
> +	if (ret)
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +static int sgx_edbgwr(struct sgx_encl *encl, struct sgx_encl_page *page,
> +		      unsigned long addr, void *data)
> +{
> +	unsigned long offset = addr & ~PAGE_MASK;
> +	int ret;
> +
> +	ret = __edbgwr(sgx_get_epc_addr(page->epc_page) + offset, data);
> +	if (ret)
> +		return -EIO;
> +
> +	return 0;
> +}

I know those are supposed to correspond to the ENCLS leafs but the
function names are totally unreadable. I guess you could name them

sgx_encl_dbg_read
sgx_encl_dbg_write

and leave the lowlevel helpers like the insn names.

> +static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr,
> +			  void *buf, int len, int write)
> +{
> +	struct sgx_encl *encl = vma->vm_private_data;
> +	struct sgx_encl_page *entry = NULL;
> +	char data[sizeof(unsigned long)];
> +	unsigned long align;
> +	unsigned int flags;
> +	int offset;
> +	int cnt;
> +	int ret = 0;
> +	int i;
> +
> +	/* If process was forked, VMA is still there but vm_private_data is set
> +	 * to NULL.
> +	 */

Kernel comments style is:

	/*
	 * A sentence ending with a full-stop.
	 * Another sentence. ...
	 * More sentences. ...
	 */

> +	if (!encl)
> +		return -EFAULT;
> +
> +	flags = atomic_read(&encl->flags);
> +
> +	if (!(flags & SGX_ENCL_DEBUG) || !(flags & SGX_ENCL_INITIALIZED) ||
> +	    (flags & SGX_ENCL_DEAD))
> +		return -EFAULT;
> +
> +	for (i = 0; i < len; i += cnt) {
> +		entry = sgx_encl_reserve_page(encl, (addr + i) & PAGE_MASK);
> +		if (IS_ERR(entry)) {
> +			ret = PTR_ERR(entry);
> +			break;
> +		}
> +
> +		align = ALIGN_DOWN(addr + i, sizeof(unsigned long));
> +		offset = (addr + i) & (sizeof(unsigned long) - 1);
> +		cnt = sizeof(unsigned long) - offset;
> +		cnt = min(cnt, len - i);
> +
> +		ret = sgx_edbgrd(encl, entry, align, data);
> +		if (ret)
> +			goto out;
> +
> +		if (write) {
> +			memcpy(data + offset, buf + i, cnt);
> +			ret = sgx_edbgwr(encl, entry, align, data);
> +			if (ret)
> +				goto out;
> +		} else

		} else {

> +			memcpy(buf + i, data + offset, cnt);

		}

Put the else branch in {} too.
Jarkko Sakkinen Sept. 23, 2020, 1:20 p.m. UTC | #2
On Tue, Sep 22, 2020 at 05:44:24PM +0200, Borislav Petkov wrote:
> 
> > Subject: Re: [PATCH v38 17/24] x86/sgx: ptrace() support for the SGX driver
> 			     ... x86/sgx: Add ptrace() support...
> 
> subject needs a verb.
> 
> On Tue, Sep 15, 2020 at 02:28:35PM +0300, Jarkko Sakkinen wrote:
> > Add VMA callbacks for ptrace() that can be used with debug enclaves.
> > With debug enclaves data can be read and write the memory word at a time
> 
> I think you wanna say here
> 
> "... data can be read and/or written a memory word at a time by using..."

I also fixed the other issues but I'll paste here the rewrite that I did
for the commit message:

"
x86/sgx: Add ptrace() support for the SGX driver

Intel Sofware Guard eXtensions (SGX) allows creation of executable blobs
called enclaves, which cannot be accessed by default when not executing
inside the enclave. Enclaves can be entered by only using predefined memory
addresses, which are defined the enclave is loaded.

However, enclaves can defined as debug enclaves during the load time. In
debug enclaves data can be read and/or written a memory word at a time by
using by using ENCLS[EDBGRD] and ENCLS[EDBGWR] leaf instructions.

Add 'access' implementation to vm_ops with the help of these functions.
This allows to use ptrace() with debug enclaves.
"

I also think that mm CC would make sense also for this patch.

/Jarkko
Borislav Petkov Sept. 23, 2020, 4:17 p.m. UTC | #3
On Wed, Sep 23, 2020 at 04:20:49PM +0300, Jarkko Sakkinen wrote:
> Intel Sofware Guard eXtensions (SGX) allows creation of executable blobs
> called enclaves, which cannot be accessed by default when not executing
> inside the enclave. Enclaves can be entered by only using predefined memory
> addresses, which are defined the enclave is loaded.
			      ^
			      "when" or "before". I think it is before.

> However, enclaves can defined as debug enclaves during the load time. In

"However, enclaves can be defined as debug enclaves at load time."

> debug enclaves data can be read and/or written a memory word at a time by
> using by using ENCLS[EDBGRD] and ENCLS[EDBGWR] leaf instructions.

only one "by using" is enough.

> Add 'access' implementation to vm_ops with the help of these functions.

"Add an ->access virtual MM function for accessing the enclave's memory... "
Jarkko Sakkinen Sept. 24, 2020, 11:51 a.m. UTC | #4
On Wed, Sep 23, 2020 at 06:17:33PM +0200, Borislav Petkov wrote:
> > Add 'access' implementation to vm_ops with the help of these functions.
> 
> "Add an ->access virtual MM function for accessing the enclave's memory... "

Thank you. I wrote the last paragraph like this:

"Add an '->access' virtual function for accessing the enclave's memory
to vm_ops by using these functions. This allows to use ptrace() with
debug enclaves."

> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette

/Jarkko
Borislav Petkov Sept. 24, 2020, 3:57 p.m. UTC | #5
On Thu, Sep 24, 2020 at 02:51:28PM +0300, Jarkko Sakkinen wrote:
> On Wed, Sep 23, 2020 at 06:17:33PM +0200, Borislav Petkov wrote:
> > > Add 'access' implementation to vm_ops with the help of these functions.
> > 
> > "Add an ->access virtual MM function for accessing the enclave's memory... "
> 
> Thank you. I wrote the last paragraph like this:
> 
> "Add an '->access' virtual function for accessing the enclave's memory
> to vm_ops by using these functions. This allows to use ptrace() with

"to vm_ops" must come after "function".

But lemme ask what is "vm_ops"?
Jarkko Sakkinen Sept. 24, 2020, 8:38 p.m. UTC | #6
On Thu, Sep 24, 2020 at 05:57:51PM +0200, Borislav Petkov wrote:
> On Thu, Sep 24, 2020 at 02:51:28PM +0300, Jarkko Sakkinen wrote:
> > On Wed, Sep 23, 2020 at 06:17:33PM +0200, Borislav Petkov wrote:
> > > > Add 'access' implementation to vm_ops with the help of these functions.
> > > 
> > > "Add an ->access virtual MM function for accessing the enclave's memory... "
> > 
> > Thank you. I wrote the last paragraph like this:
> > 
> > "Add an '->access' virtual function for accessing the enclave's memory
> > to vm_ops by using these functions. This allows to use ptrace() with
> 
> "to vm_ops" must come after "function".
> 
> But lemme ask what is "vm_ops"?

I assume this is a rethorical question and I notice what I suggested
looks as bad as my earlier commit message :-)

So, I gave it some thought that and decided to "open code" the paragraph
as

"Add sgx_vma_access() function that implements 'access' virtual function
of struct vm_operations_struct. Use formentioned leaf instructions to
achieve read and write primitives for the enclave memory."

I think this starts to have the right balance and is understandable.

Still open for futher suggestion of course.

> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette

/Jarkko
Jarkko Sakkinen Sept. 24, 2020, 8:40 p.m. UTC | #7
On Thu, Sep 24, 2020 at 11:39:07PM +0300, Jarkko Sakkinen wrote:
> On Thu, Sep 24, 2020 at 05:57:51PM +0200, Borislav Petkov wrote:
> > On Thu, Sep 24, 2020 at 02:51:28PM +0300, Jarkko Sakkinen wrote:
> > > On Wed, Sep 23, 2020 at 06:17:33PM +0200, Borislav Petkov wrote:
> > > > > Add 'access' implementation to vm_ops with the help of these functions.
> > > > 
> > > > "Add an ->access virtual MM function for accessing the enclave's memory... "
> > > 
> > > Thank you. I wrote the last paragraph like this:
> > > 
> > > "Add an '->access' virtual function for accessing the enclave's memory
> > > to vm_ops by using these functions. This allows to use ptrace() with
> > 
> > "to vm_ops" must come after "function".
> > 
> > But lemme ask what is "vm_ops"?
> 
> I assume this is a rethorical question and I notice what I suggested
> looks as bad as my earlier commit message :-)
> 
> So, I gave it some thought that and decided to "open code" the paragraph
> as
> 
> "Add sgx_vma_access() function that implements 'access' virtual function
> of struct vm_operations_struct. Use formentioned leaf instructions to
> achieve read and write primitives for the enclave memory."
> 
> I think this starts to have the right balance and is understandable.
> 
> Still open for futher suggestion of course.

I'm not sure if I said it already but I also added cc to linux-mm (same
CC's in the patch as with mprotect callback commit). This should also
have mm ack I think.

/Jarkko
Borislav Petkov Sept. 25, 2020, 7:51 a.m. UTC | #8
On Thu, Sep 24, 2020 at 11:38:59PM +0300, Jarkko Sakkinen wrote:
> I assume this is a rethorical question

Of course - our text should not be write-only.

> and I notice what I suggested
> looks as bad as my earlier commit message :-)
> 
> So, I gave it some thought that and decided to "open code" the paragraph
> as
> 
> "Add sgx_vma_access() function that implements 'access' virtual function
> of struct vm_operations_struct. Use formentioned leaf instructions to

"aforementioned"

> achieve read and write primitives for the enclave memory."

I'd say "to provide read and write access to enclave memory."
Borislav Petkov Sept. 25, 2020, 7:53 a.m. UTC | #9
On Thu, Sep 24, 2020 at 11:40:22PM +0300, Jarkko Sakkinen wrote:
> I'm not sure if I said it already but I also added cc to linux-mm (same
> CC's in the patch as with mprotect callback commit). This should also
> have mm ack I think.

Why? This is adding ptrace functionality to enclaves which is purely
arch/x86/.
Jarkko Sakkinen Sept. 25, 2020, 11 a.m. UTC | #10
On Fri, Sep 25, 2020 at 09:53:01AM +0200, Borislav Petkov wrote:
> On Thu, Sep 24, 2020 at 11:40:22PM +0300, Jarkko Sakkinen wrote:
> > I'm not sure if I said it already but I also added cc to linux-mm (same
> > CC's in the patch as with mprotect callback commit). This should also
> > have mm ack I think.
> 
> Why? This is adding ptrace functionality to enclaves which is purely
> arch/x86/.

You are right. No changes to vm_operations_struct itself.

> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette

/Jarkko
Jarkko Sakkinen Sept. 25, 2020, 11:21 a.m. UTC | #11
On Fri, Sep 25, 2020 at 09:51:04AM +0200, Borislav Petkov wrote:
> On Thu, Sep 24, 2020 at 11:38:59PM +0300, Jarkko Sakkinen wrote:
> > I assume this is a rethorical question
> 
> Of course - our text should not be write-only.
> 
> > and I notice what I suggested
> > looks as bad as my earlier commit message :-)
> > 
> > So, I gave it some thought that and decided to "open code" the paragraph
> > as
> > 
> > "Add sgx_vma_access() function that implements 'access' virtual function
> > of struct vm_operations_struct. Use formentioned leaf instructions to
> 
> "aforementioned"

Ugh, that the was worst spelling I've done for a while.

> > achieve read and write primitives for the enclave memory."
> 
> I'd say "to provide read and write access to enclave memory."

Sound better yes, thanks.

> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette

Updated the commit message accordingly. I also rebased now to x86
tip (and yes, merge conflicts were trivial to sort out).

/Jarkko
diff mbox series

Patch

diff --git a/arch/x86/kernel/cpu/sgx/encl.c b/arch/x86/kernel/cpu/sgx/encl.c
index 11ec2df59b54..7f8df2c8ef35 100644
--- a/arch/x86/kernel/cpu/sgx/encl.c
+++ b/arch/x86/kernel/cpu/sgx/encl.c
@@ -333,10 +333,97 @@  static int sgx_vma_mprotect(struct vm_area_struct *vma,
 	return mprotect_fixup(vma, pprev, start, end, newflags);
 }
 
+static int sgx_edbgrd(struct sgx_encl *encl, struct sgx_encl_page *page,
+		      unsigned long addr, void *data)
+{
+	unsigned long offset = addr & ~PAGE_MASK;
+	int ret;
+
+
+	ret = __edbgrd(sgx_get_epc_addr(page->epc_page) + offset, data);
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
+static int sgx_edbgwr(struct sgx_encl *encl, struct sgx_encl_page *page,
+		      unsigned long addr, void *data)
+{
+	unsigned long offset = addr & ~PAGE_MASK;
+	int ret;
+
+	ret = __edbgwr(sgx_get_epc_addr(page->epc_page) + offset, data);
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
+static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr,
+			  void *buf, int len, int write)
+{
+	struct sgx_encl *encl = vma->vm_private_data;
+	struct sgx_encl_page *entry = NULL;
+	char data[sizeof(unsigned long)];
+	unsigned long align;
+	unsigned int flags;
+	int offset;
+	int cnt;
+	int ret = 0;
+	int i;
+
+	/* If process was forked, VMA is still there but vm_private_data is set
+	 * to NULL.
+	 */
+	if (!encl)
+		return -EFAULT;
+
+	flags = atomic_read(&encl->flags);
+
+	if (!(flags & SGX_ENCL_DEBUG) || !(flags & SGX_ENCL_INITIALIZED) ||
+	    (flags & SGX_ENCL_DEAD))
+		return -EFAULT;
+
+	for (i = 0; i < len; i += cnt) {
+		entry = sgx_encl_reserve_page(encl, (addr + i) & PAGE_MASK);
+		if (IS_ERR(entry)) {
+			ret = PTR_ERR(entry);
+			break;
+		}
+
+		align = ALIGN_DOWN(addr + i, sizeof(unsigned long));
+		offset = (addr + i) & (sizeof(unsigned long) - 1);
+		cnt = sizeof(unsigned long) - offset;
+		cnt = min(cnt, len - i);
+
+		ret = sgx_edbgrd(encl, entry, align, data);
+		if (ret)
+			goto out;
+
+		if (write) {
+			memcpy(data + offset, buf + i, cnt);
+			ret = sgx_edbgwr(encl, entry, align, data);
+			if (ret)
+				goto out;
+		} else
+			memcpy(buf + i, data + offset, cnt);
+
+out:
+		mutex_unlock(&encl->lock);
+
+		if (ret)
+			break;
+	}
+
+	return ret < 0 ? ret : i;
+}
+
 const struct vm_operations_struct sgx_vm_ops = {
 	.open = sgx_vma_open,
 	.fault = sgx_vma_fault,
 	.mprotect = sgx_vma_mprotect,
+	.access = sgx_vma_access,
 };
 
 /**