Commit a4950109 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Ben Hutchings

x86/iopl: Fix iopl capability check on Xen PV

commit c29016cf upstream.

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: default avatarJan Beulich <JBeulich@suse.com>
Signed-off-by: default avatarAndy 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>
Link: http://lkml.kernel.org/r/8ce12013e6e4c0a44a97e316be4a6faff31bd5ea.1458162709.git.luto@kernel.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 031a3cd4
...@@ -96,9 +96,14 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) ...@@ -96,9 +96,14 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
SYSCALL_DEFINE1(iopl, unsigned int, level) SYSCALL_DEFINE1(iopl, unsigned int, level)
{ {
struct pt_regs *regs = current_pt_regs(); struct pt_regs *regs = current_pt_regs();
unsigned int old = (regs->flags >> 12) & 3;
struct thread_struct *t = &current->thread; struct thread_struct *t = &current->thread;
/*
* Careful: the IOPL bits in regs->flags are undefined under Xen PV
* and changing them has no effect.
*/
unsigned int old = t->iopl >> X86_EFLAGS_IOPL_BIT;
if (level > 3) if (level > 3)
return -EINVAL; return -EINVAL;
/* Trying to gain more privileges? */ /* Trying to gain more privileges? */
...@@ -106,8 +111,9 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) ...@@ -106,8 +111,9 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
if (!capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_RAWIO))
return -EPERM; return -EPERM;
} }
regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
t->iopl = level << 12; (level << X86_EFLAGS_IOPL_BIT);
t->iopl = level << X86_EFLAGS_IOPL_BIT;
set_iopl_mask(t->iopl); set_iopl_mask(t->iopl);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment