Re: [PATCH v22 09/24] x86/sgx: Add functions to allocate and free EPC pages

From: Borislav Petkov
Date: Sat Oct 05 2019 - 12:44:17 EST


On Tue, Sep 03, 2019 at 05:26:40PM +0300, Jarkko Sakkinen wrote:
> Add functions for grabbing EPC pages into use:
>
> * sgx_alloc_page(): Iterate the EPC sections and return the first free
> page, or ERR_PTR(-ENOMEM) when no free pages are available.
> * __sgx_free_page(): Return the page into uninitialized state and move
> it back to the corresponding EPC section structure. Issues WARN()
> when EREMOVE fails.
> * sgx_free_page(): Return the page into uninitialized state and move
> it back to the corresponding EPC section structure. Returns
> ENCLS[EREMOVE] error code back to the caller.
>
> [1] Intel SDM: 40.3 INTELÂ SGX SYSTEM LEAF FUNCTION REFERENCE
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@xxxxxxxxxxxxxxx>
> Co-developed-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
> Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
> ---
> arch/x86/kernel/cpu/sgx/main.c | 90 ++++++++++++++++++++++++++++++++++
> arch/x86/kernel/cpu/sgx/sgx.h | 4 ++
> 2 files changed, 94 insertions(+)
>
> diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c
> index e2317f6e4374..6b4727df72ca 100644
> --- a/arch/x86/kernel/cpu/sgx/main.c
> +++ b/arch/x86/kernel/cpu/sgx/main.c
> @@ -9,6 +9,7 @@
> #include <linux/sched/signal.h>
> #include <linux/slab.h>
> #include "arch.h"
> +#include "encls.h"
> #include "sgx.h"
>
> struct sgx_epc_section sgx_epc_sections[SGX_MAX_EPC_SECTIONS];
> @@ -16,6 +17,95 @@ EXPORT_SYMBOL_GPL(sgx_epc_sections);
>
> int sgx_nr_epc_sections;
>
> +static struct sgx_epc_page *sgx_section_get_page(

That fits into 80 cols (oh well, 81) and even if not, a trailing opening
arg brace is ugly.

> + struct sgx_epc_section *section)
> +{
> + struct sgx_epc_page *page;
> +
> + if (!section->free_cnt)
> + return NULL;
> +
> + page = list_first_entry(&section->page_list,
> + struct sgx_epc_page, list);

That fits in 80-cols too. Why break it?

> + list_del_init(&page->list);
> + section->free_cnt--;
> + return page;
> +}
> +
> +/**
> + * sgx_alloc_page - Allocate an EPC page
> + *
> + * Try to grab a page from the free EPC page list.
> + *
> + * Return:
> + * a pointer to a &struct sgx_epc_page instance,
> + * -errno on error
> + */
> +struct sgx_epc_page *sgx_alloc_page(void)
> +{
> + struct sgx_epc_section *section;
> + struct sgx_epc_page *page;
> + int i;
> +
> + for (i = 0; i < sgx_nr_epc_sections; i++) {
> + section = &sgx_epc_sections[i];
> + spin_lock(&section->lock);
> + page = sgx_section_get_page(section);
> + spin_unlock(&section->lock);
> +
> + if (page)
> + return page;
> + }
> +
> + return ERR_PTR(-ENOMEM);
> +}
> +EXPORT_SYMBOL_GPL(sgx_alloc_page);

That export gets removed later too. But you know already...

> +
> +/**
> + * __sgx_free_page - Free an EPC page
> + * @page: pointer a previously allocated EPC page
> + *
> + * EREMOVE an EPC page and insert it back to the list of free pages.
> + *
> + * Return:
> + * 0 on success
> + * SGX error code if EREMOVE fails
> + */
> +int __sgx_free_page(struct sgx_epc_page *page)
> +{
> + struct sgx_epc_section *section = sgx_epc_section(page);
> + int ret;

Shouldn't you be grabbing the lock here already?

Or nothing can happen to that page from another thread after you
ENCLS[EREMOVE] it and before it is added to the ->page_list of the
section?

> +
> + ret = __eremove(sgx_epc_addr(page));
> + if (ret)
> + return ret;
> +
> + spin_lock(&section->lock);
> + list_add_tail(&page->list, &section->page_list);
> + section->free_cnt++;
> + spin_unlock(&section->lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(__sgx_free_page);
> +
> +/**
> + * sgx_free_page - Free an EPC page and WARN on failure
> + * @page: pointer to a previously allocated EPC page
> + *
> + * EREMOVE an EPC page and insert it back to the list of free pages, and WARN
> + * if EREMOVE fails. For use when the call site cannot (or chooses not to)
> + * handle failure, i.e. the page is leaked on failure.
> + */
> +void sgx_free_page(struct sgx_epc_page *page)
> +{
> + int ret;
> +
> + ret = __sgx_free_page(page);
> + WARN(ret > 0, "sgx: EREMOVE returned %d (0x%x)", ret, ret);

That will potentially flood dmesg. Why are we even accommodating such
callers? They either handle the error or they don't get to alloc EPC
pages. There's also __must_check with which you can enforce the error
code checking or we simply don't allow not handling failure. Fullstop.

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette