Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*  Copyright(c) 2016-20 Intel Corporation. */
0003 
0004 #include <linux/acpi.h>
0005 #include <linux/miscdevice.h>
0006 #include <linux/mman.h>
0007 #include <linux/security.h>
0008 #include <linux/suspend.h>
0009 #include <asm/traps.h>
0010 #include "driver.h"
0011 #include "encl.h"
0012 
0013 u64 sgx_attributes_reserved_mask;
0014 u64 sgx_xfrm_reserved_mask = ~0x3;
0015 u32 sgx_misc_reserved_mask;
0016 
0017 static int sgx_open(struct inode *inode, struct file *file)
0018 {
0019     struct sgx_encl *encl;
0020     int ret;
0021 
0022     encl = kzalloc(sizeof(*encl), GFP_KERNEL);
0023     if (!encl)
0024         return -ENOMEM;
0025 
0026     kref_init(&encl->refcount);
0027     xa_init(&encl->page_array);
0028     mutex_init(&encl->lock);
0029     INIT_LIST_HEAD(&encl->va_pages);
0030     INIT_LIST_HEAD(&encl->mm_list);
0031     spin_lock_init(&encl->mm_lock);
0032 
0033     ret = init_srcu_struct(&encl->srcu);
0034     if (ret) {
0035         kfree(encl);
0036         return ret;
0037     }
0038 
0039     file->private_data = encl;
0040 
0041     return 0;
0042 }
0043 
0044 static int sgx_release(struct inode *inode, struct file *file)
0045 {
0046     struct sgx_encl *encl = file->private_data;
0047     struct sgx_encl_mm *encl_mm;
0048 
0049     /*
0050      * Drain the remaining mm_list entries. At this point the list contains
0051      * entries for processes, which have closed the enclave file but have
0052      * not exited yet. The processes, which have exited, are gone from the
0053      * list by sgx_mmu_notifier_release().
0054      */
0055     for ( ; ; )  {
0056         spin_lock(&encl->mm_lock);
0057 
0058         if (list_empty(&encl->mm_list)) {
0059             encl_mm = NULL;
0060         } else {
0061             encl_mm = list_first_entry(&encl->mm_list,
0062                            struct sgx_encl_mm, list);
0063             list_del_rcu(&encl_mm->list);
0064         }
0065 
0066         spin_unlock(&encl->mm_lock);
0067 
0068         /* The enclave is no longer mapped by any mm. */
0069         if (!encl_mm)
0070             break;
0071 
0072         synchronize_srcu(&encl->srcu);
0073         mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm);
0074         kfree(encl_mm);
0075 
0076         /* 'encl_mm' is gone, put encl_mm->encl reference: */
0077         kref_put(&encl->refcount, sgx_encl_release);
0078     }
0079 
0080     kref_put(&encl->refcount, sgx_encl_release);
0081     return 0;
0082 }
0083 
0084 static int sgx_mmap(struct file *file, struct vm_area_struct *vma)
0085 {
0086     struct sgx_encl *encl = file->private_data;
0087     int ret;
0088 
0089     ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags);
0090     if (ret)
0091         return ret;
0092 
0093     ret = sgx_encl_mm_add(encl, vma->vm_mm);
0094     if (ret)
0095         return ret;
0096 
0097     vma->vm_ops = &sgx_vm_ops;
0098     vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
0099     vma->vm_private_data = encl;
0100 
0101     return 0;
0102 }
0103 
0104 static unsigned long sgx_get_unmapped_area(struct file *file,
0105                        unsigned long addr,
0106                        unsigned long len,
0107                        unsigned long pgoff,
0108                        unsigned long flags)
0109 {
0110     if ((flags & MAP_TYPE) == MAP_PRIVATE)
0111         return -EINVAL;
0112 
0113     if (flags & MAP_FIXED)
0114         return addr;
0115 
0116     return current->mm->get_unmapped_area(file, addr, len, pgoff, flags);
0117 }
0118 
0119 #ifdef CONFIG_COMPAT
0120 static long sgx_compat_ioctl(struct file *filep, unsigned int cmd,
0121                   unsigned long arg)
0122 {
0123     return sgx_ioctl(filep, cmd, arg);
0124 }
0125 #endif
0126 
0127 static const struct file_operations sgx_encl_fops = {
0128     .owner          = THIS_MODULE,
0129     .open           = sgx_open,
0130     .release        = sgx_release,
0131     .unlocked_ioctl     = sgx_ioctl,
0132 #ifdef CONFIG_COMPAT
0133     .compat_ioctl       = sgx_compat_ioctl,
0134 #endif
0135     .mmap           = sgx_mmap,
0136     .get_unmapped_area  = sgx_get_unmapped_area,
0137 };
0138 
0139 static struct miscdevice sgx_dev_enclave = {
0140     .minor = MISC_DYNAMIC_MINOR,
0141     .name = "sgx_enclave",
0142     .nodename = "sgx_enclave",
0143     .fops = &sgx_encl_fops,
0144 };
0145 
0146 int __init sgx_drv_init(void)
0147 {
0148     unsigned int eax, ebx, ecx, edx;
0149     u64 attr_mask;
0150     u64 xfrm_mask;
0151     int ret;
0152 
0153     if (!cpu_feature_enabled(X86_FEATURE_SGX_LC))
0154         return -ENODEV;
0155 
0156     cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx);
0157 
0158     if (!(eax & 1))  {
0159         pr_err("SGX disabled: SGX1 instruction support not available.\n");
0160         return -ENODEV;
0161     }
0162 
0163     sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK;
0164 
0165     cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx);
0166 
0167     attr_mask = (((u64)ebx) << 32) + (u64)eax;
0168     sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK;
0169 
0170     if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) {
0171         xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
0172         sgx_xfrm_reserved_mask = ~xfrm_mask;
0173     }
0174 
0175     ret = misc_register(&sgx_dev_enclave);
0176     if (ret)
0177         return ret;
0178 
0179     return 0;
0180 }