xref: /linux/arch/x86/kernel/cpu/sgx/driver.c (revision d639d9fa162aadec1ae9980c4dcf6e50bd2f8290)
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