Skip to content

Commit c29016c

Browse files
amlutoIngo Molnar
authored andcommitted
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 <[email protected]> Signed-off-by: Andy Lutomirski <[email protected]> Cc: Andrew Cooper <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Boris Ostrovsky <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Brian Gerst <[email protected]> Cc: David Vrabel <[email protected]> Cc: Denys Vlasenko <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Jan Beulich <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/8ce12013e6e4c0a44a97e316be4a6faff31bd5ea.1458162709.git.luto@kernel.org Signed-off-by: Ingo Molnar <[email protected]>
1 parent b7a5845 commit c29016c

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

arch/x86/kernel/ioport.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,24 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
9696
SYSCALL_DEFINE1(iopl, unsigned int, level)
9797
{
9898
struct pt_regs *regs = current_pt_regs();
99-
unsigned int old = (regs->flags >> 12) & 3;
10099
struct thread_struct *t = &current->thread;
101100

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;
106+
102107
if (level > 3)
103108
return -EINVAL;
104109
/* Trying to gain more privileges? */
105110
if (level > old) {
106111
if (!capable(CAP_SYS_RAWIO))
107112
return -EPERM;
108113
}
109-
regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
110-
t->iopl = level << 12;
114+
regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) |
115+
(level << X86_EFLAGS_IOPL_BIT);
116+
t->iopl = level << X86_EFLAGS_IOPL_BIT;
111117
set_iopl_mask(t->iopl);
112118

113119
return 0;

0 commit comments

Comments
 (0)