Windows 10 RS1 & Server 2016 VGA bug

This is a brief note on a new Windows bug that was discovered recently. Windows 10 RS1 (aka Anniversary Update) and Windows Server 2016 RTM added a new BSOD graphical element, namely a QR code which points to http://windows.com/stopcode. This has even received media coverage.

bsod_qrcode

Unfortunately the QR code rendering code has a bug. If Windows decides to use a 24 bits-per-pixel VGA mode for displaying the blue screen, it crashes at a callstack similar to this:

nt!BgpGxConvertRectangle
nt!BgpGxDrawRectangle
nt!BgpFwDisplayBugCheckScreen
nt!KiDisplayBlueScreen
nt!KeBugCheck2

The code in BgpGxConvertRectangle appears to be performing a pixel format conversion of some sort and overruns its buffer. Note that this is a traditional BIOS VGA mode and has nothing to do with how the Windows display driver is set up. After all, it may be the display driver crashing here so Windows needs a robust way to present the user with graphical output.

Crashing an already crashed machine doesn’t sound like a big deal, but it prevents the crash dump generation code from running which makes diagnosing the initial crash much harder.

As for the impact of the bug, it is uncommon for a modern VGA BIOS to support 24 bpp modes – they have been obsoleted by 32 bpp ones long time ago. Fun exercise, run the following commands at the grub command line:

grub> insmod all_video
grub> videoinfo

But there is one important exception: SeaBIOS. This popular BIOS/VGA BIOS implementation used by emulators like QEMU/KVM provides two kinds of virtual VGA adapters: one Cirrus and a handful of Bochs-based ones. All of them have a 24 bpp VGA mode which Windows happens to use – VBE mode 0x118 1024 x 768 24 bpp. So in summary, due to this Windows bug it is not possible to get a Windows crash dump out of a QEMU/KVM virtual machine.

Fixes and workarounds

The Cirrus virtual adapter does not support any 32 bpp modes and should simply not be used at all. In the QEMU/KVM context, avoid the following:

-vga cirrus

and instead use one of

-vga std
-vga qxl
-vga virtio
-vga vmware

to get an adapter that supports both 24 bpp and 32 bpp modes. That’s not enough though, because at boot time Windows sees the 24 bpp mode first and will use it even though a better one is available. The only known workaround at the moment is to change the order in which video modes are enumerated to make sure that Windows sees 32 bpp first:
https://www.coreboot.org/pipermail/seabios/2016-October/010963.html

The issue can also be completely side-stepped by switching from SeaBIOS to OVMF as the virtual machine firmware. This is definitely a less commonly used configuration, but it should work fine with modern guest operating systems.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s