On Tue, Mar 04, 2025 at 04:05:45PM +0300, Dan Carpenter wrote:
> Hello Jarkko Sakkinen,

Hi Dan, thanks for the report, it is very well put together with all the
detail it has :-)

> 
> Commit 888d24911787 ("x86/sgx: Add SGX_IOC_ENCLAVE_CREATE") from Nov
> 13, 2020 (linux-next), leads to the following Smatch static checker
> warning:
> 
>       arch/x86/kernel/cpu/sgx/ioctl.c:75 sgx_encl_create()
>       warn: potential user controlled sizeof overflow 'secs->size + ((1) << 
> 12)' '0-u64max + 4096'


What I tried:

1. Installed smatch package to Fedora.
2. Cloned git clone git://repo.or.cz/smatch.git

I get:

$ O=.clangd ~/work/staging/smatch/smatch_scripts/kchecker 
arch/x86/kernel/cpu/sgx/ioctl.c
make[1]: Entering directory 
'/home/jarkko/work/kernel.org/jarkko/linux-tpmdd/.clangd'
  SYNC    include/config/auto.conf
  GEN     Makefile
  GEN     Makefile
  CHECK   ../scripts/mod/empty.c
  CALL    ../scripts/checksyscalls.sh
  DESCEND objtool
  INSTALL libsubcmd_headers
  CHECK   ../arch/x86/kernel/cpu/sgx/ioctl.c
make[7]: *** [../scripts/Makefile.build:208: arch/x86/kernel/cpu/sgx/ioctl.o] 
Error 139
make[6]: *** [../scripts/Makefile.build:465: arch/x86/kernel/cpu/sgx] Error 2
make[5]: *** [../scripts/Makefile.build:465: arch/x86/kernel/cpu] Error 2
make[4]: *** [../scripts/Makefile.build:465: arch/x86/kernel] Error 2
make[3]: *** [../scripts/Makefile.build:465: arch/x86] Error 2
make[2]: *** [/home/jarkko/work/kernel.org/jarkko/linux-tpmdd/Makefile:1989: .] 
Error 2
make[1]: *** [/home/jarkko/work/kernel.org/jarkko/linux-tpmdd/Makefile:251: 
__sub-make] Error 2
make[1]: Leaving directory 
'/home/jarkko/work/kernel.org/jarkko/linux-tpmdd/.clangd'
make: *** [Makefile:251: __sub-make] Error 2

Am I using smatch incorrectly? I'd just love to learn how to use it in
order to make sure that my fix will address the bug.

> 
> arch/x86/kernel/cpu/sgx/ioctl.c
>     57 static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs 
> *secs)
>     58 {
>     59         struct sgx_epc_page *secs_epc;
>     60         struct sgx_va_page *va_page;
>     61         struct sgx_pageinfo pginfo;
>     62         struct sgx_secinfo secinfo;
>     63         unsigned long encl_size;
>     64         struct file *backing;
>     65         long ret;
>     66 
>     67         va_page = sgx_encl_grow(encl, true);
>     68         if (IS_ERR(va_page))
>     69                 return PTR_ERR(va_page);
>     70         else if (va_page)
>     71                 list_add(&va_page->list, &encl->va_pages);
>     72         /* else the tail page of the VA page list had free slots. */
>     73 
>     74         /* The extra page goes to SECS. */
> --> 75         encl_size = secs->size + PAGE_SIZE;
> 
> secs->size is a u64 that comes from the user in sgx_ioc_enclave_create().
> If we add PAGE_SIZE that could be an integer overflow.  Also encl_size is
> unsigned long so on 32 bits that's another integer overflow.

It's guaranteeed to be 64-bit given:

config X86_SGX
        bool "Software Guard eXtensions (SGX)"
        depends on X86_64 && CPU_SUP_INTEL && X86_X2APIC

That said, it would add clarity to explicitly declare encl_size as u64.

How it is now, is somewhat obfuscated, I give you that (but still not
incorrect).


> 
>     76 
>     77         backing = shmem_file_setup("SGX backing", encl_size + 
> (encl_size >> 5),
>                                                          
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Also this can integer overflow.


I drafted this quickly but I think we could probably fix this up by:

diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
index b65ab214bdf5..551e65c94eb3 100644
--- a/arch/x86/kernel/cpu/sgx/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -60,10 +60,20 @@ static int sgx_encl_create(struct sgx_encl *encl, struct 
sgx_secs *secs)
        struct sgx_va_page *va_page;
        struct sgx_pageinfo pginfo;
        struct sgx_secinfo secinfo;
-       unsigned long encl_size;
+       u64 encl_size, pcmd_size;
        struct file *backing;
        long ret;

+       if ((u64)PAGE_SIZE > ~secs->size)
+               return -E2BIG;
+
+       /* The extra page is for SECS: */
+       encl_size = secs->size + PAGE_SIZE;
+       pcmd_size = encl_size >> 5;
+
+       if (pcmd_size > ~encl_size)
+               return -E2BIG;
+
        va_page = sgx_encl_grow(encl, true);
        if (IS_ERR(va_page))
                return PTR_ERR(va_page);
@@ -71,9 +81,6 @@ static int sgx_encl_create(struct sgx_encl *encl, struct 
sgx_secs *secs)
                list_add(&va_page->list, &encl->va_pages);
        /* else the tail page of the VA page list had free slots. */

-       /* The extra page goes to SECS. */
-       encl_size = secs->size + PAGE_SIZE;
-
        backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
                                   VM_NORESERVE);
        if (IS_ERR(backing)) {

The gist here is that by inverting bits we check if the remaining space
in 64-bit number has enough space for the "extra fill"

BR, Jarkko

Reply via email to