.. | .. |
---|
3 | 3 | * This contains the io-permission bitmap code - written by obz, with changes |
---|
4 | 4 | * by Linus. 32/64 bits code unification by Miguel Botón. |
---|
5 | 5 | */ |
---|
6 | | - |
---|
7 | | -#include <linux/sched.h> |
---|
8 | | -#include <linux/sched/task_stack.h> |
---|
9 | | -#include <linux/kernel.h> |
---|
10 | 6 | #include <linux/capability.h> |
---|
11 | | -#include <linux/errno.h> |
---|
12 | | -#include <linux/types.h> |
---|
13 | | -#include <linux/ioport.h> |
---|
14 | | -#include <linux/smp.h> |
---|
15 | | -#include <linux/stddef.h> |
---|
16 | | -#include <linux/slab.h> |
---|
17 | | -#include <linux/thread_info.h> |
---|
| 7 | +#include <linux/security.h> |
---|
18 | 8 | #include <linux/syscalls.h> |
---|
19 | 9 | #include <linux/bitmap.h> |
---|
20 | | -#include <asm/syscalls.h> |
---|
| 10 | +#include <linux/ioport.h> |
---|
| 11 | +#include <linux/sched.h> |
---|
| 12 | +#include <linux/slab.h> |
---|
| 13 | + |
---|
| 14 | +#include <asm/io_bitmap.h> |
---|
21 | 15 | #include <asm/desc.h> |
---|
| 16 | +#include <asm/syscalls.h> |
---|
| 17 | + |
---|
| 18 | +#ifdef CONFIG_X86_IOPL_IOPERM |
---|
| 19 | + |
---|
| 20 | +static atomic64_t io_bitmap_sequence; |
---|
| 21 | + |
---|
| 22 | +void io_bitmap_share(struct task_struct *tsk) |
---|
| 23 | +{ |
---|
| 24 | + /* Can be NULL when current->thread.iopl_emul == 3 */ |
---|
| 25 | + if (current->thread.io_bitmap) { |
---|
| 26 | + /* |
---|
| 27 | + * Take a refcount on current's bitmap. It can be used by |
---|
| 28 | + * both tasks as long as none of them changes the bitmap. |
---|
| 29 | + */ |
---|
| 30 | + refcount_inc(¤t->thread.io_bitmap->refcnt); |
---|
| 31 | + tsk->thread.io_bitmap = current->thread.io_bitmap; |
---|
| 32 | + } |
---|
| 33 | + set_tsk_thread_flag(tsk, TIF_IO_BITMAP); |
---|
| 34 | +} |
---|
| 35 | + |
---|
| 36 | +static void task_update_io_bitmap(struct task_struct *tsk) |
---|
| 37 | +{ |
---|
| 38 | + struct thread_struct *t = &tsk->thread; |
---|
| 39 | + |
---|
| 40 | + if (t->iopl_emul == 3 || t->io_bitmap) { |
---|
| 41 | + /* TSS update is handled on exit to user space */ |
---|
| 42 | + set_tsk_thread_flag(tsk, TIF_IO_BITMAP); |
---|
| 43 | + } else { |
---|
| 44 | + clear_tsk_thread_flag(tsk, TIF_IO_BITMAP); |
---|
| 45 | + /* Invalidate TSS */ |
---|
| 46 | + preempt_disable(); |
---|
| 47 | + tss_update_io_bitmap(); |
---|
| 48 | + preempt_enable(); |
---|
| 49 | + } |
---|
| 50 | +} |
---|
| 51 | + |
---|
| 52 | +void io_bitmap_exit(struct task_struct *tsk) |
---|
| 53 | +{ |
---|
| 54 | + struct io_bitmap *iobm = tsk->thread.io_bitmap; |
---|
| 55 | + |
---|
| 56 | + tsk->thread.io_bitmap = NULL; |
---|
| 57 | + task_update_io_bitmap(tsk); |
---|
| 58 | + if (iobm && refcount_dec_and_test(&iobm->refcnt)) |
---|
| 59 | + kfree(iobm); |
---|
| 60 | +} |
---|
22 | 61 | |
---|
23 | 62 | /* |
---|
24 | | - * this changes the io permissions bitmap in the current task. |
---|
| 63 | + * This changes the io permissions bitmap in the current task. |
---|
25 | 64 | */ |
---|
26 | 65 | long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) |
---|
27 | 66 | { |
---|
28 | 67 | struct thread_struct *t = ¤t->thread; |
---|
29 | | - struct tss_struct *tss; |
---|
30 | | - unsigned int i, max_long, bytes, bytes_updated; |
---|
| 68 | + unsigned int i, max_long; |
---|
| 69 | + struct io_bitmap *iobm; |
---|
31 | 70 | |
---|
32 | 71 | if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) |
---|
33 | 72 | return -EINVAL; |
---|
34 | | - if (turn_on && !capable(CAP_SYS_RAWIO)) |
---|
| 73 | + if (turn_on && (!capable(CAP_SYS_RAWIO) || |
---|
| 74 | + security_locked_down(LOCKDOWN_IOPORT))) |
---|
35 | 75 | return -EPERM; |
---|
36 | 76 | |
---|
37 | 77 | /* |
---|
.. | .. |
---|
39 | 79 | * IO bitmap up. ioperm() is much less timing critical than clone(), |
---|
40 | 80 | * this is why we delay this operation until now: |
---|
41 | 81 | */ |
---|
42 | | - if (!t->io_bitmap_ptr) { |
---|
43 | | - unsigned long *bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL); |
---|
44 | | - |
---|
45 | | - if (!bitmap) |
---|
| 82 | + iobm = t->io_bitmap; |
---|
| 83 | + if (!iobm) { |
---|
| 84 | + /* No point to allocate a bitmap just to clear permissions */ |
---|
| 85 | + if (!turn_on) |
---|
| 86 | + return 0; |
---|
| 87 | + iobm = kmalloc(sizeof(*iobm), GFP_KERNEL); |
---|
| 88 | + if (!iobm) |
---|
46 | 89 | return -ENOMEM; |
---|
47 | 90 | |
---|
48 | | - memset(bitmap, 0xff, IO_BITMAP_BYTES); |
---|
49 | | - t->io_bitmap_ptr = bitmap; |
---|
50 | | - set_thread_flag(TIF_IO_BITMAP); |
---|
51 | | - |
---|
52 | | - /* |
---|
53 | | - * Now that we have an IO bitmap, we need our TSS limit to be |
---|
54 | | - * correct. It's fine if we are preempted after doing this: |
---|
55 | | - * with TIF_IO_BITMAP set, context switches will keep our TSS |
---|
56 | | - * limit correct. |
---|
57 | | - */ |
---|
58 | | - preempt_disable(); |
---|
59 | | - refresh_tss_limit(); |
---|
60 | | - preempt_enable(); |
---|
| 91 | + memset(iobm->bitmap, 0xff, sizeof(iobm->bitmap)); |
---|
| 92 | + refcount_set(&iobm->refcnt, 1); |
---|
61 | 93 | } |
---|
62 | 94 | |
---|
63 | 95 | /* |
---|
64 | | - * do it in the per-thread copy and in the TSS ... |
---|
65 | | - * |
---|
66 | | - * Disable preemption via get_cpu() - we must not switch away |
---|
67 | | - * because the ->io_bitmap_max value must match the bitmap |
---|
68 | | - * contents: |
---|
| 96 | + * If the bitmap is not shared, then nothing can take a refcount as |
---|
| 97 | + * current can obviously not fork at the same time. If it's shared |
---|
| 98 | + * duplicate it and drop the refcount on the original one. |
---|
69 | 99 | */ |
---|
70 | | - tss = &per_cpu(cpu_tss_rw, get_cpu()); |
---|
| 100 | + if (refcount_read(&iobm->refcnt) > 1) { |
---|
| 101 | + iobm = kmemdup(iobm, sizeof(*iobm), GFP_KERNEL); |
---|
| 102 | + if (!iobm) |
---|
| 103 | + return -ENOMEM; |
---|
| 104 | + refcount_set(&iobm->refcnt, 1); |
---|
| 105 | + io_bitmap_exit(current); |
---|
| 106 | + } |
---|
71 | 107 | |
---|
| 108 | + /* |
---|
| 109 | + * Store the bitmap pointer (might be the same if the task already |
---|
| 110 | + * head one). Must be done here so freeing the bitmap when all |
---|
| 111 | + * permissions are dropped has the pointer set up. |
---|
| 112 | + */ |
---|
| 113 | + t->io_bitmap = iobm; |
---|
| 114 | + /* Mark it active for context switching and exit to user mode */ |
---|
| 115 | + set_thread_flag(TIF_IO_BITMAP); |
---|
| 116 | + |
---|
| 117 | + /* |
---|
| 118 | + * Update the tasks bitmap. The update of the TSS bitmap happens on |
---|
| 119 | + * exit to user mode. So this needs no protection. |
---|
| 120 | + */ |
---|
72 | 121 | if (turn_on) |
---|
73 | | - bitmap_clear(t->io_bitmap_ptr, from, num); |
---|
| 122 | + bitmap_clear(iobm->bitmap, from, num); |
---|
74 | 123 | else |
---|
75 | | - bitmap_set(t->io_bitmap_ptr, from, num); |
---|
| 124 | + bitmap_set(iobm->bitmap, from, num); |
---|
76 | 125 | |
---|
77 | 126 | /* |
---|
78 | 127 | * Search for a (possibly new) maximum. This is simple and stupid, |
---|
79 | 128 | * to keep it obviously correct: |
---|
80 | 129 | */ |
---|
81 | | - max_long = 0; |
---|
82 | | - for (i = 0; i < IO_BITMAP_LONGS; i++) |
---|
83 | | - if (t->io_bitmap_ptr[i] != ~0UL) |
---|
| 130 | + max_long = UINT_MAX; |
---|
| 131 | + for (i = 0; i < IO_BITMAP_LONGS; i++) { |
---|
| 132 | + if (iobm->bitmap[i] != ~0UL) |
---|
84 | 133 | max_long = i; |
---|
| 134 | + } |
---|
| 135 | + /* All permissions dropped? */ |
---|
| 136 | + if (max_long == UINT_MAX) { |
---|
| 137 | + io_bitmap_exit(current); |
---|
| 138 | + return 0; |
---|
| 139 | + } |
---|
85 | 140 | |
---|
86 | | - bytes = (max_long + 1) * sizeof(unsigned long); |
---|
87 | | - bytes_updated = max(bytes, t->io_bitmap_max); |
---|
| 141 | + iobm->max = (max_long + 1) * sizeof(unsigned long); |
---|
88 | 142 | |
---|
89 | | - t->io_bitmap_max = bytes; |
---|
90 | | - |
---|
91 | | - /* Update the TSS: */ |
---|
92 | | - memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated); |
---|
93 | | - |
---|
94 | | - put_cpu(); |
---|
| 143 | + /* |
---|
| 144 | + * Update the sequence number to force a TSS update on return to |
---|
| 145 | + * user mode. |
---|
| 146 | + */ |
---|
| 147 | + iobm->sequence = atomic64_add_return(1, &io_bitmap_sequence); |
---|
95 | 148 | |
---|
96 | 149 | return 0; |
---|
97 | 150 | } |
---|
.. | .. |
---|
102 | 155 | } |
---|
103 | 156 | |
---|
104 | 157 | /* |
---|
105 | | - * sys_iopl has to be used when you want to access the IO ports |
---|
106 | | - * beyond the 0x3ff range: to get the full 65536 ports bitmapped |
---|
107 | | - * you'd need 8kB of bitmaps/process, which is a bit excessive. |
---|
| 158 | + * The sys_iopl functionality depends on the level argument, which if |
---|
| 159 | + * granted for the task is used to enable access to all 65536 I/O ports. |
---|
108 | 160 | * |
---|
109 | | - * Here we just change the flags value on the stack: we allow |
---|
110 | | - * only the super-user to do it. This depends on the stack-layout |
---|
111 | | - * on system-call entry - see also fork() and the signal handling |
---|
112 | | - * code. |
---|
| 161 | + * This does not use the IOPL mechanism provided by the CPU as that would |
---|
| 162 | + * also allow the user space task to use the CLI/STI instructions. |
---|
| 163 | + * |
---|
| 164 | + * Disabling interrupts in a user space task is dangerous as it might lock |
---|
| 165 | + * up the machine and the semantics vs. syscalls and exceptions is |
---|
| 166 | + * undefined. |
---|
| 167 | + * |
---|
| 168 | + * Setting IOPL to level 0-2 is disabling I/O permissions. Level 3 |
---|
| 169 | + * 3 enables them. |
---|
| 170 | + * |
---|
| 171 | + * IOPL is strictly per thread and inherited on fork. |
---|
113 | 172 | */ |
---|
114 | 173 | SYSCALL_DEFINE1(iopl, unsigned int, level) |
---|
115 | 174 | { |
---|
116 | | - struct pt_regs *regs = current_pt_regs(); |
---|
117 | 175 | struct thread_struct *t = ¤t->thread; |
---|
118 | | - |
---|
119 | | - /* |
---|
120 | | - * Careful: the IOPL bits in regs->flags are undefined under Xen PV |
---|
121 | | - * and changing them has no effect. |
---|
122 | | - */ |
---|
123 | | - unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT; |
---|
| 176 | + unsigned int old; |
---|
124 | 177 | |
---|
125 | 178 | if (level > 3) |
---|
126 | 179 | return -EINVAL; |
---|
| 180 | + |
---|
| 181 | + old = t->iopl_emul; |
---|
| 182 | + |
---|
| 183 | + /* No point in going further if nothing changes */ |
---|
| 184 | + if (level == old) |
---|
| 185 | + return 0; |
---|
| 186 | + |
---|
127 | 187 | /* Trying to gain more privileges? */ |
---|
128 | 188 | if (level > old) { |
---|
129 | | - if (!capable(CAP_SYS_RAWIO)) |
---|
| 189 | + if (!capable(CAP_SYS_RAWIO) || |
---|
| 190 | + security_locked_down(LOCKDOWN_IOPORT)) |
---|
130 | 191 | return -EPERM; |
---|
131 | 192 | } |
---|
132 | | - regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | |
---|
133 | | - (level << X86_EFLAGS_IOPL_BIT); |
---|
134 | | - t->iopl = level << X86_EFLAGS_IOPL_BIT; |
---|
135 | | - set_iopl_mask(t->iopl); |
---|
| 193 | + |
---|
| 194 | + t->iopl_emul = level; |
---|
| 195 | + task_update_io_bitmap(current); |
---|
136 | 196 | |
---|
137 | 197 | return 0; |
---|
138 | 198 | } |
---|
| 199 | + |
---|
| 200 | +#else /* CONFIG_X86_IOPL_IOPERM */ |
---|
| 201 | + |
---|
| 202 | +long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) |
---|
| 203 | +{ |
---|
| 204 | + return -ENOSYS; |
---|
| 205 | +} |
---|
| 206 | +SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on) |
---|
| 207 | +{ |
---|
| 208 | + return -ENOSYS; |
---|
| 209 | +} |
---|
| 210 | + |
---|
| 211 | +SYSCALL_DEFINE1(iopl, unsigned int, level) |
---|
| 212 | +{ |
---|
| 213 | + return -ENOSYS; |
---|
| 214 | +} |
---|
| 215 | +#endif |
---|