xref: /linux/arch/x86/kernel/ioport.c (revision 0529ef8c36d74a05e929ea4adbdecd2c3393b0bb)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This contains the io-permission bitmap code - written by obz, with changes
4  * by Linus. 32/64 bits code unification by Miguel Botón.
5  */
6 #include <linux/capability.h>
7 #include <linux/security.h>
8 #include <linux/syscalls.h>
9 #include <linux/bitmap.h>
10 #include <linux/ioport.h>
11 #include <linux/sched.h>
12 #include <linux/slab.h>
13 
14 #include <asm/io_bitmap.h>
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 
io_bitmap_share(struct task_struct * tsk)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(&current->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 
task_update_io_bitmap(void)36 static void task_update_io_bitmap(void)
37 {
38 	struct task_struct *tsk = current;
39 	struct thread_struct *t = &tsk->thread;
40 
41 	if (t->iopl_emul == 3 || t->io_bitmap) {
42 		/* TSS update is handled on exit to user space */
43 		set_tsk_thread_flag(tsk, TIF_IO_BITMAP);
44 	} else {
45 		clear_tsk_thread_flag(tsk, TIF_IO_BITMAP);
46 		/* Invalidate TSS */
47 		preempt_disable();
48 		tss_update_io_bitmap();
49 		preempt_enable();
50 	}
51 }
52 
io_bitmap_exit(struct task_struct * tsk)53 void io_bitmap_exit(struct task_struct *tsk)
54 {
55 	struct io_bitmap *iobm = tsk->thread.io_bitmap;
56 
57 	tsk->thread.io_bitmap = NULL;
58 	/*
59 	 * Don't touch the TSS when invoked on a failed fork(). TSS
60 	 * reflects the state of @current and not the state of @tsk.
61 	 */
62 	if (tsk == current)
63 		task_update_io_bitmap();
64 	if (iobm && refcount_dec_and_test(&iobm->refcnt))
65 		kfree(iobm);
66 }
67 
68 /*
69  * This changes the io permissions bitmap in the current task.
70  */
ksys_ioperm(unsigned long from,unsigned long num,int turn_on)71 long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
72 {
73 	struct thread_struct *t = &current->thread;
74 	unsigned int i, max_long;
75 	struct io_bitmap *iobm;
76 
77 	if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
78 		return -EINVAL;
79 	if (turn_on && (!capable(CAP_SYS_RAWIO) ||
80 			security_locked_down(LOCKDOWN_IOPORT)))
81 		return -EPERM;
82 
83 	/*
84 	 * If it's the first ioperm() call in this thread's lifetime, set the
85 	 * IO bitmap up. ioperm() is much less timing critical than clone(),
86 	 * this is why we delay this operation until now:
87 	 */
88 	iobm = t->io_bitmap;
89 	if (!iobm) {
90 		/* No point to allocate a bitmap just to clear permissions */
91 		if (!turn_on)
92 			return 0;
93 		iobm = kmalloc(sizeof(*iobm), GFP_KERNEL);
94 		if (!iobm)
95 			return -ENOMEM;
96 
97 		memset(iobm->bitmap, 0xff, sizeof(iobm->bitmap));
98 		refcount_set(&iobm->refcnt, 1);
99 	}
100 
101 	/*
102 	 * If the bitmap is not shared, then nothing can take a refcount as
103 	 * current can obviously not fork at the same time. If it's shared
104 	 * duplicate it and drop the refcount on the original one.
105 	 */
106 	if (refcount_read(&iobm->refcnt) > 1) {
107 		iobm = kmemdup(iobm, sizeof(*iobm), GFP_KERNEL);
108 		if (!iobm)
109 			return -ENOMEM;
110 		refcount_set(&iobm->refcnt, 1);
111 		io_bitmap_exit(current);
112 	}
113 
114 	/*
115 	 * Store the bitmap pointer (might be the same if the task already
116 	 * head one). Must be done here so freeing the bitmap when all
117 	 * permissions are dropped has the pointer set up.
118 	 */
119 	t->io_bitmap = iobm;
120 	/* Mark it active for context switching and exit to user mode */
121 	set_thread_flag(TIF_IO_BITMAP);
122 
123 	/*
124 	 * Update the tasks bitmap. The update of the TSS bitmap happens on
125 	 * exit to user mode. So this needs no protection.
126 	 */
127 	if (turn_on)
128 		bitmap_clear(iobm->bitmap, from, num);
129 	else
130 		bitmap_set(iobm->bitmap, from, num);
131 
132 	/*
133 	 * Search for a (possibly new) maximum. This is simple and stupid,
134 	 * to keep it obviously correct:
135 	 */
136 	max_long = UINT_MAX;
137 	for (i = 0; i < IO_BITMAP_LONGS; i++) {
138 		if (iobm->bitmap[i] != ~0UL)
139 			max_long = i;
140 	}
141 	/* All permissions dropped? */
142 	if (max_long == UINT_MAX) {
143 		io_bitmap_exit(current);
144 		return 0;
145 	}
146 
147 	iobm->max = (max_long + 1) * sizeof(unsigned long);
148 
149 	/*
150 	 * Update the sequence number to force a TSS update on return to
151 	 * user mode.
152 	 */
153 	iobm->sequence = atomic64_inc_return(&io_bitmap_sequence);
154 
155 	return 0;
156 }
157 
SYSCALL_DEFINE3(ioperm,unsigned long,from,unsigned long,num,int,turn_on)158 SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on)
159 {
160 	return ksys_ioperm(from, num, turn_on);
161 }
162 
163 /*
164  * The sys_iopl functionality depends on the level argument, which if
165  * granted for the task is used to enable access to all 65536 I/O ports.
166  *
167  * This does not use the IOPL mechanism provided by the CPU as that would
168  * also allow the user space task to use the CLI/STI instructions.
169  *
170  * Disabling interrupts in a user space task is dangerous as it might lock
171  * up the machine and the semantics vs. syscalls and exceptions is
172  * undefined.
173  *
174  * Setting IOPL to level 0-2 is disabling I/O permissions. Level 3
175  * 3 enables them.
176  *
177  * IOPL is strictly per thread and inherited on fork.
178  */
SYSCALL_DEFINE1(iopl,unsigned int,level)179 SYSCALL_DEFINE1(iopl, unsigned int, level)
180 {
181 	struct thread_struct *t = &current->thread;
182 	unsigned int old;
183 
184 	if (level > 3)
185 		return -EINVAL;
186 
187 	old = t->iopl_emul;
188 
189 	/* No point in going further if nothing changes */
190 	if (level == old)
191 		return 0;
192 
193 	/* Trying to gain more privileges? */
194 	if (level > old) {
195 		if (!capable(CAP_SYS_RAWIO) ||
196 		    security_locked_down(LOCKDOWN_IOPORT))
197 			return -EPERM;
198 	}
199 
200 	t->iopl_emul = level;
201 	task_update_io_bitmap();
202 	return 0;
203 }
204 
205 #else /* CONFIG_X86_IOPL_IOPERM */
206 
ksys_ioperm(unsigned long from,unsigned long num,int turn_on)207 long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
208 {
209 	return -ENOSYS;
210 }
SYSCALL_DEFINE3(ioperm,unsigned long,from,unsigned long,num,int,turn_on)211 SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on)
212 {
213 	return -ENOSYS;
214 }
215 
SYSCALL_DEFINE1(iopl,unsigned int,level)216 SYSCALL_DEFINE1(iopl, unsigned int, level)
217 {
218 	return -ENOSYS;
219 }
220 #endif
221