Skip to content

Commit

Permalink
x86/iopl: Remove legacy IOPL option
Browse files Browse the repository at this point in the history
The IOPL emulation via the I/O bitmap is sufficient. Remove the legacy
cruft dealing with the (e)flags based IOPL mechanism.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Juergen Gross <jgross@suse.com> (Paravirt and Xen parts)
Acked-by: Andy Lutomirski <luto@kernel.org>
  • Loading branch information
KAGA-KOKO committed Nov 16, 2019
1 parent c8137ac commit a24ca99
Show file tree
Hide file tree
Showing 10 changed files with 17 additions and 119 deletions.
23 changes: 3 additions & 20 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1254,12 +1254,9 @@ config X86_VSYSCALL_EMULATION
Disabling this option saves about 7K of kernel size and
possibly 4K of additional runtime pagetable memory.

choice
prompt "IOPL"
default X86_IOPL_EMULATION

config X86_IOPL_EMULATION
bool "IOPL Emulation"
default y
---help---
Legacy IOPL support is an overbroad mechanism which allows user
space aside of accessing all 65536 I/O ports also to disable
Expand All @@ -1269,22 +1266,8 @@ config X86_IOPL_EMULATION

The emulation restricts the functionality of the syscall to
only allowing the full range I/O port access, but prevents the
ability to disable interrupts from user space.

config X86_IOPL_LEGACY
bool "IOPL Legacy"
---help---
Allow the full IOPL permissions, i.e. user space access to all
65536 I/O ports and also the ability to disable interrupts, which
is overbroad and can result in system lockups.

config X86_IOPL_NONE
bool "IOPL None"
---help---
Disable the IOPL permission syscall. That's the safest option as
no sane application should depend on this functionality.

endchoice
ability to disable interrupts from user space which would be
granted if the hardware IOPL mechanism would be used.

config TOSHIBA
tristate "Toshiba Laptop support"
Expand Down
4 changes: 0 additions & 4 deletions arch/x86/include/asm/paravirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,6 @@ static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
{
PVOP_VCALL3(cpu.write_idt_entry, dt, entry, g);
}
static inline void set_iopl_mask(unsigned mask)
{
PVOP_VCALL1(cpu.set_iopl_mask, mask);
}

static inline void paravirt_activate_mm(struct mm_struct *prev,
struct mm_struct *next)
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/include/asm/paravirt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ struct pv_cpu_ops {

void (*load_sp0)(unsigned long sp0);

void (*set_iopl_mask)(unsigned mask);

void (*wbinvd)(void);

/* cpuid emulation, mostly so that caps bits can be disabled */
Expand Down
26 changes: 3 additions & 23 deletions arch/x86/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -516,10 +516,10 @@ struct thread_struct {
struct io_bitmap *io_bitmap;

/*
* IOPL. Priviledge level dependent I/O permission which includes
* user space CLI/STI when granted.
* IOPL. Priviledge level dependent I/O permission which is
* emulated via the I/O bitmap to prevent user space from disabling
* interrupts.
*/
unsigned long iopl;
unsigned long iopl_emul;

mm_segment_t addr_limit;
Expand Down Expand Up @@ -552,25 +552,6 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
*/
#define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/

/*
* Set IOPL bits in EFLAGS from given mask
*/
static inline void native_set_iopl_mask(unsigned mask)
{
#ifdef CONFIG_X86_32
unsigned int reg;

asm volatile ("pushfl;"
"popl %0;"
"andl %1, %0;"
"orl %2, %0;"
"pushl %0;"
"popfl"
: "=&r" (reg)
: "i" (~X86_EFLAGS_IOPL), "r" (mask));
#endif
}

static inline void
native_load_sp0(unsigned long sp0)
{
Expand Down Expand Up @@ -610,7 +591,6 @@ static inline void load_sp0(unsigned long sp0)
native_load_sp0(sp0);
}

#define set_iopl_mask native_set_iopl_mask
#endif /* CONFIG_PARAVIRT_XXL */

/* Free all resources held by a thread. */
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/include/asm/xen/hypervisor.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,4 @@ void xen_arch_register_cpu(int num);
void xen_arch_unregister_cpu(int num);
#endif

extern void xen_set_iopl_mask(unsigned mask);

#endif /* _ASM_X86_XEN_HYPERVISOR_H */
47 changes: 11 additions & 36 deletions arch/x86/kernel/ioport.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,28 +153,23 @@ SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on)

/*
* The sys_iopl functionality depends on the level argument, which if
* granted for the task is used by the CPU to check I/O instruction and
* CLI/STI against the current priviledge level (CPL). If CPL is less than
* or equal the tasks IOPL level the instructions take effect. If not a #GP
* is raised. The default IOPL is 0, i.e. no permissions.
* granted for the task is used to enable access to all 65536 I/O ports.
*
* Setting IOPL to level 0-2 is disabling the userspace access. Only level
* 3 enables it. If set it allows the user space thread:
* This does not use the IOPL mechanism provided by the CPU as that would
* also allow the user space task to use the CLI/STI instructions.
*
* - Unrestricted access to all 65535 I/O ports
* - The usage of CLI/STI instructions
* Disabling interrupts in a user space task is dangerous as it might lock
* up the machine and the semantics vs. syscalls and exceptions is
* undefined.
*
* The advantage over ioperm is that the context switch does not require to
* update the I/O bitmap which is especially true when a large number of
* ports is accessed. But the allowance of CLI/STI in userspace is
* considered a major problem.
* Setting IOPL to level 0-2 is disabling I/O permissions. Level 3
* 3 enables them.
*
* IOPL is strictly per thread and inherited on fork.
*/
SYSCALL_DEFINE1(iopl, unsigned int, level)
{
struct thread_struct *t = &current->thread;
struct pt_regs *regs = current_pt_regs();
unsigned int old;

/*
Expand All @@ -187,10 +182,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
if (level > 3)
return -EINVAL;

if (IS_ENABLED(CONFIG_X86_IOPL_EMULATION))
old = t->iopl_emul;
else
old = t->iopl >> X86_EFLAGS_IOPL_BIT;
old = t->iopl_emul;

/* No point in going further if nothing changes */
if (level == old)
Expand All @@ -203,25 +195,8 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
return -EPERM;
}

if (IS_ENABLED(CONFIG_X86_IOPL_EMULATION)) {
t->iopl_emul = level;
task_update_io_bitmap();
} else {
/*
* Change the flags value on the return stack, which has
* been set up on system-call entry. See also the fork and
* signal handling code how this is handled.
*/
regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
(level << X86_EFLAGS_IOPL_BIT);
/* Store the new level in the thread struct */
t->iopl = level << X86_EFLAGS_IOPL_BIT;
/*
* X86_32 switches immediately and XEN handles it via
* emulation.
*/
set_iopl_mask(t->iopl);
}
t->iopl_emul = level;
task_update_io_bitmap();

return 0;
}
2 changes: 0 additions & 2 deletions arch/x86/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,6 @@ struct paravirt_patch_template pv_ops = {
.cpu.iret = native_iret,
.cpu.swapgs = native_swapgs,

.cpu.set_iopl_mask = native_set_iopl_mask,

.cpu.start_context_switch = paravirt_nop,
.cpu.end_context_switch = paravirt_nop,

Expand Down
9 changes: 0 additions & 9 deletions arch/x86/kernel/process_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
*/
load_TLS(next, cpu);

/*
* Restore IOPL if needed. In normal use, the flags restore
* in the switch assembly will handle this. But if the kernel
* is running virtualized at a non-zero CPL, the popf will
* not restore flags, so it must be done in a separate step.
*/
if (get_kernel_rpl() && unlikely(prev->iopl != next->iopl))
set_iopl_mask(next->iopl);

switch_to_extra(prev_p, next_p);

/*
Expand Down
11 changes: 0 additions & 11 deletions arch/x86/kernel/process_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,17 +497,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)

switch_to_extra(prev_p, next_p);

#ifdef CONFIG_XEN_PV
/*
* On Xen PV, IOPL bits in pt_regs->flags have no effect, and
* current_pt_regs()->flags may not match the current task's
* intended IOPL. We need to switch it manually.
*/
if (unlikely(static_cpu_has(X86_FEATURE_XENPV) &&
prev->iopl != next->iopl))
xen_set_iopl_mask(next->iopl);
#endif

if (static_cpu_has_bug(X86_BUG_SYSRET_SS_ATTRS)) {
/*
* AMD CPUs have a misfeature: SYSRET sets the SS selector but
Expand Down
10 changes: 0 additions & 10 deletions arch/x86/xen/enlighten_pv.c
Original file line number Diff line number Diff line change
Expand Up @@ -837,15 +837,6 @@ static void xen_load_sp0(unsigned long sp0)
this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
}

void xen_set_iopl_mask(unsigned mask)
{
struct physdev_set_iopl set_iopl;

/* Force the change at ring 0. */
set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
}

static void xen_io_delay(void)
{
}
Expand Down Expand Up @@ -1055,7 +1046,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
.write_idt_entry = xen_write_idt_entry,
.load_sp0 = xen_load_sp0,

.set_iopl_mask = xen_set_iopl_mask,
.io_delay = xen_io_delay,

/* Xen takes care of %gs when switching to usermode for us */
Expand Down

0 comments on commit a24ca99

Please sign in to comment.