2023-07-10 15:43:08 +00:00
|
|
|
---
|
|
|
|
title: Hardening GRUB
|
|
|
|
x-toc-enable: true
|
|
|
|
...
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
GRUB can have password protection at boot, prevent unauthorised access to the
|
|
|
|
shell and to menuentries. You can also boot from fully encrypted distros, where
|
|
|
|
the `/boot` directory is already encrypted, containing your kernel. You can
|
|
|
|
additionally verify each file, including GRUB configuration files and Linux
|
|
|
|
kernels, using GPG; GRUB supports putting a GPG pubkey in CBFS, and using it
|
|
|
|
to verify all files that it accesses.
|
|
|
|
|
|
|
|
Let's begin.
|
|
|
|
|
2024-08-26 20:55:49 +00:00
|
|
|
**Disable security before flashing**
|
|
|
|
================================
|
|
|
|
|
|
|
|
**Before internal flashing, you must first disable `/dev/mem` protections. Make
|
|
|
|
sure to re-enable them after you're finished.**
|
|
|
|
|
|
|
|
**See: [Disabling /dev/mem protection](../install/devmem.md)**
|
|
|
|
|
|
|
|
This only applies if you're following these instructions via internal
|
|
|
|
flashing, from an existing installation.
|
|
|
|
|
|
|
|
Back up your flash first!
|
|
|
|
=========================
|
|
|
|
|
|
|
|
Make sure you also back up the current flash contents, before you proceed with
|
|
|
|
this guide. See: [Canoeboot flashing guides](../install/) (it also says how
|
|
|
|
to read the flash, in addition to writing it)
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Build dependencies
|
|
|
|
==================
|
|
|
|
|
|
|
|
You need `cbfstool` from coreboot. For whatever board you have, check which
|
|
|
|
coreboot tree it uses in Canoeboot's build system, cbmk. For example, let's
|
|
|
|
say your board is `x200_8mb`, you would do:
|
|
|
|
|
|
|
|
grep tree= config/coreboot/x200_8mb/target.cfg
|
|
|
|
|
|
|
|
In this example, the output might be:
|
|
|
|
|
|
|
|
tree="default"
|
|
|
|
|
|
|
|
This means you should compile `cbfstool` from the `default` coreboot tree,
|
|
|
|
like so:
|
|
|
|
|
|
|
|
./mk -d coreboot default
|
|
|
|
|
|
|
|
This will result in the following binary: `elf/cbfstool/default/cbfstool`
|
|
|
|
|
|
|
|
We won't assume the path to cbfstool, in the remainder of this guide, so
|
|
|
|
adapt accordingly.
|
|
|
|
|
|
|
|
Background information
|
2023-07-10 15:43:08 +00:00
|
|
|
=========================
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
By default, the `grub.cfg` file and `grubtest.cfg` file are not present in
|
|
|
|
CBFS, because the GRUB memdisk, contained within the GRUB binary itself, within
|
|
|
|
CBFS, contains a GRUB configuration file.
|
|
|
|
|
|
|
|
Canoeboot will switch to `grub.cfg` from flash instead, if it exists,
|
|
|
|
skipping the one in memdisk.
|
|
|
|
|
|
|
|
Because we need to put a signature next to each file, that would mean
|
|
|
|
re-building GRUB if you wanted to use the one in memdisk. Therefore, we can
|
|
|
|
insert a custom one in CBFS, to mitigate that fact.
|
|
|
|
|
|
|
|
By doing it this way, you can avoid re-building GRUB, or indeed anything inside
|
|
|
|
your current Canoeboot images.
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
References:
|
|
|
|
|
|
|
|
* [GRUB manual](https://www.gnu.org/software/grub/manual/html_node/Security.html#Security)
|
|
|
|
* [GRUB info pages](http://git.savannah.gnu.org/cgit/grub.git/tree/docs/grub.texi)
|
|
|
|
* [Coreboot GRUB security howto](https://www.coreboot.org/GRUB2#Security)
|
|
|
|
|
|
|
|
GRUB Password
|
|
|
|
=============
|
|
|
|
|
|
|
|
The security of this setup depends on a good GRUB password as GPG signature
|
|
|
|
checking can be disabled through the interactive console:
|
|
|
|
|
|
|
|
set check_signatures=no
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Disabling signatures, using the above command, is useful when you're booting
|
|
|
|
regular media such as live distros via USB.
|
|
|
|
|
|
|
|
You are strongly advised to use an *open diceware* passphrase (look that up).
|
|
|
|
Generate a strong passphrase of completely random words, at least 20 words in
|
|
|
|
total is ideal. Passphrases are better than pass*words* containing lots
|
|
|
|
of random letters and symbols, because pass*phrases* have higher entropy and
|
|
|
|
are therefore harder to crack.
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
The GRUB password can be stored in one of two ways:
|
|
|
|
|
|
|
|
* plaintext
|
|
|
|
* protected with [PBKDF2](https://en.wikipedia.org/wiki/Pbkdf2)
|
|
|
|
|
|
|
|
We will *obviously* use the latter method. Generating the PBKDF2 derived key is
|
|
|
|
done using the `grub-mkpasswd-pbkdf2` utility. You can get it by
|
|
|
|
installing GRUB version 2. Generate a key by giving it a password:
|
|
|
|
|
|
|
|
NOTE: This utility is included under the `grub/` directory, when you build
|
2023-10-26 00:10:41 +00:00
|
|
|
GRUB using the Canoeboot build system. Run the following commands (assuming
|
2023-07-10 15:43:08 +00:00
|
|
|
you have the correct build dependencies installed) to build GRUB, from the
|
2023-10-26 00:10:41 +00:00
|
|
|
Canoeboot Git repository:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-23 00:28:08 +00:00
|
|
|
./mk -b grub default
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-23 00:28:08 +00:00
|
|
|
The following executable will then be available under `src/grub/default/`:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
grub-mkpasswd-pbkdf2
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Run that program. It will ask you to choose a new passphrase. Its output will
|
|
|
|
be a string of the following form:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
grub.pbkdf2.sha512.10000.HEXDIGITS.MOREHEXDIGITS
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Make sure to copy this into the correct GRUB config. The correct GRUB config
|
|
|
|
can be determined as follows. Again, let's assume that you have `x200_8mb`:
|
|
|
|
|
|
|
|
grep grubtree= config/coreboot/x200_8mb/target.cfg
|
|
|
|
|
|
|
|
It *may* or *may not* output anything. If it outputs *nothing*, then the
|
|
|
|
GRUB tree is `default`, otherwise it might output something like:
|
|
|
|
|
|
|
|
grubtree="nvme"
|
|
|
|
|
|
|
|
Make *sure* to use the correct GRUB tree. We will assume `default`, so you
|
|
|
|
should adapt accordingly, when doing this yourself:
|
|
|
|
|
|
|
|
cp config/grub/default/config/payload grub.cfg
|
|
|
|
|
|
|
|
Now, your `grub.cfg` file is correct for the board, and you can insert
|
|
|
|
the salted, hashed passphrase that you get from `grub-mkpasswd-pbkdf2` earlier.
|
|
|
|
|
2023-07-10 15:43:08 +00:00
|
|
|
Now open my.grubtest.cfg and put the following before the menu entries
|
|
|
|
(prefered above the functions and after other directives). Of course use
|
|
|
|
the pbdkf string that you had generated yourself:
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Put this *before* the menuentries (just before) in `grub.cfg`, but note that
|
|
|
|
you should **not** literally use what is below; the hash below is not the one
|
|
|
|
you generated yourself. Make sure to adapt accordingly.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
2023-07-10 15:43:08 +00:00
|
|
|
set superusers="root"
|
|
|
|
password_pbkdf2 root grub.pbkdf2.sha512.10000.711F186347156BC105CD83A2ED7AF1EB971AA2B1EB2640172F34B0DEFFC97E654AF48E5F0C3B7622502B76458DA494270CC0EA6504411D676E6752FD1651E749.8DD11178EB8D1F633308FD8FCC64D0B243F949B9B99CCEADE2ECA11657A757D22025986B0FA116F1D5191E0A22677674C994EDBFADE62240E9D161688266A711
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
**Again**, replace it with the correct hash that you actually obtained for the
|
2023-07-10 15:43:08 +00:00
|
|
|
password you entered. In other words, *do not use the hash that you see above!*
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Once this configuration is inserted, you will need to enter a passphrase every
|
|
|
|
time you boot. GRUB will also ask for a username. In the above example, we
|
|
|
|
made a username `root`, but you can set it to what you want and
|
|
|
|
adapt accordingly.
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
Another good thing to do, if we chose to load signed on-disk GRUB
|
2024-08-26 17:51:02 +00:00
|
|
|
configurations, is to remove (or comment out) `unset superusers`. Find any line
|
|
|
|
that says this, in your `grub.cfg` file:
|
2023-07-10 15:43:08 +00:00
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
unset superusers
|
|
|
|
|
|
|
|
Change it to this:
|
|
|
|
|
|
|
|
# unset superusers
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
The `unset superusers` command disables password authentication, which will
|
|
|
|
allow the attacker to boot an arbitrary operating system, regardless of
|
2024-08-26 17:51:02 +00:00
|
|
|
signature checking. The default Canoeboot configuration is tweaked for *ease of
|
2023-07-10 15:43:08 +00:00
|
|
|
use* by end users, and it is *not* done with security in mind (though security
|
2023-10-26 00:10:41 +00:00
|
|
|
is preferred). Thus, Canoeboot is less restrictive by default. What you are
|
2023-07-10 15:43:08 +00:00
|
|
|
doing, per this article, is making your system *more secure* but at the expense
|
|
|
|
of user-friendliness.
|
|
|
|
|
|
|
|
That just about covers it, where password setup is concerned!
|
|
|
|
|
2024-05-27 23:46:50 +00:00
|
|
|
SeaBIOS first?
|
|
|
|
==============
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
**Very important. Make sure you read this carefully.**
|
|
|
|
|
2024-05-27 23:46:50 +00:00
|
|
|
In releases after Canoeboot 20240510, SeaBIOS is the primary payload on
|
|
|
|
all images, but GRUB is available in the boot menu. Select a ROM image
|
|
|
|
with `grubfirst` at the end, and do this to the ROM image:
|
|
|
|
|
|
|
|
cbfstool canoeboot.rom add-int -i 0 -n etc/show-boot-menu
|
|
|
|
|
|
|
|
This disables the SeaBIOS menu, so that it only loads GRUB. The `grubfirst`
|
2024-08-26 17:51:02 +00:00
|
|
|
image had this done to it by cbmk (Canoeboot build system) during build:
|
2024-05-27 23:46:50 +00:00
|
|
|
|
|
|
|
cbfstool canoeboot.rom add -f config/grub/bootorder -n bootorder -t raw
|
|
|
|
|
|
|
|
This `bootorder` file has the following contents:
|
|
|
|
|
|
|
|
```
|
|
|
|
/rom@img/grub2
|
|
|
|
```
|
|
|
|
|
|
|
|
You can add it yourself if your image doesn't have it. With this, SeaBIOS
|
|
|
|
only loads GRUB first.
|
|
|
|
|
|
|
|
NOTE: Before disabling the boot menu, make sure GRUB works. Access it using
|
|
|
|
the `bootorder` file and/or press ESC in the SeaBIOS menu. Then disable the
|
2024-08-26 17:51:02 +00:00
|
|
|
SeaBIOS menu:
|
|
|
|
|
|
|
|
cbfstool canoeboot.rom add-int -i 0 -n etc/show-boot-menu
|
|
|
|
|
|
|
|
Although the `bootorder` file only specifies *GRUB*, this just means that
|
|
|
|
SeaBIOS won't automatically try to boot anything else. The SeaBIOS menu is still
|
|
|
|
accessible, by pressing ESC when prompted; the above `add-int` command disables
|
|
|
|
that menu, so that *only* the GRUB payload will be executed.
|
|
|
|
|
|
|
|
SeaBIOS option ROMs
|
|
|
|
===================
|
|
|
|
|
|
|
|
SeaBIOS will also still execute PCI option ROMs. Depending on your preference,
|
|
|
|
you may wish to disable this, but please note that this will break certain
|
|
|
|
things like graphics cards. More information is available here:
|
|
|
|
|
|
|
|
<https://www.seabios.org/Runtime_config>
|
|
|
|
|
|
|
|
On a laptop, you probably don't have to worry about option ROMs at all, but
|
|
|
|
desktops are much more easily upgradeable; though, in practise, anyone
|
|
|
|
inclined to insert a card with a malicious option ROM on it wouldn't do that
|
|
|
|
anyway, because if they have access to your hardware, they could just
|
|
|
|
externally re-flash the machine anyway, so I wouldn't worry, but it's up to you.
|
|
|
|
|
|
|
|
If you're using a graphics card, you *need* VGA option ROMs at least.
|
2024-05-27 23:46:50 +00:00
|
|
|
|
2023-07-10 15:43:08 +00:00
|
|
|
GPG keys
|
|
|
|
========
|
|
|
|
|
|
|
|
First, generate a GPG keypair to use for signing. Option RSA (sign only)
|
|
|
|
is ok.
|
|
|
|
|
|
|
|
WARNING: GRUB does not read ASCII armored keys. When attempting to
|
|
|
|
trust ... a key filename it will print `error: bad signature` on the screen.
|
|
|
|
|
|
|
|
```
|
|
|
|
mkdir --mode 0700 keys
|
|
|
|
gpg --homedir keys --gen-key
|
|
|
|
gpg --homedir keys --export-secret-keys --armor > boot.secret.key # backup
|
|
|
|
gpg --homedir keys --export > boot.key
|
|
|
|
```
|
|
|
|
|
|
|
|
Now that we have a key, we can sign some files with it. We must sign:
|
|
|
|
|
|
|
|
- a kernel
|
|
|
|
- (if we have one) an initramfs
|
|
|
|
- (if we wish to transfer control to it) an on-disk `grub.cfg`
|
|
|
|
- `grubtest.cfg` (so that you can go back to `grubtest.cfg` after signature
|
|
|
|
checking is enforced. You can always get back to `grub.cfg` by pressing ESC,
|
2024-08-26 17:51:02 +00:00
|
|
|
but, afterwards, `grubtest.cfg` is not signed and it will not load. The
|
|
|
|
GRUB config we made earlier can be copied to `grubtest.cfg` and inserted,
|
|
|
|
but please only do this at the end of the guide when it tells you to insert
|
|
|
|
the GRUB config, because there are still osme things you need to do.
|
2023-07-10 15:43:08 +00:00
|
|
|
|
|
|
|
Suppose that we have a pair of `my.kernel` and `my.initramfs` and an
|
2023-10-26 00:10:41 +00:00
|
|
|
on-disk `canoeboot_grub.cfg`. We will sign them by running the following
|
2023-07-10 15:43:08 +00:00
|
|
|
commands:
|
|
|
|
|
|
|
|
```
|
|
|
|
gpg --homedir keys --detach-sign my.initramfs
|
|
|
|
gpg --homedir keys --detach-sign my.kernel
|
2023-10-26 00:10:41 +00:00
|
|
|
gpg --homedir keys --detach-sign canoeboot_grub.cfg
|
2023-07-10 15:43:08 +00:00
|
|
|
gpg --homedir keys --detach-sign my.grubtest.cfg
|
|
|
|
```
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Of course, some further modifications to grubtest.cfg will be required. We
|
2023-07-10 15:43:08 +00:00
|
|
|
need to *trust* the key and enable signature enforcement (put this before menu
|
|
|
|
entries):
|
|
|
|
|
|
|
|
```
|
|
|
|
trust (cbfsdisk)/boot.key
|
|
|
|
set check_signatures=enforce
|
|
|
|
```
|
|
|
|
|
2023-10-26 00:10:41 +00:00
|
|
|
What remains now is to include the modifications into the Canoeboot image
|
2023-07-10 15:43:08 +00:00
|
|
|
(ROM):
|
|
|
|
|
|
|
|
```
|
2024-08-26 17:51:02 +00:00
|
|
|
cbfstool canoeboot.rom add -n boot.key -f boot.key -t raw
|
|
|
|
|
|
|
|
# You might consider copying `grub.cfg` to `grubtest.cfg` and adding that.
|
|
|
|
# Otherwise, adding just `grub.cfg` is also fine.
|
|
|
|
|
|
|
|
cbfstool canoeboot.rom add -n grub.cfg -f my.grub.cfg -t raw
|
|
|
|
cbfstool canoeboot.rom add -n grub.cfg.sig -f my.grub.cfg.sig -t raw
|
|
|
|
|
|
|
|
cbfstool canoeboot.rom add -n grubtest.cfg -f my.grubtest.cfg -t raw
|
|
|
|
cbfstool canoeboot.rom add -n grubtest.cfg.sig -f my.grubtest.cfg.sig -t raw
|
2023-07-10 15:43:08 +00:00
|
|
|
```
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Congratulations!
|
|
|
|
================
|
|
|
|
|
|
|
|
With any luck, this should work perfectly. Your system will no longer boot
|
|
|
|
anything unless it's signed by your key.
|
|
|
|
|
|
|
|
If your entire system is also encrypted, including `/boot`, then that protects
|
|
|
|
everything including the privkey much more robustly, and it further prevents
|
|
|
|
tampering with your kernel (where GPG only detects tampering, encryption can
|
|
|
|
prevent it).
|
|
|
|
|
|
|
|
Encryption, combined with a GRUB passphrase, combined with a GPG check, should
|
|
|
|
make you pretty damn secure at boot time. All that's left now is one final,
|
|
|
|
optional step:
|
|
|
|
|
|
|
|
Flash write protection
|
|
|
|
======================
|
|
|
|
|
|
|
|
Although not strictly related to GNU GRUB, flash protection will prevent anyone
|
|
|
|
except you from overwriting the flash without permission. This is important,
|
|
|
|
because you don't want some malicious software running as root from overwriting
|
|
|
|
your flash, thus removing any of the above protections.
|
|
|
|
|
|
|
|
The simplest way is to just do this:
|
|
|
|
|
|
|
|
ifdtool -x canoeboot.rom -O canoeboot.rom
|
|
|
|
|
2024-08-26 17:53:47 +00:00
|
|
|
If you did the step before, to compile `cbfstool`, you can find ifdtool in
|
|
|
|
the `elf/` directory, e.g. `elf/ifdtool/default/ifdtool`. Make sure to use
|
|
|
|
the correct version, as per `tree=` (same as before when deciding to which
|
|
|
|
cbfstool version to use based on the coreboot tree used by your board).
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Note that this only works for Intel-based systems that use an Intel Flash
|
|
|
|
Descriptor, which is actually most Intel systems that Canoeboot supports.
|
|
|
|
|
|
|
|
You can still flash externally, or strap `HDA_SDO` (`HDA_DOCK_EN` on older
|
|
|
|
GM45 machines) accordingly. Note that the x4x/ich10-based machines don't have
|
|
|
|
flash descriptors, and neither do the i945 machines, but the GM45 and newer
|
|
|
|
Intel platforms do.
|
|
|
|
|
2024-08-26 20:24:32 +00:00
|
|
|
Other facts
|
|
|
|
-----------
|
|
|
|
|
|
|
|
Strapping `HDA_SDO` or `HDA_DOCK_EN` requires physical access, because you have
|
|
|
|
to short a pin on the HDA chip on the motherboard, or there will be a header
|
|
|
|
for this on the board (e.g. "service mode" jumper).
|
|
|
|
|
|
|
|
On *Dell Latitude* laptops specifically, the EC can unlock flash by setting
|
|
|
|
the SDO/DOCK\_EN signal as described, and this is in fact what
|
|
|
|
the `dell-flash-unlock` utility does, so you can consider IFD locking there
|
|
|
|
to be basically useless.
|
|
|
|
|
|
|
|
In addition to the above, you may also consider `/dev/mem` protection.
|
|
|
|
Enable `CONFIG_STRICT_DEVMEM` in your Linux kernel, or set `securelevel` above
|
|
|
|
zero on your BSD setup (but BSD cannot be booted with GRUB very easily so
|
|
|
|
it's a moot point).
|
|
|
|
|
2024-08-26 20:55:49 +00:00
|
|
|
Other write-protect methods
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
The steps above do not require recompilation of the Canoeboot images. However,
|
|
|
|
coreboot offers additional security at build time, which you can select if you
|
|
|
|
wish.
|
|
|
|
|
|
|
|
Let's assume your board is `x200_8mb`, do:
|
|
|
|
|
|
|
|
./mk -m coreboot x200_8mb
|
|
|
|
|
|
|
|
Find this section: Security -> Boot media protection mechanism
|
|
|
|
|
|
|
|
In the above example, I found:
|
|
|
|
|
|
|
|
* Lock boot media using the controller
|
|
|
|
* Lock boot media using the chip
|
|
|
|
|
|
|
|
Which one to pick depends on your board. Let's pick "controller".
|
|
|
|
|
|
|
|
Now we can see: Security -> Boot media protected regions
|
|
|
|
|
|
|
|
In there, there is the option to ban writes, or to ban both reads and writes.
|
|
|
|
Banning reads may be desirable, for example if you have a salt hashed password
|
|
|
|
stored in `grub.cfg`! (as this guide told you to do)
|
|
|
|
|
|
|
|
You'll have to play around with this yourself. These options are not enabled
|
|
|
|
by default, because Canoeboot images are supposed to allow writes by default,
|
|
|
|
when booted. You have to enable such security yourself, because the design of
|
|
|
|
Canoeboot is to be as easy to use as possible by defalut, which include updates,
|
|
|
|
thus implying read-write flash permissions.
|
|
|
|
|
|
|
|
This example was for `x200_8mb`, but other boards may look different in config.
|
|
|
|
Anyway, when you're done, save the config and then build it from source in cbmk.
|
|
|
|
|
|
|
|
See: [build from source](../build/)
|
|
|
|
|
2024-08-26 17:51:02 +00:00
|
|
|
Install the new image
|
|
|
|
=====================
|
|
|
|
|
|
|
|
Now simply flash the new image, using
|
|
|
|
the [flashing instructions](../install/).
|
|
|
|
|
|
|
|
If you did all of the above steps correctly, your system should boot
|
|
|
|
up just fine. Shut it down and wait a few seconds. If you screwed it up
|
|
|
|
and the system is now unbootable, that's OK because you can use an
|
|
|
|
external flasher; please
|
|
|
|
read [external flashing instructions](../install/spi.md)
|