virtual secure boot

Secure boot support in qemu, kvm and ovmf.

 

Gerd Hoffmann <kraxel@redhat.com>

33C3, Hamburg

Outline

Terms

secure boot

qemu - quick emulator

kvm - kernel virtual machine

tcg - tiny code generator

edk2 - EFI Development Kit II

ovmf - Open Virtual Machine Firmware

seabios

Two years ago

2014: secure boot support in ovmf

Designing qemu support

Emulate existing hardware

Create paravirtual hardware

Firmware protection on physical hardware

Firmware protection on qemu

Implementing SMM in qemu

qemu: our todo list

qemu: the memory api

qemu: "info mtree" snippet (-M isapc)

memory-region: system
  00000000-ffffffff (prio 0, RW): system
    00000000-07ffffff (prio 0, RW): alias ram-below-4g @pc.ram 00000000-07ffffff
    000a0000-000bffff (prio 1, RW): cirrus-lowmem-container
      000a0000-000a7fff (prio 1, RW): alias vga.bank0 @vga.vram 00000000-00007fff [disabled]
      000a0000-000bffff (prio 0, RW): cirrus-low-memory
      000a8000-000affff (prio 1, RW): alias vga.bank1 @vga.vram 00008000-0000ffff [disabled]
    000c0000-000dffff (prio 1, RW): pc.rom
    000e0000-000fffff (prio 1, RW): alias isa-bios @pc.bios 00000000-0001ffff
    fffe0000-ffffffff (prio 0, RW): pc.bios

qemu: smram/tseg system memory regions (-M q35)

memory-region: system
  00000000-ffffffff (prio 0, RW): system
    00000000-7fffffff (prio 0, RW): alias ram-below-4g @pc.ram 00000000-7fffffff
    00000000-ffffffff (prio -1, RW): pci
      000a0000-000fffff [ ... real mode mappings ... ]
      90000000-fff00000 [ ... pci bars ... ]
    000a0000-000bffff (prio 1, RW): alias smram-region @pci 000a0000-000bffff
    000c0000-000fffff [ ... lots of pam regions ... ]
    7f800000-7fffffff (prio 1, RW): tseg-blackhole
    80000000-8fffffff (prio 0, RW): pcie-mmcfg-mmio
    fec00000-fec00fff (prio 0, RW): ioapic
    feda0000-fedbffff (prio 1, RW): alias smram-open-high @pc.ram 000a0000-000bffff [disabled]
    fee00000-feefffff (prio 4096, RW): apic-msi
    ffe00000-ffe1ffff (prio 0, R-): system.flash1
    ffe20000-ffffffff (prio 0, R-): system.flash0

qemu: smram/tseg memory regions (tcg)

memory-region: smram
  00000000-ffffffff (prio 0, RW): smram
    000a0000-000bffff (prio 0, RW): alias smram-low @pc.ram 000a0000-000bffff
    7f800000-7fffffff (prio 0, RW): alias tseg-window @pc.ram 7f800000-7fffffff
    feda0000-fedbffff (prio 0, RW): alias smram-high @pc.ram 000a0000-000bffff [disabled]
address-space: CPU
  00000000-ffffffff (prio 0, RW): memory
    00000000-ffffffff (prio 1, RW): alias smram @smram 00000000-ffffffff [disabled]
    00000000-ffffffff (prio 0, RW): alias memory @system 00000000-ffffffff
address-space: nec-usb-xhci
  00000000-ffffffff (prio 0, RW): alias bus master @system 00000000-ffffffff

qemu: smram lockbit (from tests/q35-test.c)

static void test_smram_lock(void)
{
    /* check open is settable */
    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);

    /* lock, check open is cleared & not settable */
    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_LCK, true);
    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
}

q35 tseg hardware bug

Flash protection on real q35 hardware

Flash on qemu

Implementing SMM in kvm

Memory regions in kvm mode

kvm: adding SMM support

qemu: smram/tseg memory regions (kvm)

address-space: cpu-memory
  00000000-ffffffff (prio 0, RW): system
    00000000-7fffffff (prio 0, RW): alias ram-below-4g @pc.ram 00000000-7fffffff
    [ ... ]

address-space: KVM-SMRAM
  00000000-ffffffff (prio 0, RW): mem-container-smram
    00000000-ffffffff (prio 10, RW): smram
      000a0000-000bffff (prio 0, RW): alias smram-low @pc.ram 000a0000-000bffff
      7f800000-7fffffff (prio 0, RW): alias tseg-window @pc.ram 7f800000-7fffffff
      feda0000-fedbffff (prio 0, RW): alias smram-high @pc.ram 000a0000-000bffff [disabled]
    00000000-ffffffff (prio 0, RW): alias mem-smram @system 00000000-ffffffff

SMM support for OVMF

Just wire up SMM for OVMF …

Dig up the smm init source code

Merge the smm init source code

Wire up SMM for OVMF

Hands on

Minimum versions

libvirt domain config (RHEL-7.3 host)

<domain type='kvm'>
  <name>secboot-rhel7-kvm</name>
  [ ... ]
  <os>
    <type arch='x86_64' machine='pc-q35-rhel7.3.0'>hvm</type>
    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/.../secboot-rhel7-kvm_VARS.fd</nvram>
  </os>
  <features>
    [ ... ]
    <smm state='on'/>
  </features>
  [ ... ]

Qemu command line

/usr/libexec/qemu-kvm \
    -machine q35,accel=kvm,smm=on \
    -drive file=.../OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,readonly=on \
    -drive file=.../secboot-rhel7-kvm_VARS.fd,if=pflash,format=raw,unit=1 \
    -global driver=cfi.pflash01,property=secure,value=on \
    ${moreargs}

libvirt domain config for older versions

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  [ ... ]
  </devices>
  <qemu:commandline>
    <qemu:arg value='-machine'/>
    <qemu:arg value='smm=on'/>
    <qemu:arg value='-global'/>
    <qemu:arg value='driver=cfi.pflash01,property=secure,value=on'/>
  </qemu:commandline>
</domain>

enroll keys

# dmesg | grep "EFI.*cert"
EFI: Loaded cert 'Microsoft Windows Production PCA 2011: [ ... ]
EFI: Loaded cert 'Microsoft Corporation UEFI CA 2011: [ ... ]
EFI: Loaded cert 'Red Hat Secure Boot (CA key 1): [ ... ]

cutting edge firmware builds

Demo

That's it

/