Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/iopl: Fix iopl capability check on Xen PV

iopl(3) is supposed to work if iopl is already 3, even if
unprivileged. This didn't work right on Xen PV. Fix it.

Reviewewd-by: Jan Beulich <JBeulich@suse.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jan Beulich <JBeulich@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/8ce12013e6e4c0a44a97e316be4a6faff31bd5ea.1458162709.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Andy Lutomirski and committed by
Ingo Molnar
c29016cf b7a58459

+9 -3
+9 -3
arch/x86/kernel/ioport.c
··· 96 96 SYSCALL_DEFINE1(iopl, unsigned int, level) 97 97 { 98 98 struct pt_regs *regs = current_pt_regs(); 99 - unsigned int old = (regs->flags >> 12) & 3; 100 99 struct thread_struct *t = &current->thread; 100 + 101 + /* 102 + * Careful: the IOPL bits in regs->flags are undefined under Xen PV 103 + * and changing them has no effect. 104 + */ 105 + unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT; 101 106 102 107 if (level > 3) 103 108 return -EINVAL; ··· 111 106 if (!capable(CAP_SYS_RAWIO)) 112 107 return -EPERM; 113 108 } 114 - regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); 115 - t->iopl = level << 12; 109 + regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | 110 + (level << X86_EFLAGS_IOPL_BIT); 111 + t->iopl = level << X86_EFLAGS_IOPL_BIT; 116 112 set_iopl_mask(t->iopl); 117 113 118 114 return 0;