On UEFI platforms, GRUB
implements a command linuxefi
to load linux kernel only after its signature against the DB key
is verified, and enable the feature for kernel to load modules after its signature get verified.
This command only available on UEFI platforms, but in reality, grub itself has the mechanism to import gpg public keys, and use them to verify detached signature for any file. it even has an option to make it implicitly verify any file before load it into ram.
All we need is to wrap those mechanism with grub config script into a function able to be invoked like a builtin command, with similar interface like linuxefi
, like this grub.cfg.embedded:
Function linuxpgp
will first enable enforced signature verification, "load" linux kernel, with kernel command line option module.sig_enforce=1
appended at the end of the command line, then disable enforced signature verification. This function could be used in place of linux
, just as linuxefi
.
Every OpenPGP public keys put under (cbfsdisk)/keys (inside the firmware flash, not any external storage) would be trusted.
This script will be embedded into the standalone ELF GRUB executable, to extend its functionality. In its execution, it loads the second stage config file under (cbfsdisk)/grub.cfg.
Similar to procedures to generate a standalone grub EFI executable mentioned in this article, This Makefile could be used to generate a standalone grub ELF executable in order to integrate into coreboot images. Proper modules.lst and instmod.lst should also be provided.
In order to use that makefile, you should install the binaries of the coreboot version of grub:
# apt-get install grub-coreboot-bin
and a font will be integrated into the executable, you must copy or symlink the ttf
formatted font file to font.ttf
under the same directory of the makefile, e.g.
$ ln -s /usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf font.ttf
The font will be converted to pf2
format by grub-mkfont(1)
, and integrated into the executable during the invocation of the makefile.
Make sure all dependencies are ready, the makefile could be invoked:
$ make -f grub.mk
A standalone grub ELF executable named grub.elf
will be generated, with grub.cfg.embedded integrated as the first stage config script.
Update for coreboot (after commit 2ac149d294af795710eb4bb20f093e9920604abd)
On some newer platforms of intel (confirmed on nehalem, sandy/ivy bridge), coreboot registers an SMI to lockdown some registers on the chipset, as well as access to the SPI flash, optionally. The SMI will always be triggered by coreboot during S3 resume, but can be triggered by either coreboot or the payload during normal boot path.
Enabling lockdown access to SPI flash will effectly write-protect it, but there is no runtime option for coreboot to control it, so letting coreboot to trigger such SMI will leave the owner of the machine lost any possibility to program the SPI flash with its own OS, and becomes a nightmare if the machine is uneasy to disassemble.
Fortunately, grub has the compatibility to use outb, outl, and outw, which means it has the ability to trigger SMI as well. We can then write
an extension config script, in which an auto-executed menuitem
is designed to trigger the SMI, and whose
context is protected with a password. Only designated superuser could edit the code within this menuitem
at runtime, thus disable the write-
protection temporarily, in order to reprogram the SPI flash.
Such config script is designed as an extension of the embedded script within the grub payload executable. In order to make such protection unable to bypass during boot, the payload had better be executed by coreboot directly, rather than to be chainloaded from other runtime-operable payloads, such as SeaBIOS.
Use the script below to insert the extension script into the coreboot image:
#!/bin/sh
CBROM=$1
build/cbfstool ${CBROM} add -t raw -n extensions/$(basename $2) -f $2
build/cbfstool ${CBROM} print
For now, you are assumed to have set up a usable coreboot building environment under ${CBSRC}
.
First, configure it as your wish.
$ cd ${CBSRC}
$ make menuconfig
coreboot allows to use existing elf executable as payload, which will be executed by coreboot directly.
Use seabios as the default payload, which will be built and integrated into the image automatically during coreboot's building process, then use the script below to insert the grub payload into the image, and configure SeaBIOS to chainload it automatically.
After saving the config result, invoke make(1)
to build the coreboot image.
$ make
The coreboot image will be generated at ${CBSRC}/build/coreboot.rom
.
You need cbfstool
to manipulate CBFS with the image. An usable executable should be built at ${CBSRC}/build/cbfstool
during coreboot's build process.
Copy the grub executable to ${CBSRC}/grub2.elf
and run the following script under ${CBSRC}
, if SeaGrub scheme will be used:
#!/bin/sh
if [ -z $1 ];then
CBROM=build/coreboot.rom
else
CBROM=$1
fi
build/cbfstool ${CBROM} add-payload -c lzma -f grub2.elf -n img/grub2
printf "/rom@img/grub2\n" > bootorder
build/cbfstool ${CBROM} add -f bootorder -n bootorder -t raw
build/cbfstool ${CBROM} add-int -i 1 -n etc/show-boot-menu || "already exists"
build/cbfstool ${CBROM} remove -n etc/ps2-keyboard-spinup || printf "does not exist"
build/cbfstool ${CBROM} add-int -i 3000 -n etc/ps2-keyboard-spinup || printf "already exists"
build/cbfstool ${CBROM} print
I recommend to leave one second for seabios before launching grub, in order to execute other payloads integraded during coreboot's build process.
Exemplar grub.cfg and grubtest.cfg are those used by libreboot. You could insert them into the coreboot image with the following script:
#!/bin/sh
if [ -z $1 ];then
CBROM=build/coreboot.rom
else
CBROM=$1
fi
build/cbfstool ${CBROM} add -t raw -n grub.cfg -f grub.cfg
build/cbfstool ${CBROM} add -t raw -n grubtest.cfg -f grubtest.cfg
build/cbfstool ${CBROM} print
provided that you have copied the two files under ${CBSRC}
.
Hints to write your own config file could be found in coreboot's documents for grub referred below.
Use the following script to integrate pubkeys into the coreboot image:
#!/bin/sh
case $1 in
*.rom)
CBROM=$1
shift
;;
*)
CBROM=build/coreboot.rom
;;
esac
FILE=${1}
echo "Insert OpenPGP pubkey ${FILE}..."
build/cbfstool ${CBROM} add -t raw -f ${FILE} -n keys/$(basename ${FILE})
build/cbfstool ${CBROM} print
You could then flash this image to its targeting mother board.
Very similar to the scheme described in this article.
Sign your kernel with the corresponding private key, which should be recognized inside your private keyring, and could be inside an OpenPGP card, using this wrapper script.
$ /path/to/gpg-sign-kernel.sh /boot/vmlinuz-ver-arch <key identity>
The signature file is generated inside your current working directory. Copy it to /boot
.
Patch /etc/grub.d/10_linux
with this patch. This version could handle both UEFI secure boot and this scheme, as well as the ordinary insecure scheme.
Then regenerate the /boot/grub/grub.cfg
.
# patch /etc/grub.d/10_linux 10_linux.diff
# update-grub
For now signed kernels is going to be loaded with linuxpgp
function.
######Reference: [1] The beta version of GRUB2's documents
[2] manpages of grub-mkstandalone(1)
[3] Source code of grub
[4] Latest release of libreboot