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