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