mbox series

[0/2] Sign the Image which is zboot's payload

Message ID 20230921133703.39042-1-kernelfans@gmail.com (mailing list archive)
Headers show
Series Sign the Image which is zboot's payload | expand

Message

Pingfan Liu Sept. 21, 2023, 1:37 p.m. UTC
From: Pingfan Liu <piliu@redhat.com>

I hesitate to post this series, since Ard has recommended using an
emulated UEFI boot service to resolve the UKI kexec load problem [1].
since on aarch64, vmlinuz.efi has faced the similar issue at present.
But anyway, I have a crude outline of it and am sending it out for
discussion.

For security boot, the vmlinuz.efi will be signed so UEFI boot loader
can check against it. But at present, there is no signature for kexec
file load, this series makes a signature on the zboot's payload -- Image
before it is compressed. As a result, the kexec-tools parses and
decompresses the Image.gz to get the Image, which has signature and can
be checked against during kexec file load

[1]: https://lore.kernel.org/lkml/20230918173607.421d2616@rotkaeppchen/T/#mc60aa591cb7616ceb39e1c98f352383f9ba6e985

Cc: "Ard Biesheuvel <ardb@kernel.org>"
Cc: "Jan Hendrik Farr" <kernel@jfarr.cc>
Cc: "Baoquan He" <bhe@redhat.com>
Cc: "Dave Young" <dyoung@redhat.com>
Cc: "Philipp Rudo" <prudo@redhat.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
To: linux-arm-kernel@lists.infradead.org
To: linux-efi@vger.kernel.org
To: kexec@lists.infradead.org


Pingfan Liu (2):
  zboot: Signing the payload
  arm64: Enable signing on the kernel image loaded by kexec file load

 arch/arm64/Kconfig                          |  2 +
 drivers/firmware/efi/libstub/Makefile.zboot | 23 +++++++--
 kernel/Kconfig.kexec_sign                   | 54 +++++++++++++++++++++
 3 files changed, 76 insertions(+), 3 deletions(-)
 create mode 100644 kernel/Kconfig.kexec_sign

Comments

Jan Hendrik Farr Sept. 22, 2023, 5:19 a.m. UTC | #1
Hi Pingfan!

On 21 21:37:01, Pingfan Liu wrote:
> From: Pingfan Liu <piliu@redhat.com>
> 

> For security boot, the vmlinuz.efi will be signed so UEFI boot loader
> can check against it. But at present, there is no signature for kexec
> file load, this series makes a signature on the zboot's payload -- Image
> before it is compressed. As a result, the kexec-tools parses and
> decompresses the Image.gz to get the Image, which has signature and can
> be checked against during kexec file load

I missed some of the earlier discussion about this zboot kexec support.
So just let me know if I'm missing something here. You were exploring
these two options in getting this supported:

1. Making kexec_file_load do all the work.

This option makes the signature verification easy. kexec_file_load
checks the signature on the pe file and then extracts it and does the
kexec.

This is similar to how I'm approaching UKI support in [1].

2. Extract in userspace and pass decompressed kernel to kexec_file_load

This options requires the decompressed kernel to have a valid signature on
it. That's why this patch adds the ability to add that signature to the
kernel contained inside the zboot image.

This option would not make sense for UKI support as it would not
validate the signature with respect to the initrd and cmdline that it
contains. Am I correct in thinking that there is no similar issue with
zboot images? They don't contain any more information besides the kernel
that is intended to be securely signed, right? Do you have a reference
for the zboot image layout somewhere?

> I hesitate to post this series, 

I appreciate you sending it, it's helping the discussion along.

> [...] since Ard has recommended using an
> emulated UEFI boot service to resolve the UKI kexec load problem [1].
> since on aarch64, vmlinuz.efi has faced the similar issue at present.
> But anyway, I have a crude outline of it and am sending it out for
> discussion.

The more I'm thinking about it, the more I like Ard's idea. There's now
already two different formats trying to be added to kexec that are
pretty different from each other, yet they both have the UEFI interface
in common. I think if the kernel supported kexec'ing EFI applications
that would be a more flexible and forward-looking approach. It's a
standard that both zboot and UKI as well as all future formats for UEFI
platforms will support anyways. So while it's more work right now to
implement, I think it'll likely pay off.

It is significantly more work than the other options though. So I think
before work is started on it, it would be nice to get some type of
consensus on these things (not an exhaustive list, please feel free to
add to it):

1. Is it the right approach? It adds a significant amount of userspace
API.
2. What subset of the UEFI spec needs/should to be supported?
3. Can we let runtime services still be handled by the firmware after
exiting boot services?
4. How can we debug the stubs that are being invoked?
5. Can we let the EFI binary know that this is a kexec and not a normal
bootup. Potentially systemd-stub would want to change how/if it does TPM
PCR measurements.
...


[1] https://lore.kernel.org/kexec/20230911052535.335770-2-kernel@jfarr.cc/T/

Added some more CCs.
Dave Young Sept. 22, 2023, 5:41 a.m. UTC | #2
Hi Jan,

On Fri, 22 Sept 2023 at 13:19, Jan Hendrik Farr <kernel@jfarr.cc> wrote:
>
> Hi Pingfan!
>
> On 21 21:37:01, Pingfan Liu wrote:
> > From: Pingfan Liu <piliu@redhat.com>
> >
>
> > For security boot, the vmlinuz.efi will be signed so UEFI boot loader
> > can check against it. But at present, there is no signature for kexec
> > file load, this series makes a signature on the zboot's payload -- Image
> > before it is compressed. As a result, the kexec-tools parses and
> > decompresses the Image.gz to get the Image, which has signature and can
> > be checked against during kexec file load
>
> I missed some of the earlier discussion about this zboot kexec support.
> So just let me know if I'm missing something here. You were exploring
> these two options in getting this supported:
>
> 1. Making kexec_file_load do all the work.
>
> This option makes the signature verification easy. kexec_file_load
> checks the signature on the pe file and then extracts it and does the
> kexec.
>
> This is similar to how I'm approaching UKI support in [1].
>
> 2. Extract in userspace and pass decompressed kernel to kexec_file_load
>
> This options requires the decompressed kernel to have a valid signature on
> it. That's why this patch adds the ability to add that signature to the
> kernel contained inside the zboot image.
>
> This option would not make sense for UKI support as it would not
> validate the signature with respect to the initrd and cmdline that it
> contains.

Another possibility for the cmdline could be using the bootconfig
facility which was
introduced for boot time tracking:
Documentation/admin-guide/bootconfig.rst

So the initrd+cmdline can be signed as well.  Has this been discussed
before for UKI?

Thanks
Dave
Pingfan Liu Sept. 25, 2023, 3:01 a.m. UTC | #3
On Fri, Sep 22, 2023 at 1:19 PM Jan Hendrik Farr <kernel@jfarr.cc> wrote:
>
> Hi Pingfan!
>
> On 21 21:37:01, Pingfan Liu wrote:
> > From: Pingfan Liu <piliu@redhat.com>
> >
>
> > For security boot, the vmlinuz.efi will be signed so UEFI boot loader
> > can check against it. But at present, there is no signature for kexec
> > file load, this series makes a signature on the zboot's payload -- Image
> > before it is compressed. As a result, the kexec-tools parses and
> > decompresses the Image.gz to get the Image, which has signature and can
> > be checked against during kexec file load
>
> I missed some of the earlier discussion about this zboot kexec support.
> So just let me know if I'm missing something here. You were exploring
> these two options in getting this supported:
>
> 1. Making kexec_file_load do all the work.
>
> This option makes the signature verification easy. kexec_file_load
> checks the signature on the pe file and then extracts it and does the
> kexec.
>
> This is similar to how I'm approaching UKI support in [1].
>

Yes, that is my original try.

> 2. Extract in userspace and pass decompressed kernel to kexec_file_load
>
> This option requires the decompressed kernel to have a valid signature on
> it. That's why this patch adds the ability to add that signature to the
> kernel contained inside the zboot image.
>

You got it.

> This option would not make sense for UKI support as it would not
> validate the signature with respect to the initrd and cmdline that it
> contains. Am I correct in thinking that there is no similar issue with
> zboot images? They don't contain any more information besides the kernel
> that is intended to be securely signed, right? Do you have a reference

If using my second method, it means to unpack the UKI image in user
space, and pass the kernel image, initrd and cmdline through
kexec_file_load interface. If the UKI can have signature on the initrd
and cmdline, we extend the capability of that interface to check those
verification.

> for the zboot image layout somewhere?
>

Sorry that maybe there is no document. I understand them through the code.
The zboot image, aka, vmlinuz.efi looks like:
PE header, which is formed manually in arch/arm64/kernel/head.S
EFI decompressor, which consists of
drivers/firmware/efi/libstub/zboot.c and libstub
Image.gz, which is formed by compressing Image as instructed in Makefile.zboot


> > I hesitate to post this series,
>
> I appreciate you sending it, it's helping the discussion along.
>
> > [...] since Ard has recommended using an
> > emulated UEFI boot service to resolve the UKI kexec load problem [1].
> > since on aarch64, vmlinuz.efi has faced the similar issue at present.
> > But anyway, I have a crude outline of it and am sending it out for
> > discussion.
>
> The more I'm thinking about it, the more I like Ard's idea. There's now
> already two different formats trying to be added to kexec that are
> pretty different from each other, yet they both have the UEFI interface
> in common. I think if the kernel supported kexec'ing EFI applications
> that would be a more flexible and forward-looking approach. It's a

Yes, I agree. That method is attractive, originally I had a try when
Ard suggested it but there was no clear boundary on which boot service
should be implemented for zboot, so I did not move on along that
direction.

Now, UKI poses another challenge to kexec_file_load, and seems to
require more than zboot. And it appears that Ard's approach is a
silver bullet for that issue.

> standard that both zboot and UKI as well as all future formats for UEFI
> platforms will support anyways. So while it's more work right now to
> implement, I think it'll likely pay off.
>
> It is significantly more work than the other options though. So I think
> before work is started on it, it would be nice to get some type of
> consensus on these things (not an exhaustive list, please feel free to
> add to it):
>

I try to answer part of the questions.

> 1. Is it the right approach? It adds a significant amount of userspace
> API.

My crude assumption: this new stub will replace the purgatory, and I
am not sure whether kexec-tools source tree will accommodate it. It
can be signed and checked during the kexec_file_load.

> 2. What subset of the UEFI spec needs/should to be supported?
> 3. Can we let runtime services still be handled by the firmware after
> exiting boot services?

I think the runtime services survive through the kexec process. It is
derived from the real firmware, not related with this stub

> 4. How can we debug the stubs that are being invoked?
> 5. Can we let the EFI binary know that this is a kexec and not a normal
> bootup. Potentially systemd-stub would want to change how/if it does TPM
> PCR measurements.
> ...
>

Besides these questions, I wonder whether a highly configured EDK2 can
be used as the stub (ArmVirtQemuKernel.dsc can be the start point).
But there should be efforts to exclude the drivers which have the MMIO
access. I saw Ard is active in EDK2, maybe that is the reason why he
did not pick up EDK2 to serve the stub.


Thanks,

Pingfan
Ard Biesheuvel Sept. 25, 2023, 8:55 a.m. UTC | #4
On Mon, 25 Sept 2023 at 03:01, Pingfan Liu <piliu@redhat.com> wrote:
>
> On Fri, Sep 22, 2023 at 1:19 PM Jan Hendrik Farr <kernel@jfarr.cc> wrote:
> >
...
> > I missed some of the earlier discussion about this zboot kexec support.
> > So just let me know if I'm missing something here. You were exploring
> > these two options in getting this supported:
> >
> > 1. Making kexec_file_load do all the work.
> >
> > This option makes the signature verification easy. kexec_file_load
> > checks the signature on the pe file and then extracts it and does the
> > kexec.
> >
> > This is similar to how I'm approaching UKI support in [1].
> >
>
> Yes, that is my original try.
>
> > 2. Extract in userspace and pass decompressed kernel to kexec_file_load
> >
> > This option requires the decompressed kernel to have a valid signature on
> > it. That's why this patch adds the ability to add that signature to the
> > kernel contained inside the zboot image.
> >
>
> You got it.
>
> > This option would not make sense for UKI support as it would not
> > validate the signature with respect to the initrd and cmdline that it
> > contains. Am I correct in thinking that there is no similar issue with
> > zboot images? They don't contain any more information besides the kernel
> > that is intended to be securely signed, right? Do you have a reference
>
> If using my second method, it means to unpack the UKI image in user
> space, and pass the kernel image, initrd and cmdline through
> kexec_file_load interface. If the UKI can have signature on the initrd
> and cmdline, we extend the capability of that interface to check those
> verification.
>
> > for the zboot image layout somewhere?
> >
>
> Sorry that maybe there is no document. I understand them through the code.
> The zboot image, aka, vmlinuz.efi looks like:
> PE header, which is formed manually in arch/arm64/kernel/head.S
> EFI decompressor, which consists of
> drivers/firmware/efi/libstub/zboot.c and libstub
> Image.gz, which is formed by compressing Image as instructed in Makefile.zboot
>
>

Indeed, this is currently only documented in code. zboot is a PE
executable that decompresses the kernel and boots it, but it also
carries the base and size of the compressed payload in its header,
along with the compression type so non-EFI loaders can run it as well
(QEMU implements this for gzip on arm64)

> > > I hesitate to post this series,
> >
> > I appreciate you sending it, it's helping the discussion along.
> >

Absolutely. RFCs are important because nobody knows how exactly the
code will look until someone takes the time to implement it. So your
work on this is much appreciated, even if we may decide to take
another approach down the road.

> > > [...] since Ard has recommended using an
> > > emulated UEFI boot service to resolve the UKI kexec load problem [1].
> > > since on aarch64, vmlinuz.efi has faced the similar issue at present.
> > > But anyway, I have a crude outline of it and am sending it out for
> > > discussion.
> >
> > The more I'm thinking about it, the more I like Ard's idea. There's now
> > already two different formats trying to be added to kexec that are
> > pretty different from each other, yet they both have the UEFI interface
> > in common. I think if the kernel supported kexec'ing EFI applications
> > that would be a more flexible and forward-looking approach. It's a
>
> Yes, I agree. That method is attractive, originally I had a try when
> Ard suggested it but there was no clear boundary on which boot service
> should be implemented for zboot, so I did not move on along that
> direction.
>
> Now, UKI poses another challenge to kexec_file_load, and seems to
> require more than zboot. And it appears that Ard's approach is a
> silver bullet for that issue.
>

Yes, it looks appealing but it will take some time to iterate on ideas
and converge on an implementation.

> > standard that both zboot and UKI as well as all future formats for UEFI
> > platforms will support anyways. So while it's more work right now to
> > implement, I think it'll likely pay off.
> >
> > It is significantly more work than the other options though. So I think
> > before work is started on it, it would be nice to get some type of
> > consensus on these things (not an exhaustive list, please feel free to
> > add to it):
> >
>
> I try to answer part of the questions.
>
> > 1. Is it the right approach? It adds a significant amount of userspace
> > API.
>
> My crude assumption: this new stub will replace the purgatory, and I
> am not sure whether kexec-tools source tree will accommodate it. It
> can be signed and checked during the kexec_file_load.
>
> > 2. What subset of the UEFI spec needs/should to be supported?
> > 3. Can we let runtime services still be handled by the firmware after
> > exiting boot services?
>
> I think the runtime services survive through the kexec process. It is
> derived from the real firmware, not related with this stub
>

Yes, this should be possible.

> > 4. How can we debug the stubs that are being invoked?
> > 5. Can we let the EFI binary know that this is a kexec and not a normal
> > bootup. Potentially systemd-stub would want to change how/if it does TPM
> > PCR measurements.
> > ...
> >
>

Not sure whether this matters. The TPM logic is exposed via EFI
protocols, and the kernel could either expose them or not. If it does,
and we execute the EFI stub (sytemd-stub) code all the way through to
ExitBootServices() while executing in the old kernel, we could even
take PCR measurements and display them, giving us secure and measured
boot for kexec.

> Besides these questions, I wonder whether a highly configured EDK2 can
> be used as the stub (ArmVirtQemuKernel.dsc can be the start point).
> But there should be efforts to exclude the drivers which have the MMIO
> access. I saw Ard is active in EDK2, maybe that is the reason why he
> did not pick up EDK2 to serve the stub.
>

I don't think EDK2 is suitable for this - the code style is different,
the license is different and it is simply a lot of code.

What I would prefer is to define a subset of the EFI boot services
that we actually rely on, and perhaps even introduce some other
constraints on the EFI code, e.g., allow it to run unprivileged.

That way, kexec could execute the EFI stub as an ordinary user process
(to some extent), including allocations for the decompressed kernel,
initrd, etc. Finally, the only thing purgatory would need to do is
linearize the populated regions in the VA space and copy them to
physical memory.

This all sounds very high-level, and there may be some difficulties
down the road, but I think this deserves a proper look because it is
an appealing way to make EFI execution idempotent in the context of
kexec, and also reduces the arch-specific logic substantially.
Philipp Rudo Sept. 25, 2023, 3:24 p.m. UTC | #5
Hi Dave,

On Fri, 22 Sep 2023 13:41:22 +0800
Dave Young <dyoung@redhat.com> wrote:

> Hi Jan,
> 
> On Fri, 22 Sept 2023 at 13:19, Jan Hendrik Farr <kernel@jfarr.cc> wrote:
> >
> > Hi Pingfan!
> >
> > On 21 21:37:01, Pingfan Liu wrote:  
> > > From: Pingfan Liu <piliu@redhat.com>
> > >  
> >  
> > > For security boot, the vmlinuz.efi will be signed so UEFI boot loader
> > > can check against it. But at present, there is no signature for kexec
> > > file load, this series makes a signature on the zboot's payload -- Image
> > > before it is compressed. As a result, the kexec-tools parses and
> > > decompresses the Image.gz to get the Image, which has signature and can
> > > be checked against during kexec file load  
> >
> > I missed some of the earlier discussion about this zboot kexec support.
> > So just let me know if I'm missing something here. You were exploring
> > these two options in getting this supported:
> >
> > 1. Making kexec_file_load do all the work.
> >
> > This option makes the signature verification easy. kexec_file_load
> > checks the signature on the pe file and then extracts it and does the
> > kexec.
> >
> > This is similar to how I'm approaching UKI support in [1].
> >
> > 2. Extract in userspace and pass decompressed kernel to kexec_file_load
> >
> > This options requires the decompressed kernel to have a valid signature on
> > it. That's why this patch adds the ability to add that signature to the
> > kernel contained inside the zboot image.
> >
> > This option would not make sense for UKI support as it would not
> > validate the signature with respect to the initrd and cmdline that it
> > contains.  
> 
> Another possibility for the cmdline could be using the bootconfig
> facility which was
> introduced for boot time tracking:
> Documentation/admin-guide/bootconfig.rst
> 
> So the initrd+cmdline can be signed as well.  Has this been discussed
> before for UKI?

Not that I know of. But I'm not sure if the bootconfig the way it works
today does the trick.

For one the bootconfig is simply glued to the end of the initrd. But
that makes it part of the UKI as well. So there is no added gain.

Plus, adding the cmdline to the UKI was done on purpose to prevent any
unauthorized editing. That basically means that any change to the
cmdline needs to be signed as well. But I don't see any signature
verification while processing the bootconfig. 

Finally the bootconfig is setup too late in the boot process,
in particular after setup_arch which reserves the crashkernel
memory and needs to parse the kernel command line for that. An even more
extreme example is the decompressor phase on s390. There the command
line is parsed as well. And that is code that runs before start_kernel.

All in all I don't believe that using the bootconfig adds much benefit
for the UKI.

Thanks
Philipp
Jan Hendrik Farr Sept. 27, 2023, 11:46 p.m. UTC | #6
On 25 08:55:46, Ard Biesheuvel wrote:
> On Mon, 25 Sept 2023 at 03:01, Pingfan Liu <piliu@redhat.com> wrote:
>
> [...]
>
> > > 4. How can we debug the stubs that are being invoked?
> > > 5. Can we let the EFI binary know that this is a kexec and not a normal
> > > bootup. Potentially systemd-stub would want to change how/if it does TPM
> > > PCR measurements.
> > > ...
> > >
> >
> 
> Not sure whether this matters. The TPM logic is exposed via EFI
> protocols, and the kernel could either expose them or not. If it does,
> and we execute the EFI stub (sytemd-stub) code all the way through to
> ExitBootServices() while executing in the old kernel, we could even
> take PCR measurements and display them, giving us secure and measured
> boot for kexec.
> 

I think we should definitely delay any of the measurements until
ExitBootServices(). We don't wan't measurements of a kernel that is not
running and might even get unloaded before being kexec'ed to make their
way into the TPM.

> > Besides these questions, I wonder whether a highly configured EDK2 can
> > be used as the stub (ArmVirtQemuKernel.dsc can be the start point).
> > But there should be efforts to exclude the drivers which have the MMIO
> > access. I saw Ard is active in EDK2, maybe that is the reason why he
> > did not pick up EDK2 to serve the stub.
> >
> 
> I don't think EDK2 is suitable for this - the code style is different,
> the license is different and it is simply a lot of code.
> 
> What I would prefer is to define a subset of the EFI boot services
> that we actually rely on, and perhaps even introduce some other
> constraints on the EFI code, e.g., allow it to run unprivileged.
> 
> That way, kexec could execute the EFI stub as an ordinary user process
> (to some extent), including allocations for the decompressed kernel,
> initrd, etc. Finally, the only thing purgatory would need to do is
> linearize the populated regions in the VA space and copy them to
> physical memory.
> 
> This all sounds very high-level, and there may be some difficulties
> down the road, but I think this deserves a proper look because it is
> an appealing way to make EFI execution idempotent in the context of
> kexec, and also reduces the arch-specific logic substantially.

I just started work on a proof-of-concept implementation of this [1]. It's
kinda unorganized and early right now though. Currently just testing with
executing a bzimage with the normal EFI stub on x86. At this point it starts
executing the EFI stub which checks efi_system_table->hdr.signature for the
correct signature (which I have not set yet). That causes the EFI stub to
exit. It does correctly call the exit function from my provided boot services
table and the correct ExitStatus gets logged in dmesg. So it's able to call
into my boot services correctly.

This is definitly the most low level code I've ever written though, so
I'm just learning this stuff.

Next I'll work on setting up a proper memory mapping for the EFI
application.

After that I'll work on implementing the needed boot services and
protocols.

[1] https://github.com/Cydox/linux/commits/kexec-uefi

--

Jan