Hi Boyang, On Thu, Dec 22, 2022 at 10:37:01PM +0800, Zhang Boyang wrote:
[...] > > > On 2022/12/22 19:14, Leo Yan wrote: > > > > When boot from menu and the flag GRUB_VERIFY_FLAGS_DEFER_AUTH is set, > > > > grub returns error: > > > > > > > > Booting a command list > > > > > > > > error: verification requested but nobody cares: (hd0,gpt1)/Image. > > > > > > > > Press any key to continue... > > > > > > > > In this case, the image should be deferred for authentication, grub > > > > should return the file handle and pass down to later firmware (e.g. > > > > U-Boot, etc) for authentication. > > > > > > This is probably not what verification framework designed to be. It seems > > > to > > > be designed to verify files during GRUB is executing (e.g. check file > > > signature if UEFI Secure Boot is enabled). > > > > Good point. We expect the solution is grub can defer authentication for > > an image and invokes EFI LoadImage service, then EFI loader can load > > and verify the image. > > Since you mentioned "authentication" and "verify", I guess you are > using/implementing some kind of secure boot mechanism. Is it an standard > UEFI Secure Boot implementation? I don't read specification for standard UEFI secure boot, but from my very limited understanding, I don't think now I am using a standard UEFI secure boot sequence. Anyway, I will explain more in below comments. > The standard UEFI Secure Boot for Linux works like this (at least on x86): > > 1) Firmware verifies and loads shim (shimx64.efi), which is signed by > Microsoft. (https://github.com/rhboot/shim ) > > 2) shim registers an EFI protocol, to provide an API for verifying files. > > 3) shim verifies and loads GRUB (grubx64.efi), using certificate embedded in > itself. The certificate is generated by vendor (e.g. Debian). > > 4) GRUB opens kernel image file and loads and executes that file. The key > point is, during grub_file_open() of the kernel image, the verifier > framework will call shim lock verifier, which calls the API provided by > shim, to verify the signature of kernel file. (grub-core/kern/efi/sb.c) > > In the above example, the kernel is loaded by GRUB, not shim, not EFI > firmware. GRUB calls the API provided by shim to verify the kernel. > > Another example is GRUB can also chainload Windows: > > 1) 2) 3) is same > > 4) GRUB invokes EFI firmware's LoadFile() and StartImage(). The verification > is completely delegated to EFI firmware. shim is not envolved. > > In this example, the verification is done by EFI firmware, and GRUB/shim has > no control of it. You can't even chainload GRUB itself because it's not > signed by Microsoft. Very good summary, thanks a lot! > > For more specific, now I am debugging U-boot EFI with grub, since U-boot > > EFI provides functionality for loading and authentication image (see > > efi_load_image() in [1]), this is my purpose to use U-boot EFI to > > authenticate kernel image (and even for initrd image). > > > > It seems efi_load_image() is just a wrapper of EFI firmware's LoadFile() and > there is no implementation of verification in U-boot? This isn't right. U-boot EFI service verifies image with below flow: efi_load_image() `> efi_load_pe() `> efi_image_authenticate() > I'd like to ask what kind of image you are trying to boot/execute? If it is > an EFI application, I think you can "chainloader" it and forget U-boot (if > U-boot have no verification in it self). We want to create a trust of chian: firmware -> U-boot -> GRUB -> Linux kernel image / initrd / grub.cfg Comparing against you mentioned solution which uses shim to verify and load GRUB, we use U-boot to verify and load GRUB. Therefore, in our implementation we don't use shim verifier for GRUB, and not for later Linux kernel image / initrd / GRUB config files. > Let me guess: You are using standard Secure Boot, and want to boot linux > kernel image directly signed by keys in EFI firmware, and your GRUB is > installed with --disable-shim-lock. If this is what you are doing, you might > run into the following situation: > > 1) During GRUB init, grub_efi_init() detects Secure Boot is enabled, so it > calls grub_lockdown(). [grub-core/kern/efi/init.c] > > 2) grub_lockdown() registers lockdown verifier. [grub-core/kern/lockdown.c] > > 3) grub_efi_init() also calls grub_shim_lock_verifier_setup(). However, > grub_shim_lock_verifier_setup() does nothing because of > "--disable-shim-lock" [grub-core/kern/efi/sb.c] > > 4) During GRUB load linux kernel, the lockdown verifier sets a flag > (GRUB_VERIFY_FLAGS_DEFER_AUTH) for kernel file, and expect shim lock > verifier to do the verification. > > 5) However, there is no shim lock verifier. As a security measure, it > reports the error "verification requested but nobody cares". > > So the root cause seems like --disable-shim-lock is broken? Excellent analysis, and it's exactly an issue I am facing. > As a workaround, you can use shim: build shim for you platform and install > GRUB with shim support. > > You can also submit a fix to --disable-shim-lock (recommended). However it > should be done very carefully. I'm afraid you can't remove the security > measure (i.e. the "verification requested but nobody cares") directly. I > think it is a good idea to add an EFI verifier (like shim verifier), which > use LoadImage() to do verification, and enable it if (and only if) > --disable-shim-lock is specified. You can talk to GRUB maintainers about > your proposal before coding. Thanks a lot for the suggestion. As you proposed to add an EFI verifier, this would be a candidate solution we should consider seriously, seems to me, this is a neat way to allow us to hook the verifier in U-boot and GRUB. However, I found actually we have another choice (though it's not neat but it does work after I did some experiments). We can enable GRUB's internal verifier 'gpg', thus we can sign grub.cfg / kernel image / initrd with the gpg key and GRUB will use 'gpg' verifier to load these images, please note, we sign these files with detached format so every file has a corresponding signature file with suffix '.sig'. The tricky thing is the kernel image, since GRUB invokes EFI LoadImage() to load kernel image, and the kernel image has a self-contained signature, so finally the kernel image also will be authenticated by U-boot's EFI service. This means the kernel image will be authenticated for twice, one is by GRUB's verifier and another is by U-boot's efi_load_image(). At least it's a pragmatic solution for me, I will check internally if we should move forward for using a central place (like U-boot) for all files authentication and it also can simplify the key management. > The above is what I guess about what's happening. It might be wrong. Please > point out if there is something wrong. I would like to step back a bit and ask a question: if GRUB doesn't enable any crypto verifier and it runs into grub_verifiers_open(), in current code grub_verifiers_open() prevents to load kernel image. In this case, here I am confused why we cannot proceed to load kernel image? Or I want to check with maintainers if this patch is still valid :) Very appreciate your insight comments and suggestions! Leo _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel