On Fri, Jun 26, 2020 at 11:14:19AM +0200, Borislav Petkov wrote:
> On Thu, Jun 18, 2020 at 01:08:33AM +0300, Jarkko Sakkinen wrote:
> > +static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
> > +{
> > +   unsigned long encl_size = secs->size + PAGE_SIZE;
> 
> Wait, you just copied @secs from user memory in sgx_ioc_enclave_create()
> and now use ->size unverified? You're kidding, right?

The size of the enclave is checked in sgx_validate_secs() before it is used
to configure the shmem backing.
 
> > +   struct sgx_epc_page *secs_epc;
> > +   unsigned long ssaframesize;
> > +   struct sgx_pageinfo pginfo;
> > +   struct sgx_secinfo secinfo;
> > +   struct file *backing;
> > +   long ret;
> > +
> > +   if (atomic_read(&encl->flags) & SGX_ENCL_CREATED)
> > +           return -EINVAL;
> > +
> > +   ssaframesize = sgx_calc_ssaframesize(secs->miscselect, secs->xfrm);
> 
> So this is using more un-validated user input to do further calculations.
> What can possibly go wrong?

ssaframesize is also validated below, and the computations on miscselect and
xfm in sgx_calc_ssaframesize() are bounded such that bad input won't send
the kernel into the weeds.

That being said, I agree that it would be safer to move sgx_calc_ssaframesize()
inside sgx_validate_secs() and only compute encl_size after the secs is
validated.

> I sure hope *I* am wrong and am missing something here.
> 
> If not, please, for the next version, audit all your user input and
> validate it before using it. Srsly.
> 
> > +   if (sgx_validate_secs(secs, ssaframesize)) {
> > +           pr_debug("invalid SECS\n");
> > +           return -EINVAL;
> > +   }
> > +
> > +   backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
> > +                              VM_NORESERVE);
> > +   if (IS_ERR(backing))
> > +           return PTR_ERR(backing);
> > +
> > +   encl->backing = backing;
> > +
> > +   secs_epc = __sgx_alloc_epc_page();
> > +   if (IS_ERR(secs_epc)) {
> > +           ret = PTR_ERR(secs_epc);
> > +           goto err_out_backing;
> > +   }
> > +
> > +   encl->secs.epc_page = secs_epc;
> > +
> > +   pginfo.addr = 0;
> > +   pginfo.contents = (unsigned long)secs;
> > +   pginfo.metadata = (unsigned long)&secinfo;
> > +   pginfo.secs = 0;
> > +   memset(&secinfo, 0, sizeof(secinfo));
> > +
> > +   ret = __ecreate((void *)&pginfo, sgx_get_epc_addr(secs_epc));
> > +   if (ret) {
> > +           pr_debug("ECREATE returned %ld\n", ret);
> > +           goto err_out;
> > +   }
> > +
> > +   if (secs->attributes & SGX_ATTR_DEBUG)
> > +           atomic_or(SGX_ENCL_DEBUG, &encl->flags);
> > +
> > +   encl->secs.encl = encl;
> > +   encl->secs_attributes = secs->attributes;
> > +   encl->allowed_attributes |= SGX_ATTR_ALLOWED_MASK;
> > +   encl->base = secs->base;
> > +   encl->size = secs->size;
> > +   encl->ssaframesize = secs->ssa_frame_size;
> > +
> > +   /*
> > +    * Set SGX_ENCL_CREATED only after the enclave is fully prepped.  This
> > +    * allows setting and checking enclave creation without having to take
> > +    * encl->lock.
> > +    */
> > +   atomic_or(SGX_ENCL_CREATED, &encl->flags);
> > +
> > +   return 0;
> > +
> > +err_out:
> > +   sgx_free_epc_page(encl->secs.epc_page);
> > +   encl->secs.epc_page = NULL;
> > +
> > +err_out_backing:
> > +   fput(encl->backing);
> > +   encl->backing = NULL;
> > +
> > +   return ret;
> > +}
> > +
> > +/**
> > + * sgx_ioc_enclave_create - handler for %SGX_IOC_ENCLAVE_CREATE
> > + * @filep: open file to /dev/sgx
> 
> That's
> 
> @encl: enclave pointer
> 
> or so.
> 
> > + * @arg:   userspace pointer to a struct sgx_enclave_create instance
> > + *
> > + * Allocate kernel data structures for a new enclave and execute ECREATE 
> > after
> > + * verifying the correctness of the provided SECS.
> > + *
> > + * Note, enforcement of restricted and disallowed attributes is deferred 
> > until
> > + * sgx_ioc_enclave_init(), only the architectural correctness of the SECS 
> > is
> > + * checked by sgx_ioc_enclave_create().
> 
> Well, I don't see that checking. Where is it?
> 
> > + *
> > + * Return:
> > + *   0 on success,
> > + *   -errno otherwise
> > + */
> > +static long sgx_ioc_enclave_create(struct sgx_encl *encl, void __user *arg)
> > +{
> > +   struct sgx_enclave_create ecreate;
> > +   struct page *secs_page;
> > +   struct sgx_secs *secs;
> > +   int ret;
> > +
> > +   if (copy_from_user(&ecreate, arg, sizeof(ecreate)))
> > +           return -EFAULT;
> > +
> > +   secs_page = alloc_page(GFP_KERNEL);
> > +   if (!secs_page)
> > +           return -ENOMEM;
> > +
> > +   secs = kmap(secs_page);
> > +   if (copy_from_user(secs, (void __user *)ecreate.src, sizeof(*secs))) {
> > +           ret = -EFAULT;
> > +           goto out;
> > +   }
> > +
> > +   ret = sgx_encl_create(encl, secs);
> > +
> > +out:
> > +   kunmap(secs_page);
> > +   __free_page(secs_page);
> > +   return ret;
> > +}
> 
> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette

Reply via email to