* [Qemu-devel] [Bug 1428352] [NEW] SYSRET instruction incorrectly implemented
@ 2015-03-04 22:22 Bill Paul
2020-08-07 18:03 ` [Bug 1428352] " Thomas Huth
0 siblings, 1 reply; 2+ messages in thread
From: Bill Paul @ 2015-03-04 22:22 UTC (permalink / raw)
To: qemu-devel
Public bug reported:
The Intel architecture manual states that when returning to user mode,
the SYSRET instruction will re-load the stack selector (%ss) from the
IA32_STAR model specific register using the following logic:
SS.Selector <-- (IA32_STAR[63:48]+8) OR 3; (* RPL forced to 3 *)
Another description of the instruction behavior which shows the same
logic in a slightly different form can also be found here:
http://tptp.cc/mirrors/siyobik.info/instruction/SYSRET.html
[...]
SS(SEL) = IA32_STAR[63:48] + 8;
SS(PL) = 0x3;
[...]
In other words, the value of the %ss register is supposed to be loaded
from bits 63:48 of the IA32_STAR model-specific register, incremented
by 8, and then ORed with 3. ORing in the 3 sets the privilege level to 3
(user). This is done since SYSRET returns to user mode after a system
call.
However, helper_sysret() in target-i386/seg_helper.c does not do the "OR
3" step. The code looks like this:
cpu_x86_load_seg_cache(env, R_SS, selector + 8,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
It should look like this:
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
The code does correctly set the privilege level bits for the code
selector register (%cs) but not for the stack selector (%ss).
The effect of this is that when SYSRET returns control to the user-mode
caller, %ss will be have the privilege level bits cleared. In my case,
it went from 0x2b to 0x28. This caused a crash later: when the user-mode
code was preempted by an interrupt, and the interrupt handler would do
an IRET, a general protection fault would occur because the %ss value
being loaded from the exception frame was not valid for user mode. (At
least, I think that's what happened.)
This behavior seems inconsistent with real hardware, and also appears to
be wrong with respect to the Intel documentation, so I'm pretty
confident in calling this a bug. :)
Note that this issue seems to have been around for a long time. I
discovered it while using QEMU 2.2.0, but I happened to have the sources
for QEMU 0.10.5, and the problem is there too (in os_helper.c). I am
using FreeBSD/amd64 9.1-RELEASE as my host system, without KVM.
The fix is fairly simple. I'm attaching a patch which worked for me.
Using this fix, the code that I'm testing now behaves the same on the
QEMU virtual machine as on real hardware.
- Bill (wpaul@windriver.com)
** Affects: qemu
Importance: Undecided
Status: New
** Attachment added: "Patch to correct helper_sysret()"
https://bugs.launchpad.net/bugs/1428352/+attachment/4334723/+files/0001-This-checkin-corrects-a-bug-in-the-implementation-of.patch
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1428352
Title:
SYSRET instruction incorrectly implemented
Status in QEMU:
New
Bug description:
The Intel architecture manual states that when returning to user mode,
the SYSRET instruction will re-load the stack selector (%ss) from the
IA32_STAR model specific register using the following logic:
SS.Selector <-- (IA32_STAR[63:48]+8) OR 3; (* RPL forced to 3 *)
Another description of the instruction behavior which shows the same
logic in a slightly different form can also be found here:
http://tptp.cc/mirrors/siyobik.info/instruction/SYSRET.html
[...]
SS(SEL) = IA32_STAR[63:48] + 8;
SS(PL) = 0x3;
[...]
In other words, the value of the %ss register is supposed to be loaded
from bits 63:48 of the IA32_STAR model-specific register, incremented
by 8, and then ORed with 3. ORing in the 3 sets the privilege level to
3 (user). This is done since SYSRET returns to user mode after a
system call.
However, helper_sysret() in target-i386/seg_helper.c does not do the
"OR 3" step. The code looks like this:
cpu_x86_load_seg_cache(env, R_SS, selector + 8,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
It should look like this:
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
The code does correctly set the privilege level bits for the code
selector register (%cs) but not for the stack selector (%ss).
The effect of this is that when SYSRET returns control to the user-
mode caller, %ss will be have the privilege level bits cleared. In my
case, it went from 0x2b to 0x28. This caused a crash later: when the
user-mode code was preempted by an interrupt, and the interrupt
handler would do an IRET, a general protection fault would occur
because the %ss value being loaded from the exception frame was not
valid for user mode. (At least, I think that's what happened.)
This behavior seems inconsistent with real hardware, and also appears
to be wrong with respect to the Intel documentation, so I'm pretty
confident in calling this a bug. :)
Note that this issue seems to have been around for a long time. I
discovered it while using QEMU 2.2.0, but I happened to have the
sources for QEMU 0.10.5, and the problem is there too (in
os_helper.c). I am using FreeBSD/amd64 9.1-RELEASE as my host system,
without KVM.
The fix is fairly simple. I'm attaching a patch which worked for me.
Using this fix, the code that I'm testing now behaves the same on the
QEMU virtual machine as on real hardware.
- Bill (wpaul@windriver.com)
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1428352/+subscriptions
^ permalink raw reply [flat|nested] 2+ messages in thread
* [Bug 1428352] Re: SYSRET instruction incorrectly implemented
2015-03-04 22:22 [Qemu-devel] [Bug 1428352] [NEW] SYSRET instruction incorrectly implemented Bill Paul
@ 2020-08-07 18:03 ` Thomas Huth
0 siblings, 0 replies; 2+ messages in thread
From: Thomas Huth @ 2020-08-07 18:03 UTC (permalink / raw)
To: qemu-devel
If I've got that right, this has been fixed here:
https://git.qemu.org/?p=qemu.git;a=commitdiff;h=ac57622985220de0
** Changed in: qemu
Status: New => Fix Released
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1428352
Title:
SYSRET instruction incorrectly implemented
Status in QEMU:
Fix Released
Bug description:
The Intel architecture manual states that when returning to user mode,
the SYSRET instruction will re-load the stack selector (%ss) from the
IA32_STAR model specific register using the following logic:
SS.Selector <-- (IA32_STAR[63:48]+8) OR 3; (* RPL forced to 3 *)
Another description of the instruction behavior which shows the same
logic in a slightly different form can also be found here:
http://tptp.cc/mirrors/siyobik.info/instruction/SYSRET.html
[...]
SS(SEL) = IA32_STAR[63:48] + 8;
SS(PL) = 0x3;
[...]
In other words, the value of the %ss register is supposed to be loaded
from bits 63:48 of the IA32_STAR model-specific register, incremented
by 8, and then ORed with 3. ORing in the 3 sets the privilege level to
3 (user). This is done since SYSRET returns to user mode after a
system call.
However, helper_sysret() in target-i386/seg_helper.c does not do the
"OR 3" step. The code looks like this:
cpu_x86_load_seg_cache(env, R_SS, selector + 8,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
It should look like this:
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
The code does correctly set the privilege level bits for the code
selector register (%cs) but not for the stack selector (%ss).
The effect of this is that when SYSRET returns control to the user-
mode caller, %ss will be have the privilege level bits cleared. In my
case, it went from 0x2b to 0x28. This caused a crash later: when the
user-mode code was preempted by an interrupt, and the interrupt
handler would do an IRET, a general protection fault would occur
because the %ss value being loaded from the exception frame was not
valid for user mode. (At least, I think that's what happened.)
This behavior seems inconsistent with real hardware, and also appears
to be wrong with respect to the Intel documentation, so I'm pretty
confident in calling this a bug. :)
Note that this issue seems to have been around for a long time. I
discovered it while using QEMU 2.2.0, but I happened to have the
sources for QEMU 0.10.5, and the problem is there too (in
os_helper.c). I am using FreeBSD/amd64 9.1-RELEASE as my host system,
without KVM.
The fix is fairly simple. I'm attaching a patch which worked for me.
Using this fix, the code that I'm testing now behaves the same on the
QEMU virtual machine as on real hardware.
- Bill (wpaul@windriver.com)
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1428352/+subscriptions
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-08-07 18:20 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-04 22:22 [Qemu-devel] [Bug 1428352] [NEW] SYSRET instruction incorrectly implemented Bill Paul
2020-08-07 18:03 ` [Bug 1428352] " Thomas Huth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).