Skip to content

Commit ab851d4

Browse files
committed
Merge branch 'x86-iopl-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 iopl updates from Ingo Molnar: "This implements a nice simplification of the iopl and ioperm code that Thomas Gleixner discovered: we can implement the IO privilege features of the iopl system call by using the IO permission bitmap in permissive mode, while trapping CLI/STI/POPF/PUSHF uses in user-space if they change the interrupt flag. This implements that feature, with testing facilities and related cleanups" [ "Simplification" may be an over-statement. The main goal is to avoid the cli/sti of iopl by effectively implementing the IO port access parts of iopl in terms of ioperm. This may end up not workign well in case people actually depend on cli/sti being available, or if there are mixed uses of iopl and ioperm. We will see.. - Linus ] * 'x86-iopl-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (22 commits) x86/ioperm: Fix use of deprecated config option x86/entry/32: Clarify register saving in __switch_to_asm() selftests/x86/iopl: Extend test to cover IOPL emulation x86/ioperm: Extend IOPL config to control ioperm() as well x86/iopl: Remove legacy IOPL option x86/iopl: Restrict iopl() permission scope x86/iopl: Fixup misleading comment selftests/x86/ioperm: Extend testing so the shared bitmap is exercised x86/ioperm: Share I/O bitmap if identical x86/ioperm: Remove bitmap if all permissions dropped x86/ioperm: Move TSS bitmap update to exit to user work x86/ioperm: Add bitmap sequence number x86/ioperm: Move iobitmap data into a struct x86/tss: Move I/O bitmap data into a seperate struct x86/io: Speedup schedule out of I/O bitmap user x86/ioperm: Avoid bitmap allocation if no permissions are set x86/ioperm: Simplify first ioperm() invocation logic x86/iopl: Cleanup include maze x86/tss: Fix and move VMX BUILD_BUG_ON() x86/cpu: Unify cpu_init() ...
2 parents 1d87200 + e3cb0c7 commit ab851d4

25 files changed

+686
-478
lines changed

arch/x86/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,24 @@ config X86_VSYSCALL_EMULATION
12241224
Disabling this option saves about 7K of kernel size and
12251225
possibly 4K of additional runtime pagetable memory.
12261226

1227+
config X86_IOPL_IOPERM
1228+
bool "IOPERM and IOPL Emulation"
1229+
default y
1230+
---help---
1231+
This enables the ioperm() and iopl() syscalls which are necessary
1232+
for legacy applications.
1233+
1234+
Legacy IOPL support is an overbroad mechanism which allows user
1235+
space aside of accessing all 65536 I/O ports also to disable
1236+
interrupts. To gain this access the caller needs CAP_SYS_RAWIO
1237+
capabilities and permission from potentially active security
1238+
modules.
1239+
1240+
The emulation restricts the functionality of the syscall to
1241+
only allowing the full range I/O port access, but prevents the
1242+
ability to disable interrupts from user space which would be
1243+
granted if the hardware IOPL mechanism would be used.
1244+
12271245
config TOSHIBA
12281246
tristate "Toshiba Laptop support"
12291247
depends on X86_32

arch/x86/entry/common.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <asm/cpufeature.h>
3434
#include <asm/fpu/api.h>
3535
#include <asm/nospec-branch.h>
36+
#include <asm/io_bitmap.h>
3637

3738
#define CREATE_TRACE_POINTS
3839
#include <trace/events/syscalls.h>
@@ -196,6 +197,9 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
196197
/* Reload ti->flags; we may have rescheduled above. */
197198
cached_flags = READ_ONCE(ti->flags);
198199

200+
if (unlikely(cached_flags & _TIF_IO_BITMAP))
201+
tss_update_io_bitmap();
202+
199203
fpregs_assert_state_consistent();
200204
if (unlikely(cached_flags & _TIF_NEED_FPU_LOAD))
201205
switch_fpu_return();

arch/x86/entry/entry_32.S

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,11 @@ SYM_CODE_START(__switch_to_asm)
739739
pushl %ebx
740740
pushl %edi
741741
pushl %esi
742+
/*
743+
* Flags are saved to prevent AC leakage. This could go
744+
* away if objtool would have 32bit support to verify
745+
* the STAC/CLAC correctness.
746+
*/
742747
pushfl
743748

744749
/* switch stack */
@@ -761,8 +766,9 @@ SYM_CODE_START(__switch_to_asm)
761766
FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
762767
#endif
763768

764-
/* restore callee-saved registers */
769+
/* Restore flags or the incoming task to restore AC state. */
765770
popfl
771+
/* restore callee-saved registers */
766772
popl %esi
767773
popl %edi
768774
popl %ebx

arch/x86/include/asm/io_bitmap.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_X86_IOBITMAP_H
3+
#define _ASM_X86_IOBITMAP_H
4+
5+
#include <linux/refcount.h>
6+
#include <asm/processor.h>
7+
8+
struct io_bitmap {
9+
u64 sequence;
10+
refcount_t refcnt;
11+
/* The maximum number of bytes to copy so all zero bits are covered */
12+
unsigned int max;
13+
unsigned long bitmap[IO_BITMAP_LONGS];
14+
};
15+
16+
struct task_struct;
17+
18+
#ifdef CONFIG_X86_IOPL_IOPERM
19+
void io_bitmap_share(struct task_struct *tsk);
20+
void io_bitmap_exit(void);
21+
22+
void tss_update_io_bitmap(void);
23+
#else
24+
static inline void io_bitmap_share(struct task_struct *tsk) { }
25+
static inline void io_bitmap_exit(void) { }
26+
static inline void tss_update_io_bitmap(void) { }
27+
#endif
28+
29+
#endif

arch/x86/include/asm/paravirt.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,6 @@ static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
294294
{
295295
PVOP_VCALL3(cpu.write_idt_entry, dt, entry, g);
296296
}
297-
static inline void set_iopl_mask(unsigned mask)
298-
{
299-
PVOP_VCALL1(cpu.set_iopl_mask, mask);
300-
}
301297

302298
static inline void paravirt_activate_mm(struct mm_struct *prev,
303299
struct mm_struct *next)

arch/x86/include/asm/paravirt_types.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ struct pv_cpu_ops {
140140

141141
void (*load_sp0)(unsigned long sp0);
142142

143-
void (*set_iopl_mask)(unsigned mask);
144-
145143
void (*wbinvd)(void);
146144

147145
/* cpuid emulation, mostly so that caps bits can be disabled */

arch/x86/include/asm/pgtable_32_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
4444
* Define this here and validate with BUILD_BUG_ON() in pgtable_32.c
4545
* to avoid include recursion hell
4646
*/
47-
#define CPU_ENTRY_AREA_PAGES (NR_CPUS * 39)
47+
#define CPU_ENTRY_AREA_PAGES (NR_CPUS * 41)
4848

4949
/* The +1 is for the readonly IDT page: */
5050
#define CPU_ENTRY_AREA_BASE \

arch/x86/include/asm/processor.h

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/* Forward declaration, a strange C thing */
88
struct task_struct;
99
struct mm_struct;
10+
struct io_bitmap;
1011
struct vm86;
1112

1213
#include <asm/math_emu.h>
@@ -336,10 +337,32 @@ struct x86_hw_tss {
336337
* IO-bitmap sizes:
337338
*/
338339
#define IO_BITMAP_BITS 65536
339-
#define IO_BITMAP_BYTES (IO_BITMAP_BITS/8)
340-
#define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long))
341-
#define IO_BITMAP_OFFSET (offsetof(struct tss_struct, io_bitmap) - offsetof(struct tss_struct, x86_tss))
342-
#define INVALID_IO_BITMAP_OFFSET 0x8000
340+
#define IO_BITMAP_BYTES (IO_BITMAP_BITS / BITS_PER_BYTE)
341+
#define IO_BITMAP_LONGS (IO_BITMAP_BYTES / sizeof(long))
342+
343+
#define IO_BITMAP_OFFSET_VALID_MAP \
344+
(offsetof(struct tss_struct, io_bitmap.bitmap) - \
345+
offsetof(struct tss_struct, x86_tss))
346+
347+
#define IO_BITMAP_OFFSET_VALID_ALL \
348+
(offsetof(struct tss_struct, io_bitmap.mapall) - \
349+
offsetof(struct tss_struct, x86_tss))
350+
351+
#ifdef CONFIG_X86_IOPL_IOPERM
352+
/*
353+
* sizeof(unsigned long) coming from an extra "long" at the end of the
354+
* iobitmap. The limit is inclusive, i.e. the last valid byte.
355+
*/
356+
# define __KERNEL_TSS_LIMIT \
357+
(IO_BITMAP_OFFSET_VALID_ALL + IO_BITMAP_BYTES + \
358+
sizeof(unsigned long) - 1)
359+
#else
360+
# define __KERNEL_TSS_LIMIT \
361+
(offsetof(struct tss_struct, x86_tss) + sizeof(struct x86_hw_tss) - 1)
362+
#endif
363+
364+
/* Base offset outside of TSS_LIMIT so unpriviledged IO causes #GP */
365+
#define IO_BITMAP_OFFSET_INVALID (__KERNEL_TSS_LIMIT + 1)
343366

344367
struct entry_stack {
345368
unsigned long words[64];
@@ -349,35 +372,52 @@ struct entry_stack_page {
349372
struct entry_stack stack;
350373
} __aligned(PAGE_SIZE);
351374

352-
struct tss_struct {
375+
/*
376+
* All IO bitmap related data stored in the TSS:
377+
*/
378+
struct x86_io_bitmap {
379+
/* The sequence number of the last active bitmap. */
380+
u64 prev_sequence;
381+
353382
/*
354-
* The fixed hardware portion. This must not cross a page boundary
355-
* at risk of violating the SDM's advice and potentially triggering
356-
* errata.
383+
* Store the dirty size of the last io bitmap offender. The next
384+
* one will have to do the cleanup as the switch out to a non io
385+
* bitmap user will just set x86_tss.io_bitmap_base to a value
386+
* outside of the TSS limit. So for sane tasks there is no need to
387+
* actually touch the io_bitmap at all.
357388
*/
358-
struct x86_hw_tss x86_tss;
389+
unsigned int prev_max;
359390

360391
/*
361392
* The extra 1 is there because the CPU will access an
362393
* additional byte beyond the end of the IO permission
363394
* bitmap. The extra byte must be all 1 bits, and must
364395
* be within the limit.
365396
*/
366-
unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
397+
unsigned long bitmap[IO_BITMAP_LONGS + 1];
398+
399+
/*
400+
* Special I/O bitmap to emulate IOPL(3). All bytes zero,
401+
* except the additional byte at the end.
402+
*/
403+
unsigned long mapall[IO_BITMAP_LONGS + 1];
404+
};
405+
406+
struct tss_struct {
407+
/*
408+
* The fixed hardware portion. This must not cross a page boundary
409+
* at risk of violating the SDM's advice and potentially triggering
410+
* errata.
411+
*/
412+
struct x86_hw_tss x86_tss;
413+
414+
#ifdef CONFIG_X86_IOPL_IOPERM
415+
struct x86_io_bitmap io_bitmap;
416+
#endif
367417
} __aligned(PAGE_SIZE);
368418

369419
DECLARE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss_rw);
370420

371-
/*
372-
* sizeof(unsigned long) coming from an extra "long" at the end
373-
* of the iobitmap.
374-
*
375-
* -1? seg base+limit should be pointing to the address of the
376-
* last valid byte
377-
*/
378-
#define __KERNEL_TSS_LIMIT \
379-
(IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1)
380-
381421
/* Per CPU interrupt stacks */
382422
struct irq_stack {
383423
char stack[IRQ_STACK_SIZE];
@@ -488,10 +528,14 @@ struct thread_struct {
488528
struct vm86 *vm86;
489529
#endif
490530
/* IO permissions: */
491-
unsigned long *io_bitmap_ptr;
492-
unsigned long iopl;
493-
/* Max allowed port in the bitmap, in bytes: */
494-
unsigned io_bitmap_max;
531+
struct io_bitmap *io_bitmap;
532+
533+
/*
534+
* IOPL. Priviledge level dependent I/O permission which is
535+
* emulated via the I/O bitmap to prevent user space from disabling
536+
* interrupts.
537+
*/
538+
unsigned long iopl_emul;
495539

496540
mm_segment_t addr_limit;
497541

@@ -523,25 +567,6 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
523567
*/
524568
#define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/
525569

526-
/*
527-
* Set IOPL bits in EFLAGS from given mask
528-
*/
529-
static inline void native_set_iopl_mask(unsigned mask)
530-
{
531-
#ifdef CONFIG_X86_32
532-
unsigned int reg;
533-
534-
asm volatile ("pushfl;"
535-
"popl %0;"
536-
"andl %1, %0;"
537-
"orl %2, %0;"
538-
"pushl %0;"
539-
"popfl"
540-
: "=&r" (reg)
541-
: "i" (~X86_EFLAGS_IOPL), "r" (mask));
542-
#endif
543-
}
544-
545570
static inline void
546571
native_load_sp0(unsigned long sp0)
547572
{
@@ -581,7 +606,6 @@ static inline void load_sp0(unsigned long sp0)
581606
native_load_sp0(sp0);
582607
}
583608

584-
#define set_iopl_mask native_set_iopl_mask
585609
#endif /* CONFIG_PARAVIRT_XXL */
586610

587611
/* Free all resources held by a thread. */
@@ -849,7 +873,6 @@ static inline void spin_lock_prefetch(const void *x)
849873
#define INIT_THREAD { \
850874
.sp0 = TOP_OF_INIT_STACK, \
851875
.sysenter_cs = __KERNEL_CS, \
852-
.io_bitmap_ptr = NULL, \
853876
.addr_limit = KERNEL_DS, \
854877
}
855878

arch/x86/include/asm/ptrace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,5 +361,11 @@ extern int do_get_thread_area(struct task_struct *p, int idx,
361361
extern int do_set_thread_area(struct task_struct *p, int idx,
362362
struct user_desc __user *info, int can_allocate);
363363

364+
#ifdef CONFIG_X86_64
365+
# define do_set_thread_area_64(p, s, t) do_arch_prctl_64(p, s, t)
366+
#else
367+
# define do_set_thread_area_64(p, s, t) (0)
368+
#endif
369+
364370
#endif /* !__ASSEMBLY__ */
365371
#endif /* _ASM_X86_PTRACE_H */

arch/x86/include/asm/switch_to.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,17 @@ static inline void update_task_stack(struct task_struct *task)
103103
if (static_cpu_has(X86_FEATURE_XENPV))
104104
load_sp0(task_top_of_stack(task));
105105
#endif
106+
}
106107

108+
static inline void kthread_frame_init(struct inactive_task_frame *frame,
109+
unsigned long fun, unsigned long arg)
110+
{
111+
frame->bx = fun;
112+
#ifdef CONFIG_X86_32
113+
frame->di = arg;
114+
#else
115+
frame->r12 = arg;
116+
#endif
107117
}
108118

109119
#endif /* _ASM_X86_SWITCH_TO_H */

0 commit comments

Comments
 (0)