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