rhboot / shim

UEFI shim loader
Other
816 stars 284 forks source link

RFC: Revocation Delivery Proposal #655

Open jsetje opened 2 months ago

jsetje commented 2 months ago

Problem:

Revocations beyond dbx require updating non-authenticated boot services variables. Unlike the signed dbx blobs that can be applied at runtime independently from updating the first stage bootloader, these revocations were initially built into shim as an optional “latest” and automatic payload. These payloads exist for both SBAT (shim based Linux distros) and SKU Si (bootmgr based Windows distros). Binaries from both ecosystems can be used to attack both ecosystems on typical systems that trust both the UEFI and Window CA.

While automatically putting a system into the most secure state possible by applying the latest revocation quickly is desirable, it carries a very real risk of preventing a legitimately installed system from booting. These scenarios are fall-back after and update and dual boot. While shim now supports picking up the revocation payload from a separate binary blob that can be updated independently from shim, the policy for deploying this blob will depend on how a particular system is being managed, similar to how dbx updates are being deployed.

Current state:

Most Linux distros are able to deliver a built-in automatic SBAT revocation that revokes binaries that are roughly 1 year old or older. Ones that are not have shifted to an empty automatic SBAT payload. All Linux distros deliver a shim that allows an opt-in SKU Si revocation to be applied, none of them do this automatically.

Windows currently only applies SKU Si revocations based on a manual opt-in and does not deliver SBAT revocations.

Proposal:

Systems should automatically apply the most recent payload for the ecosystem they are not in, unless the other binary is seen as an active bootloader before the one being booted on the boot list. (XXX: This seems awfully complex to protect dual boot systems that already have terrible compatibility. - Still this should be handled the same way by shim and bootmgr)

Systems that potentially need to support falling back to an older version of the same OS will need to manage revocations either manually or as part of an automated orchestration that drives the update / fallback process above the OS instance.

Solution:

Deliver revocations in a separate package that has dependencies that prevent it from being installed on an OS that it would revoke. This package also delivers previous revocations in cumulative blobs. Which revocation is put in place for shim to install can be configured as:

1) Apply the most recent revocation that does not revoke the OS being updated to.

2) Apply the most recent revocation that does not revoke the OS being updated from.

3) Apply the most recent revocation that does not revoke the OS installed at an alternate, supplied, mount location.

4) Manually lock revocations at a specific level.

Defaulting to (2) where (2) is effectively (1) for a fresh install.

Optional dual boot friendly packages:

Deliver an alternate stream of these packages that do not deliver SKU Si revocations for dual boot systems that an admin can opt into under the assumption that they are sometimes booting Windows and want Windows to manage its own revocations.

Rejected Proposal:

Record the hash of in-use bootloaders and add them to an SBAT specific exception list that allows only that binary to elude SBAT based revocation at the same time as applying the revocation.

Pros:

Cons:

Orthogonal concept:

Generic UEFI CA signed revocation.efi binaries could be delivered to fwupd and installed via that framework.

jsetje commented 2 months ago

I posted this issue under the shim repo since more folks are likely to see it here. I expect this to mostly be implemented in https://github.com/rhboot/certwrapper unless I find a bug with the revocation.efi support in shim.

Additional information on the bootmgr SKU Si revocation mechanism can be found here: https://support.microsoft.com/en-us/topic/kb5027455-guidance-for-blocking-vulnerable-windows-boot-managers-522bb851-0a61-44ad-aa94-ad11119c5e91 As of 15.8 shim does have support to apply those revocations as "latest".

hughsie commented 2 months ago

I was pinged about this today -- and I'm wondering what exactly fwupd and the LVFS should do. For instance, could we read /sys/firmware/efi/efivars/SbatLevelRT-605dab50-e046-4300-abb6-3dd810dd8b23 compare it against the metadata from the LVFS and fail an HSI check if the EFI key is older than the metadata value? Or read the shim binary and parse the .sbat section and do the same? That'd get us a nice few FAILED lines on a Insights report for instance.

jsetje commented 2 months ago

LVFS could distribute revocations.efi as well, but it's also not strictly necessary. It might be good to have that mechanism in place in case we ever had to rapidly respond to something bad happening.

I'm not sure I entirely understand what you mean by the check. Would that basically be an audit that would flag if a system is not up to date? That might be nice to have.

hughsie commented 2 months ago

Would that basically be an audit that would flag if a system is not up to date?

Yes -- although I'm a bit unsure where the "canonical truth" is for the sbat level -- and then there's also the sbat data in each file in the ESP, e.g. fwupdtool firmware-parse /boot/efi/EFI/fedora/shimx64.efi pefile gives:

<firmware gtype="FuPefileFirmware">
  <data size="0xe7cb0">[GInputStream]</data>
  <firmware>
    ...
  </firmware>
  <firmware gtype="FuSbatlevelSection">
    <id>.sbatlevel</id>
    <offset>0x7c200</offset>
    <data size="0x6a">AAAAAAgAAAA3AAAAc2JhdCwxLDIwMjMwMTI5MDAKc2hpbSwyCmdydWIsMwpncnViLmRlYmlhbiw0CgBzYmF0LDEsMjAyNDAxMDkwMApzaGltLDQKZ3J1YiwzCmdydWIuZGViaWFuLDQKAA==</data>
    <firmware gtype="FuCsvFirmware">
      <flags>no-auto-detection</flags>
      <id>previous</id>
      <offset>0xc</offset>
      <data size="0x2d">c2JhdCwxLDIwMjMwMTI5MDAKc2hpbSwyCmdydWIsMwpncnViLmRlYmlhbiw0</data>
      <write_column_ids>false</write_column_ids>
      <firmware gtype="FuCsvEntry">
        <id>sbat</id>
        <data size="0x11">c2JhdCwxLDIwMjMwMTI5MDA=</data>
        <values>
          <component_generation>1</component_generation>
          <date_stamp>2023012900</date_stamp>
        </values>
      </firmware>
      <firmware gtype="FuCsvEntry">
        <id>shim</id>
        <idx>0x1</idx>
        <data size="0x6">c2hpbSwy</data>
        <values>
          <component_generation>2</component_generation>
        </values>
      </firmware>
      <firmware gtype="FuCsvEntry">
        <id>grub</id>
        <idx>0x2</idx>
        <data size="0x6">Z3J1Yiwz</data>
        <values>
          <component_generation>3</component_generation>
        </values>
      </firmware>
      <firmware gtype="FuCsvEntry">
        <id>grub.debian</id>
        <idx>0x3</idx>
        <data size="0xd">Z3J1Yi5kZWJpYW4sNA==</data>
        <values>
          <component_generation>4</component_generation>
        </values>
      </firmware>
    </firmware>
    <firmware gtype="FuCsvFirmware">
      <flags>no-auto-detection</flags>
      <id>latest</id>
      <idx>0x1</idx>
      <offset>0x3b</offset>
      <data size="0x2d">c2JhdCwxLDIwMjQwMTA5MDAKc2hpbSw0CmdydWIsMwpncnViLmRlYmlhbiw0</data>
      <write_column_ids>false</write_column_ids>
      <firmware gtype="FuCsvEntry">
        <id>sbat</id>
        <data size="0x11">c2JhdCwxLDIwMjQwMTA5MDA=</data>
        <values>
          <component_generation>1</component_generation>
          <date_stamp>2024010900</date_stamp>
        </values>
      </firmware>
      <firmware gtype="FuCsvEntry">
        <id>shim</id>
        <idx>0x1</idx>
        <data size="0x6">c2hpbSw0</data>
        <values>
          <component_generation>4</component_generation>
        </values>
      </firmware>
      <firmware gtype="FuCsvEntry">
        <id>grub</id>
        <idx>0x2</idx>
        <data size="0x6">Z3J1Yiwz</data>
        <values>
          <component_generation>3</component_generation>
        </values>
      </firmware>
      <firmware gtype="FuCsvEntry">
        <id>grub.debian</id>
        <idx>0x3</idx>
        <data size="0xd">Z3J1Yi5kZWJpYW4sNA==</data>
        <values>
          <component_generation>4</component_generation>
        </values>
      </firmware>
    </firmware>
  </firmware>
  <firmware>
    <id>.data</id>
    <offset>0x7c400</offset>
    <data size="0x2e4f4">[GInputStream]</data>
  </firmware>
  <firmware>
    <id>.vendor_cert</id>
    <offset>0xaaa00</offset>
    <data size="0x46f">[GInputStream]</data>
  </firmware>
  <firmware>
    <id>.dynamic</id>
    <offset>0xab000</offset>
    <data size="0x100">EAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAgDgAAAAAABgAAAAAAAAAAMA0AAAAAAAoAAAAAAAAArqsAAAAAAAALAAAAAAAAABgAAAAAAAAABwAAAAAAAAAAYAsAAAAAAAgAAAAAAAAAaLQBAAAAAAAJAAAAAAAAABgAAAAAAAAAHgAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==</data>
  </firmware>
  <firmware>
    <id>.rela</id>
    <offset>0xab200</offset>
    <data size="0x1b468">[GInputStream]</data>
  </firmware>
  <firmware gtype="FuCsvFirmware">
    <flags>no-auto-detection</flags>
    <id>.sbat</id>
    <offset>0xc6800</offset>
    <data size="0x19f">[GInputStream]</data>
    <write_column_ids>true</write_column_ids>
    <firmware gtype="FuCsvEntry">
      <id>sbat</id>
      <version>1</version>
      <version_raw>0x1</version_raw>
      <data size="0x4b">c2JhdCwxLFNCQVQgVmVyc2lvbixzYmF0LDEsaHR0cHM6Ly9naXRodWIuY29tL3JoYm9vdC9zaGltL2Jsb2IvbWFpbi9TQkFULm1k</data>
      <values>
        <vendor_name>SBAT Version</vendor_name>
        <vendor_package_name>sbat</vendor_package_name>
        <vendor_url>https://github.com/rhboot/shim/blob/main/SBAT.md</vendor_url>
      </values>
    </firmware>
    <firmware gtype="FuCsvEntry">
      <id>shim</id>
      <idx>0x1</idx>
      <version>1</version>
      <version_raw>0x4</version_raw>
      <data size="0x36">c2hpbSw0LFVFRkkgc2hpbSxzaGltLDEsaHR0cHM6Ly9naXRodWIuY29tL3JoYm9vdC9zaGlt</data>
      <values>
        <vendor_name>UEFI shim</vendor_name>
        <vendor_package_name>shim</vendor_package_name>
        <vendor_url>https://github.com/rhboot/shim</vendor_url>
      </values>
    </firmware>
    <firmware gtype="FuCsvEntry">
      <id>shim.rh</id>
      <idx>0x2</idx>
      <version>15.8</version>
      <version_raw>0x3</version_raw>
      <data size="0x5b">c2hpbS5yaCwzLFRoZSBGZWRvcmEgUHJvamVjdCxzaGltLDE1LjgsaHR0cHM6Ly9zcmMuZmVkb3JhcHJvamVjdC5vcmcvcnBtcy9zaGltLXVuc2lnbmVkLXg2NA==</data>
      <values>
        <vendor_name>The Fedora Project</vendor_name>
        <vendor_package_name>shim</vendor_package_name>
        <vendor_url>https://src.fedoraproject.org/rpms/shim-unsigned-x64</vendor_url>
      </values>
    </firmware>
    <firmware gtype="FuCsvEntry">
      <id>shim.redhat</id>
      <idx>0x3</idx>
      <version>15.8</version>
      <version_raw>0x3</version_raw>
      <data size="0x5f">c2hpbS5yZWRoYXQsMyxUaGUgRmVkb3JhIFByb2plY3Qsc2hpbSwxNS44LGh0dHBzOi8vc3JjLmZlZG9yYXByb2plY3Qub3JnL3JwbXMvc2hpbS11bnNpZ25lZC14NjQ=</data>
      <values>
        <vendor_name>The Fedora Project</vendor_name>
        <vendor_package_name>shim</vendor_package_name>
        <vendor_url>https://src.fedoraproject.org/rpms/shim-unsigned-x64</vendor_url>
      </values>
    </firmware>
    <firmware gtype="FuCsvEntry">
      <id>shim.fedora</id>
      <idx>0x4</idx>
      <version>15.8</version>
      <version_raw>0x3</version_raw>
      <data size="0x5f">c2hpbS5mZWRvcmEsMyxUaGUgRmVkb3JhIFByb2plY3Qsc2hpbSwxNS44LGh0dHBzOi8vc3JjLmZlZG9yYXByb2plY3Qub3JnL3JwbXMvc2hpbS11bnNpZ25lZC14NjQ=</data>
      <values>
        <vendor_name>The Fedora Project</vendor_name>
        <vendor_package_name>shim</vendor_package_name>
        <vendor_url>https://src.fedoraproject.org/rpms/shim-unsigned-x64</vendor_url>
      </values>
    </firmware>
  </firmware>
</firmware>
jsetje commented 2 months ago

At the moment, the canonical truth for SbatLevel is tracked here: https://github.com/rhboot/shim/blob/main/SbatLevel_Variable.txt

However as part of addressing this issue, I very much want to make that a single (probably sub) repo that will drive building the various pieces.

hughsie commented 2 months ago

I don't think that document qualifies as canonical truth :)