blob: 72d13b0779a29f938c4ce6ac40012495a4a66c91 [file] [log] [blame]
Qiaowei Ren57319d82014-11-14 07:18:27 -08001/*
2 * mpx.c - Memory Protection eXtensions
3 *
4 * Copyright (c) 2014, Intel Corporation.
5 * Qiaowei Ren <qiaowei.ren@intel.com>
6 * Dave Hansen <dave.hansen@intel.com>
7 */
8#include <linux/kernel.h>
9#include <linux/syscalls.h>
10#include <linux/sched/sysctl.h>
11
12#include <asm/mman.h>
13#include <asm/mpx.h>
14
15static const char *mpx_mapping_name(struct vm_area_struct *vma)
16{
17 return "[mpx]";
18}
19
20static struct vm_operations_struct mpx_vma_ops = {
21 .name = mpx_mapping_name,
22};
23
24/*
25 * This is really a simplified "vm_mmap". it only handles MPX
26 * bounds tables (the bounds directory is user-allocated).
27 *
28 * Later on, we use the vma->vm_ops to uniquely identify these
29 * VMAs.
30 */
31static unsigned long mpx_mmap(unsigned long len)
32{
33 unsigned long ret;
34 unsigned long addr, pgoff;
35 struct mm_struct *mm = current->mm;
36 vm_flags_t vm_flags;
37 struct vm_area_struct *vma;
38
39 /* Only bounds table and bounds directory can be allocated here */
40 if (len != MPX_BD_SIZE_BYTES && len != MPX_BT_SIZE_BYTES)
41 return -EINVAL;
42
43 down_write(&mm->mmap_sem);
44
45 /* Too many mappings? */
46 if (mm->map_count > sysctl_max_map_count) {
47 ret = -ENOMEM;
48 goto out;
49 }
50
51 /* Obtain the address to map to. we verify (or select) it and ensure
52 * that it represents a valid section of the address space.
53 */
54 addr = get_unmapped_area(NULL, 0, len, 0, MAP_ANONYMOUS | MAP_PRIVATE);
55 if (addr & ~PAGE_MASK) {
56 ret = addr;
57 goto out;
58 }
59
60 vm_flags = VM_READ | VM_WRITE | VM_MPX |
61 mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
62
63 /* Set pgoff according to addr for anon_vma */
64 pgoff = addr >> PAGE_SHIFT;
65
66 ret = mmap_region(NULL, addr, len, vm_flags, pgoff);
67 if (IS_ERR_VALUE(ret))
68 goto out;
69
70 vma = find_vma(mm, ret);
71 if (!vma) {
72 ret = -ENOMEM;
73 goto out;
74 }
75 vma->vm_ops = &mpx_vma_ops;
76
77 if (vm_flags & VM_LOCKED) {
78 up_write(&mm->mmap_sem);
79 mm_populate(ret, len);
80 return ret;
81 }
82
83out:
84 up_write(&mm->mmap_sem);
85 return ret;
86}