All of lore.kernel.org
 help / color / mirror / Atom feed
From: bugzilla-daemon@kernel.org
To: kvm@vger.kernel.org
Subject: [Bug 216867] New: KVM instruction emulation breaks LOCK instruction atomicity when CMPXCHG fails
Date: Fri, 30 Dec 2022 03:02:21 +0000	[thread overview]
Message-ID: <bug-216867-28872@https.bugzilla.kernel.org/> (raw)

https://bugzilla.kernel.org/show_bug.cgi?id=216867

            Bug ID: 216867
           Summary: KVM instruction emulation breaks LOCK instruction
                    atomicity when CMPXCHG fails
           Product: Virtualization
           Version: unspecified
    Kernel Version: 6.0.14-300.fc37.x86_64
          Hardware: All
                OS: Linux
              Tree: Mainline
            Status: NEW
          Severity: normal
          Priority: P1
         Component: kvm
          Assignee: virtualization_kvm@kernel-bugs.osdl.org
          Reporter: ercli@ucdavis.edu
        Regression: No

Created attachment 303502
  --> https://bugzilla.kernel.org/attachment.cgi?id=303502&action=edit
c.img.xz: Guest software to reproduce this bug (xz compressed)

Host CPU model: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
Host kernel version: 6.0.14-300.fc37.x86_64
Host kernel arch: x86_64
Guest: a system level software (called LHV) I wrote myself, 32-bits, compressed
and attached as c.img.xz.
QEMU command line: qemu-system-i386 -m 256M -smp 4 -enable-kvm -serial stdio
-drive media=disk,file=c.img
The problem does not go away if using -machine kernel_irqchip=off
The problem goes away if -accel tcg is used (also remove -enable-kvm)

Actual behavior: serial port shows a few lines, then stops. Example:

...
counts: count0  count1  count2  count0-count1+count2
counts: 1       0       1       0
counts: 2       1       1       0
counts: 3       2       1       0
counts: 4       2       3       -1
counts: 5       3       4       -2
counts: 6       3       5       -2
counts: 7       4       6       -3
counts: 8       4       7       -3
counts: 9       4       8       -3
counts: 10      5       8       -3
(no more outputs due to deadlock)

Usually the output is shorter. Sometimes only the table header.

Expected behaivor (reproducible using TCG): serial port shows:

...
counts: count0  count1  count2  count0-count1+count2
counts: 1       0       1       0
counts: 2       1       1       0
counts: 3       1       2       0
counts: 4       2       2       0
counts: 5       2       3       0
counts: 6       3       3       0
counts: 7       3       4       0
counts: 8       4       4       0
counts: 9       5       4       0
counts: 10      5       5       0
counts: 11      5       6       0
counts: 12      6       6       0
counts: 13      7       6       0
...

Explanation:

See the following for source code, line 5 - 89:

https://github.com/lxylxy123456/uberxmhf/blob/b5935eaf8aab38ce1933da1c1be22dcf1b992eaf/xmhf/src/xmhf-core/xmhf-runtime/xmhf-startup/lhv.c#L5

My code performs the following experiment repeatedly on 3 CPUs:

* Initially, "ptr" at address 0xb8000 (VGA memory mapped I/O) is set to 0
* CPU 0 writes 0x12345678 to ptr, then increases counter "count0".
* In an infinite loop, CPU 1 tries exchanges ptr with register EAX (contains 0)
using the XCHG instruction. If CPU 1 sees 0x12345678, it increases counter
"count1".
* CPU 2's behavior is similar to CPU 1, except it increases counter "count2"
when it sees 0x12345678.

Ideally, after each experiment there should always be count1 + count2 = count0.
However, in KVM, there may be count1 + count2 > count0. This because CPU 0
writes 0x12345678 to ptr once, but CPU 1 and CPU 2 both get 0x12345678 in XCHG.
Note that XCHG instruction always implements the locking protocol.

There is also a deadlock after running the experiment a few times. However I am
not trying to explain it for now.

Guessed cause:

I guess that KVM emulates the XCHG instruction that accesses 0xb8000. The call
stack should be:

...
 x86_emulate_instruction (arch/x86/kvm/x86.c)
  x86_emulate_insn (arch/x86/kvm/emulate.c)
   writeback (arch/x86/kvm/emulate.c)
    segmented_cmpxchg (arch/x86/kvm/emulate.c)
     emulator_cmpxchg_emulated (arch/x86/kvm/x86.c, ->cmpxchg_emulated)
      emulator_try_cmpxchg_user (arch/x86/kvm/x86.c)
       ...
        CMPXCHG instruction

Suppose CPU 2 wants to write 0 to ptr using writeback(), and expecting ptr to
already contain 0x13245678. However, CPU 1 changes the content of ptr to 0. So
* The CMPXCHG instruction fails (clears ZF).
* emulator_try_cmpxchg_user returns 1.
* emulator_cmpxchg_emulated() returns X86EMUL_CMPXCHG_FAILED.
* segmented_cmpxchg() returns X86EMUL_CMPXCHG_FAILED.
* writeback() returns X86EMUL_CMPXCHG_FAILED.
* x86_emulate_insn() returns EMULATION_OK.

Thus, I think the root cause of this bug is that x86_emulate_insn() ignores the
X86EMUL_CMPXCHG_FAILED error. The correct behavior should be retrying the
emulation using the updated value (similar to load-linked/store-conditional).

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

             reply	other threads:[~2022-12-30  3:02 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-30  3:02 bugzilla-daemon [this message]
2023-01-03 22:05 ` [Bug 216867] New: KVM instruction emulation breaks LOCK instruction atomicity when CMPXCHG fails Sean Christopherson
2023-01-03 22:05 ` [Bug 216867] " bugzilla-daemon
2023-01-03 22:38 ` bugzilla-daemon
2023-01-03 22:39 ` bugzilla-daemon
2023-01-03 22:48 ` bugzilla-daemon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-216867-28872@https.bugzilla.kernel.org/ \
    --to=bugzilla-daemon@kernel.org \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.