1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2016-20 Intel Corporation. */ 3 4 #include <linux/acpi.h> 5 #include <linux/miscdevice.h> 6 #include <linux/mman.h> 7 #include <linux/security.h> 8 #include <linux/suspend.h> 9 #include <asm/traps.h> 10 #include "driver.h" 11 #include "encl.h" 12 13 u64 sgx_attributes_reserved_mask; 14 u64 sgx_xfrm_reserved_mask = ~0x3; 15 u32 sgx_misc_reserved_mask; 16 17 static int sgx_open(struct inode *inode, struct file *file) 18 { 19 struct sgx_encl *encl; 20 int ret; 21 22 encl = kzalloc(sizeof(*encl), GFP_KERNEL); 23 if (!encl) 24 return -ENOMEM; 25 26 kref_init(&encl->refcount); 27 xa_init(&encl->page_array); 28 mutex_init(&encl->lock); 29 INIT_LIST_HEAD(&encl->va_pages); 30 INIT_LIST_HEAD(&encl->mm_list); 31 spin_lock_init(&encl->mm_lock); 32 33 ret = init_srcu_struct(&encl->srcu); 34 if (ret) { 35 kfree(encl); 36 return ret; 37 } 38 39 file->private_data = encl; 40 41 return 0; 42 } 43 44 static int sgx_release(struct inode *inode, struct file *file) 45 { 46 struct sgx_encl *encl = file->private_data; 47 struct sgx_encl_mm *encl_mm; 48 49 /* 50 * Drain the remaining mm_list entries. At this point the list contains 51 * entries for processes, which have closed the enclave file but have 52 * not exited yet. The processes, which have exited, are gone from the 53 * list by sgx_mmu_notifier_release(). 54 */ 55 for ( ; ; ) { 56 spin_lock(&encl->mm_lock); 57 58 if (list_empty(&encl->mm_list)) { 59 encl_mm = NULL; 60 } else { 61 encl_mm = list_first_entry(&encl->mm_list, 62 struct sgx_encl_mm, list); 63 list_del_rcu(&encl_mm->list); 64 } 65 66 spin_unlock(&encl->mm_lock); 67 68 /* The enclave is no longer mapped by any mm. */ 69 if (!encl_mm) 70 break; 71 72 synchronize_srcu(&encl->srcu); 73 mmu_notifier_unregister(&encl_mm->mmu_notifier, encl_mm->mm); 74 kfree(encl_mm); 75 76 /* 'encl_mm' is gone, put encl_mm->encl reference: */ 77 kref_put(&encl->refcount, sgx_encl_release); 78 } 79 80 kref_put(&encl->refcount, sgx_encl_release); 81 return 0; 82 } 83 84 static int sgx_mmap(struct file *file, struct vm_area_struct *vma) 85 { 86 struct sgx_encl *encl = file->private_data; 87 int ret; 88 89 ret = sgx_encl_may_map(encl, vma->vm_start, vma->vm_end, vma->vm_flags); 90 if (ret) 91 return ret; 92 93 ret = sgx_encl_mm_add(encl, vma->vm_mm); 94 if (ret) 95 return ret; 96 97 vma->vm_ops = &sgx_vm_ops; 98 vma->vm_flags |= VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO; 99 vma->vm_private_data = encl; 100 101 return 0; 102 } 103 104 static unsigned long sgx_get_unmapped_area(struct file *file, 105 unsigned long addr, 106 unsigned long len, 107 unsigned long pgoff, 108 unsigned long flags) 109 { 110 if ((flags & MAP_TYPE) == MAP_PRIVATE) 111 return -EINVAL; 112 113 if (flags & MAP_FIXED) 114 return addr; 115 116 return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); 117 } 118 119 #ifdef CONFIG_COMPAT 120 static long sgx_compat_ioctl(struct file *filep, unsigned int cmd, 121 unsigned long arg) 122 { 123 return sgx_ioctl(filep, cmd, arg); 124 } 125 #endif 126 127 static const struct file_operations sgx_encl_fops = { 128 .owner = THIS_MODULE, 129 .open = sgx_open, 130 .release = sgx_release, 131 .unlocked_ioctl = sgx_ioctl, 132 #ifdef CONFIG_COMPAT 133 .compat_ioctl = sgx_compat_ioctl, 134 #endif 135 .mmap = sgx_mmap, 136 .get_unmapped_area = sgx_get_unmapped_area, 137 }; 138 139 static struct miscdevice sgx_dev_enclave = { 140 .minor = MISC_DYNAMIC_MINOR, 141 .name = "sgx_enclave", 142 .nodename = "sgx_enclave", 143 .fops = &sgx_encl_fops, 144 }; 145 146 int __init sgx_drv_init(void) 147 { 148 unsigned int eax, ebx, ecx, edx; 149 u64 attr_mask; 150 u64 xfrm_mask; 151 int ret; 152 153 if (!cpu_feature_enabled(X86_FEATURE_SGX_LC)) 154 return -ENODEV; 155 156 cpuid_count(SGX_CPUID, 0, &eax, &ebx, &ecx, &edx); 157 158 if (!(eax & 1)) { 159 pr_err("SGX disabled: SGX1 instruction support not available.\n"); 160 return -ENODEV; 161 } 162 163 sgx_misc_reserved_mask = ~ebx | SGX_MISC_RESERVED_MASK; 164 165 cpuid_count(SGX_CPUID, 1, &eax, &ebx, &ecx, &edx); 166 167 attr_mask = (((u64)ebx) << 32) + (u64)eax; 168 sgx_attributes_reserved_mask = ~attr_mask | SGX_ATTR_RESERVED_MASK; 169 170 if (cpu_feature_enabled(X86_FEATURE_OSXSAVE)) { 171 xfrm_mask = (((u64)edx) << 32) + (u64)ecx; 172 sgx_xfrm_reserved_mask = ~xfrm_mask; 173 } 174 175 ret = misc_register(&sgx_dev_enclave); 176 if (ret) 177 return ret; 178 179 return 0; 180 } 181