Signed kernel can load unprotected initrd #65

Closed
opened 2023-01-14 13:54:26 +00:00 by alois31 · 8 comments
alois31 commented 2023-01-14 13:54:26 +00:00 (Migrated from github.com)

As far as I understand, lanzaboote aims to protect the known kernel+initrd combinations using a signature on the stub UKI containing their hashes.

However, it also signs the kernel (presumably so that LoadImage works). Thus, it is possible to instruct systemd-boot to boot a Linux kernel directly, pointing it to an unprotected initrd.

As far as I understand, lanzaboote aims to protect the known kernel+initrd combinations using a signature on the stub UKI containing their hashes. However, it also signs the kernel (presumably so that LoadImage works). Thus, it is possible to instruct systemd-boot to boot a Linux kernel directly, pointing it to an unprotected initrd.
RaitoBezarius commented 2023-01-14 16:39:16 +00:00 (Migrated from github.com)

AFAIK, the stub UKI contains also the command line, the only way I see to load an unprotected initrd is to have:

  • signed systemd-boot
  • signed linux kernel
  • unprotected initrd

trick systemd-boot into loading signed kernel with custom command line to load this particular unprotected initrd directly right?

If systemd-boot prevented loading anything else beyond a UKI, would that close this vulnerability to your opinion?

AFAIK, the stub UKI contains also the command line, the only way I see to load an unprotected initrd is to have: - signed systemd-boot - signed linux kernel - unprotected initrd trick systemd-boot into loading signed kernel with custom command line to load this particular unprotected initrd directly right? If systemd-boot prevented loading anything else beyond a UKI, would that close this vulnerability to your opinion?
alois31 commented 2023-01-14 17:25:54 +00:00 (Migrated from github.com)

AFAIK, the stub UKI contains also the command line, the only way I see to load an unprotected initrd is to have:

* signed systemd-boot

* signed linux kernel

* unprotected initrd

trick systemd-boot into loading signed kernel with custom command line to load this particular unprotected initrd directly right?

Yes, this is exactly what I mean. The kernel is signed, so systemd-boot will happily boot it (with arbitrary cmdline) if instructed to do so via a boot loader entry, and the kernel will in turn load the unsigned initrd because it doesn't even try to verify initrds to begin with.

If systemd-boot prevented loading anything else beyond a UKI, would that close this vulnerability to your opinion?

I believe so.

> AFAIK, the stub UKI contains also the command line, the only way I see to load an unprotected initrd is to have: > > * signed systemd-boot > > * signed linux kernel > > * unprotected initrd > > > trick systemd-boot into loading signed kernel with custom command line to load this particular unprotected initrd directly right? Yes, this is exactly what I mean. The kernel is signed, so systemd-boot will happily boot it (with arbitrary cmdline) if instructed to do so via a boot loader entry, and the kernel will in turn load the unsigned initrd because it doesn't even try to verify initrds to begin with. > If systemd-boot prevented loading anything else beyond a UKI, would that close this vulnerability to your opinion? I believe so.
RaitoBezarius commented 2023-01-14 20:12:50 +00:00 (Migrated from github.com)

Yes, this is exactly what I mean. The kernel is signed, so systemd-boot will happily boot it (with arbitrary cmdline) if instructed to do so via a boot loader entry, and the kernel will in turn load the unsigned initrd because it doesn't even try to verify initrds to begin with.

Okay, going through literature and what systemd has done with UKIs & all, I think this is out of scope for pure SecureBoot protections.

The only way to protect against such threats with SecureBoot only is to use a proper UKI (with the kernel baked in at least) and don't sign non-UKI images, for now, we do not offer such things with lanzaboote at the moment.

Producing UKI though is really easy and has been done as part of https://github.com/DeterminateSystems/bootspec-secureboot that we should maybe salvage to offer this possibility.

Unfortunately, such a mechanism will require "large" ESP or accept to have few generations.

If systemd-boot prevented loading anything else beyond a UKI, would that close this vulnerability to your opinion?

I believe so.

In fact, this might not be a useful thing to pursue because it reduces the problem to find a signed bootloader with custom command line edit allowed when they are not baked in.

Thus, I think this thing should be resolved using a trusted boot mechanism, so relying on TPM2 to prevent decryption of the disk and having the adequate PCRs, etc.

> Yes, this is exactly what I mean. The kernel is signed, so systemd-boot will happily boot it (with arbitrary cmdline) if instructed to do so via a boot loader entry, and the kernel will in turn load the unsigned initrd because it doesn't even try to verify initrds to begin with. Okay, going through literature and what systemd has done with UKIs & all, I think this is out of scope for pure SecureBoot protections. The only way to protect against such threats *with SecureBoot only* is to use a proper UKI (with the kernel baked in at least) and don't sign non-UKI images, for now, we do not offer such things with lanzaboote at the moment. Producing UKI though is really easy and has been done as part of https://github.com/DeterminateSystems/bootspec-secureboot that we should maybe salvage to offer this possibility. Unfortunately, such a mechanism will require "large" ESP or accept to have few generations. > > If systemd-boot prevented loading anything else beyond a UKI, would that close this vulnerability to your opinion? > > I believe so. In fact, this might not be a useful thing to pursue because it reduces the problem to find a signed bootloader with custom command line edit allowed when they are not baked in. Thus, I think this thing should be resolved using a *trusted* boot mechanism, so relying on TPM2 to prevent decryption of the disk and having the adequate PCRs, etc.
alois31 commented 2023-01-15 06:53:26 +00:00 (Migrated from github.com)

Okay, going through literature and what systemd has done with UKIs & all, I think this is out of scope for pure SecureBoot protections.

The only way to protect against such threats with SecureBoot only is to use a proper UKI (with the kernel baked in at least) and don't sign non-UKI images, for now, we do not offer such things with lanzaboote at the moment.

Producing UKI though is really easy and has been done as part of https://github.com/DeterminateSystems/bootspec-secureboot that we should maybe salvage to offer this possibility.

Unfortunately, such a mechanism will require "large" ESP or accept to have few generations.

We would basically have to make sure that we sign nothing that allows loading a kernel with arbitrary initrd or cmdline in the end. I see multiple possibilities for this:

  • Create a "fat" UKI containing the kernel, initrd and cmdline, with the drawback you have already detailed.
  • Do not sign the kernel, and only validate it by its hash. Shim already does similar by verifying payloads against MOKs, but I think they had to implement their own PE loader to do this.
  • Patch systemd-boot to disable booting boot loader specification entries, leaving only UKIs. A pretty major drawback here is that if Microsoft keys are enrolled, it is possibly to replace it by a Microsoft-signed bootloader not carrying that patch (e.g. Fedora's shim+systemd-boot).

In fact, this might not be a useful thing to pursue because it reduces the problem to find a signed bootloader with custom command line edit allowed when they are not baked in.

This reduction is only simple if Microsoft keys are enrolled. Even there, as more of the ecosystem is moving towards UKI, I expect Microsoft to dbx such bootloaders some day (it's likely going to take a few more years, though).

Thus, I think this thing should be resolved using a trusted boot mechanism, so relying on TPM2 to prevent decryption of the disk and having the adequate PCRs, etc.

I'm not really familiar with trusted boot, but as far as I understand, implementing that would require verification of the TMP2 measurements by trusted software. In the present case, I believe this would amount to the kernel doing the verification before it loads any modules (since those come from the untrusted initrd). At this point, you can probably just as well patch the kernel to refuse booting with unsigned initrd and cmdline.

> Okay, going through literature and what systemd has done with UKIs & all, I think this is out of scope for pure SecureBoot protections. > > The only way to protect against such threats _with SecureBoot only_ is to use a proper UKI (with the kernel baked in at least) and don't sign non-UKI images, for now, we do not offer such things with lanzaboote at the moment. > > Producing UKI though is really easy and has been done as part of https://github.com/DeterminateSystems/bootspec-secureboot that we should maybe salvage to offer this possibility. > > Unfortunately, such a mechanism will require "large" ESP or accept to have few generations. We would basically have to make sure that we sign nothing that allows loading a kernel with arbitrary initrd or cmdline in the end. I see multiple possibilities for this: * Create a "fat" UKI containing the kernel, initrd and cmdline, with the drawback you have already detailed. * Do not sign the kernel, and only validate it by its hash. Shim already does similar by verifying payloads against MOKs, but I think they had to implement their own PE loader to do this. * Patch systemd-boot to disable booting boot loader specification entries, leaving only UKIs. A pretty major drawback here is that if Microsoft keys are enrolled, it is possibly to replace it by a Microsoft-signed bootloader not carrying that patch (e.g. Fedora's shim+systemd-boot). > In fact, this might not be a useful thing to pursue because it reduces the problem to find a signed bootloader with custom command line edit allowed when they are not baked in. This reduction is only simple if Microsoft keys are enrolled. Even there, as more of the ecosystem is moving towards UKI, I expect Microsoft to dbx such bootloaders some day (it's likely going to take a few more years, though). > Thus, I think this thing should be resolved using a _trusted_ boot mechanism, so relying on TPM2 to prevent decryption of the disk and having the adequate PCRs, etc. I'm not really familiar with trusted boot, but as far as I understand, implementing that would require verification of the TMP2 measurements by trusted software. In the present case, I believe this would amount to the kernel doing the verification before it loads any modules (since those come from the untrusted initrd). At this point, you can probably just as well patch the kernel to refuse booting with unsigned initrd and cmdline.
blitz commented 2023-01-15 21:54:05 +00:00 (Migrated from github.com)

Do not sign the kernel, and only validate it by its hash. Shim already does similar by verifying payloads against MOKs, but I think they had to implement their own PE loader to do this.

This seems like a pretty practical solution. We might be able to leverage some other entry points of the kernel (PVH or the normal bzImage entry point)

> Do not sign the kernel, and only validate it by its hash. Shim already does similar by verifying payloads against MOKs, but I think they had to implement their own PE loader to do this. This seems like a pretty practical solution. We might be able to leverage some other entry points of the kernel (PVH or the normal bzImage entry point)
duament commented 2023-01-27 10:27:43 +00:00 (Migrated from github.com)

It seems systemd-boot can load unsigned kernel images embedded in UKI by installing a security override.

https://github.com/systemd/systemd/blob/v253-rc1/src/boot/efi/linux.c#L71

https://github.com/systemd/systemd/blob/v253-rc1/src/boot/efi/secure-boot.c#L175

It seems `systemd-boot` can load unsigned kernel images embedded in UKI by installing a security override. https://github.com/systemd/systemd/blob/v253-rc1/src/boot/efi/linux.c#L71 https://github.com/systemd/systemd/blob/v253-rc1/src/boot/efi/secure-boot.c#L175
alois31 commented 2023-01-27 17:05:31 +00:00 (Migrated from github.com)

That's an interesting alternative. I will check that out.

That's an interesting alternative. I will check that out.
alois31 commented 2023-01-27 17:05:45 +00:00 (Migrated from github.com)

That's an interesting alternative. I will check that out.

That's an interesting alternative. I will check that out.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: raito/lanzaboote#65
No description provided.