add initial documentation

master
S.J.R. van Schaik 7 lat temu
commit 128e860201
  1. 207
      design.rst
  2. 176
      flashrom.rst
  3. 141
      kexec.rst

@ -0,0 +1,207 @@
Trusted Boot
============
Terminology
-----------
* TBM: Trusted Boot Module (the entire system) or Trusted Boot Manager (the ARM Cortex M0 or AVR
microcontroller).
* ROTS: read-only trusted state.
Prerequisites
-------------
* SPI NOR Flash to store a minimalistic read-only Linux image without networking support.
* ARM Cortex M0 or AVR microcontroller.
* A programmable timer to set deadlines and to trigger an interrupt when these expire.
* Possibly SPI NOR Flash for the Trusted Boot Module to store information.
* Key storage and management.
* The option of image rollback?
Trust Model
-----------
There are different trust models that can be used depending on the use case.
These mostly depend on whether the concept of certificate authorities (CAs) is required or not.
Furthermore, the key storage also plays an important role in deciding which of the trust models to
use.
#. "Home router"
CA: none
* replace = reflash RO flash
#. "Routers in company, sysadmin"
CA: none
* replace = reflash or signed statement
#. "Routers with CA"
CA: one.
* replace CA = reflash ROTS
* replace key = by signed CA statement
#. "Routers with multiple CAs"
CA: multiple.
* replace CA = threshold
* replace key = by signed CA statement.
#. "Routers with multiple CAs and initial CA in ROTS"
CA: multiple.
* revoking keys, which is not the same as removing keys.
#. CA: multiple.
* replace CAs = reflash ROTS.
* replace key = by signed CA statement
Key Storage
-----------
* RO Flash
* TBM
* Box storage (e.g. HDD)
* Signed statements by embeddeding keys in images.
Forced reboot
-------------
Because the image is only trusted up to the extent that the user trusts the parties that have
signed the image, the image may contain vulnerabilities that the user will only be aware of at a
later point.
As these vulnerabilities can be used to compromise the system in such a way that it will prevent
from rebooting the system, it is important that the TBM can reboot the system.
The straightforward method of performing such a forced reboot would be to set a deadline that can
be postponed by the user up to *n* times, whereupon the TBM will simply force a reboot after these
attempts or when the user decides to reboot gracefully.
Upgrading
---------
One possible attack vector is that when the image that is running has been compromised in such a
way that it prevents the system from running the update process, even after a reboot, then this
will force the system to always boot the version installed.
To mitigate this we could split up the image into two stages.
The read-only trusted stage will then first boot up a minimalistic environment within the image to
check for updates and to perform them, whereupon the full image will be booted.
Because it is impossible to update the read-only trusted stage as it is stored on a read-only
medium, we want to prevent the read-only stage from being able to perform updates, as it will
require a network stack as well as TLS support.
Both the network stack and TLS support are hard to implement correctly, thus they are both open to
many vulnerabilities that cannot be mitigated as the read-only trusted stage cannot be updated.
This is why the read-only trusted stage cannot be responsible for checking for updates and
performing updates.
Therefore, in combination with the concept of a forced reboot from the TBM, the system would always
be able to check for updates periodically.
To keep track of the images, a table can be used to mark whether the update stage and the image
itself are known to work.
Based on that table the Trusted Boot Manager can then determine which image to rollback to in case
the updated image does not work.
Furthermore, one important decision is whether to only use images that are known to fully work or
to specifically select working stages separately.
Another important open question is how far back the system is allowed to rollback.
Initial Keys and Configuration
------------------------------
The initial key(s) or certificates and the configuration for the TBM could be presented on a SD
card that is inserted before the system is booted for the very first time.
Alternatively, we could decide to have the user embed the keys within the ROTS image before
flashing it to the RO Flash.
Another option would be to offer the user the option of performing key management by means of
serial communication with the Trusted Boot Manager.
Verification of images
----------------------
As the user added the keys from the signing parties to trust, the system should only allow images
that have been signed with these keys.
This verification can take place in the read-only trusted stage before booting the image to ensure
that it has not been comprimised.
Furthermore, as there is a notion of reproducible builds, there is the option of verifying the
packages within the image.
However, as the read-only trusted state should be kept simple to avoid any possible vulnerabilities
or compromises, it is better to delegate the responsibility of verifying these packages to the
parties that sign the image.
Similarly, while the idea of sending deltas between different versions of images does sound
beneficial in the sense that the amount of data that has to be downloaded is kept to a minimum,
this would also further complicate the read-only trusted stage to the extent that it could increase
the likelihood of possible vulnerabilities.
Boot procedure
--------------
#. The image from SPI flash is read and booted.
#. The read-only trusted stage asks the Trusted Boot Manager what to boot and/or asks whether it
is allowed to boot a certain image.
By default the read-only trusted stage should boot a semi-trusted update stage.
#. The read-only trusted stage boots the semi-trusted update stage using ``kexec``.
#. The semi-trusted update stage checks for updates and downloads a new image if present.
#. Once downloaded the semi-trusted update stage finishes by telling the Trusted Boot Manager that
a new image has been downloaded or that no updates were available.
#. The Trusted Boot Manager reboots the system.
#. The image from SPI flash is read and booted.
#. The read-only trusted stage asks the Trusted Boot Manager what to boot and/or asks whether it
is allowed to boot a certain image.
After a reboot from the update process, the Trusted Boot Manager will tell the read-only
trusted stage to boot the latest image.
#. The read-only trusted stage uses ``kexec`` to boot the latest image.
Image self-test and rollback
----------------------------
The image could be extended with a self-test, where the untrusted stage tells the Trusted Boot
Manager that it managed boot successfully.
In case the image fails to boot, the Trusted Boot Manager should set a deadline to expire before
the image is booted.
When this deadline expires, the Trusted Boot Manager can then assume that the image does not work
and should not be used in the future, allowing rollback to the last-known working image.
Furthermore, by solely working with the concept of a last-known working image and an updated image
the possibility of a downgrade is severely limited and no advanced implementation of an image
rollback system would be required.
Trusted Boot Manager protocol
-----------------------------
To have the board communicate with the TBM, we have to devise a protocol.
This communication is likely to place over serial communication through the UART ports.
Furthermore, the board can only send requests to the TBM to which the TBM responds, i.e. the TBM
should never be able to initiate communication.
In the read-only trusted stage the Trusted Boot Manager fully trusts the system and as such the
read-only trusted stage can operate using the full scope of the protocol.
At some point the TBM will be informed by the read-only trusted stage that it will boot into
untrusted state, which is an indication for the TBM to configure the deadline timer and that the
scope of the protocol should be limited as the untrusted stage is only allowed to inform the TBM
that it booted successfully.
The read-only trusted stage should be able to ask which images are preferred for booting and if
booting a certain image is allowed.
Furthermore, it would probably be interesting if a list of images that can be booted can be queried
from the TBM.
In the case that we decide to support initial communication from the read-only trusted stage,
either by flashing the RO Flash or by inserting a removable medium such a SD card, it might be
interesting to support this option of configuration in the protocol.
Proposal(s)
-----------
To reduce the amount of possible vulnerabilities, the codebase and complexity of the TBM should be
kept as minimalistic as possible.
From that point of view, it would be best that the read-only trusted stage only consists of the
tools necessary to verify signed images, to communicate with the TBM and to ``kexec`` those images.
Furthermore, since the read-only trusted stage cannot be modified once it has been written to the
RO Flash, it cannot be easily patched.
As such, it makes a lot of sense to not include a network and TLS stack, as it is very likely that
they contain many vulnerabilities that have yet to be found.
Separating the update stage from the actual image itself, allows the system to forcefully perform
updates, which would essentially prevent any attacker from extending the time window they have any
further.
However, similar to the read-only trusted stage, the update stage should only come with the tools
necessary to check for updates and to perform an update: a network stack, a TLS stack and tools to
communicate with the TBM.
Finally, from the point of view of maintaining minimalism, only allowing rollback to the last-known
working image of which both the update stage and the image itself is probably one of the most
elegant choices, as it easily prevents downgrade attacks and as it is easier to implement.

@ -0,0 +1,176 @@
..
Flashing ROMs
=============
Prerequistes
------------
* BusPirate v3.6a
* SOIC clip
* Winbond 25Q128FV or any other SPI ROM
Hooking up the ROM
------------------
Clip the Winbond 25Q128FV between the SOIC clip. Using the text on the ROM, we can orient the pins on the other side of the clip. The ones on the top from left to right are:
* Chip Select (CS)
* Data Output (DO)
* Write Protect (WP)
* Ground (GND)
The pins on the bottom from left to right are (i.e. the opposite side):
* Power Supply (VCC)
* /HOLD or /RESET
* Clock (CLK)
* Data Input (DI)
Using the colour codes of the wires, we should hook up the pins as follows:
* CS <-> White <-> CS
* MISO <-> Black <-> DO
* GND <-> Brown <-> GND
* 5V <-> Orange <-> VCC
* CLK <-> Purple <-> CLK
* MOSI <-> Grey <-> DI
.. code::
VCC H/R CLK DI
+-|---|---|---|-+
| |
| Winbond |
| W25Q128.V |
|O |
+-|---|---|---|-+
CS DO WP GND
Google Flashrom
---------------
Unlike the mainline version of flashrom, Google's version has two flags to get the name and the
size of the Flash chip:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --flash-name
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
vendor="Macronix" name="MX25L6406E"
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --get-size
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
8388608
With the ``layout.txt`` file, we can tag certain regions in the ROM with a custom name:
.. code::
000000:00ffff rw
7e0000:7fffff ro
Then we can create two random blobs to verify that the ROM works:
.. code::
dd if=/dev/urandom of=rw.dat count=64K bs=1
dd if=/dev/urandom of=ro.dat count=64K bs=1
Finally, we can write these two blobs to the two ROM regions by specifying their names.
We also disable parsing the fmap and verifying the unmodified ROM regions to speed up the process.
To maintain an optimal stability an SPI speed of no more than 2 MHz is recommended when using a
BusPirate:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate -l layout.txt -i ro:ro.dat rw:rw.dat -w --ignore-fmap --fast-verify
Now that the blobs have been written, we can look at the write-protect ranges supported by the chip:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --wp-list
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
Valid write protection ranges:
start: 0x000000, length: 0x000000
start: 0x7e0000, length: 0x020000
start: 0x7c0000, length: 0x040000
start: 0x7a0000, length: 0x080000
start: 0x700000, length: 0x100000
start: 0x600000, length: 0x200000
start: 0x400000, length: 0x400000
start: 0x000000, length: 0x800000
start: 0x000000, length: 0x800000
start: 0x000000, length: 0x400000
start: 0x000000, length: 0x600000
start: 0x000000, length: 0x700000
start: 0x000000, length: 0x780000
start: 0x000000, length: 0x7c0000
start: 0x000000, length: 0x7e0000
start: 0x000000, length: 0x800000
For instance, we can set the write-protect range to be ``0x7e0000`` - ``0x810000``:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --wp-range 0x7e0000 0x020000
After setting the range, we are still able to modify the contents of the entire ROM.
To protect the range, we have to enable write protection as follows:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --wp-enable
``WP#`` must be pulled down for the write protect to be effective, i.e. it must be connected to GND.
This prevents the user from disabling the write protection, changing the write-protected range and
from writing to the write-protected region.
For example, writing a different blob to the region tagged as ``rw`` does work:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --layout layout.txt -i rw:ro.dat --write --ignore-fmap --fast-verify
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
delay loop is unreliable, trying to continue Block protection could not be disabled!
Erasing and writing flash chip... Verifying flash... VERIFIED.
SUCCESS
While writing a different blob to the region tagged as ``ro`` does not work, as it cannot be erased
due to write-protection:
.. code::
./flashrom --programmer=buspirate_spi:dev=/dev/buspirate --layout layout.txt -i ro:rw.dat --write --ignore-fmap --fast-verify
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
delay loop is unreliable, trying to continue Block protection could not be disabled!
Erasing and writing flash chip... ERASE FAILED at 0x007e0000! Expected=0xff, Read=0x15, failed byte count from 0x007e0000-0x007e0fff: 0xff1
ERASE FAILED!
Reading current flash chip contents...
Furthermore, changing the range is not possible either as long as ``WP#`` is pulled down:
.. code::
./flashrom --programmer=buspirate_spi:spispeed=2M,dev=/dev/buspirate --layout layout.txt --wp-range 0x000000 0x000000
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
expected=0x80, but actual=0x9a.
FAILED
Finally, disabling the write-protection feature is not possible either as long as ``WP#`` is pulled
down:
.. code::
./flashrom --programmer=buspirate_spi:spispeed=2M,dev=/dev/buspirate --layout layout.txt --wp-disable
flashrom v0.9.4 : bc6cab1 : Oct 30 2014 07:32:01 UTC on Linux 4.9.4-gentoo (x86_64), built with libpci 3.1.10, GCC 4.8.x-google 20140307 (prerelease), little endian
generic_disable_writeprotect(): error=-1.
FAILED
References
----------
* http://dangerousprototypes.com/docs/SPI
* https://www.winbond.com/resource-files/w25q128fv_revhh1_100913_website1.pdf
* https://www.pjrc.com/teensy/W25Q128FV.pdf
* https://learn.sparkfun.com/tutorials/bus-pirate-v36a-hookup-guide
* https://www.chromium.org/chromium-os/packages/cros-flashrom
* http://www.tnhh.net/posts/unbricking-chromebook-with-beaglebone.html

@ -0,0 +1,141 @@
..
Setting up kexec
================
Prerequisites
-------------
To be able to use kexec and initramfs images, we have to make sure the following options have been enabled in the kernel config:
.. code::
:lang: text
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
CONFIG_KEXEC=y
Building an initramfs
---------------------
Let's first create the general structure of our initramfs:
.. code::
:lang: text
mkdir -p /usr/src/initramfs/{bin,dev,etc,lib,lib64,mnt,proc,root,sbin,sys}
Rather than compiling a lot of the common utilities that can be found in e.g. coreutils, we compile a static version of busybox to install within in our initramfs:
.. code::
:lang: text
USE="static" emerge busybox
cp /usr/bin/busybox /usr/src/initramfs/bin/busybox
In addition to busybox, we will also need kexec-tools to boot our kernel:
.. code::
:lang: text
USE="static" emerge kexec-tools
cp /usr/sbin/kexec /usr/src/initramfs/sbin/kexec
If we run ldd on /usr/sbin/kexec, we can also figure out the dependencies that it will need to run:
.. code::
:lang: text
ldd /usr/sbin/kexec
cp -r /lib/{libc.so.6,libz.so.1,ld-linux-armhf.so.3} /usr/src/initramfs/lib
In /usr/src/initramfs/init, we set up the following init script:
.. code::
:lang: text
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none
busybox sh
umount /dev
exec switch root /mnt/root /sbin/init
The above script will drop us in a busybox shell session before resuming to switch to the mounted rootfs at /mnt/root.
Also, do make sure that is executable:
.. code::
:lang: text
chmod +x /usr/src/initramfs/init
Once everything has set up, we can pack it all into a initramfs as follows:
.. code::
:lang: text
cd /usr/src/initramfs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ~/initramfs.cpio.gz
Booting a kernel
----------------
.. code::
:lang: text
cd /usr/src/linux
kexec --dtb=arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dtb --ramdisk=initramfs.cpio.gz --command-line="console=tty1 rootfs=/dev/mmcblk2p2 rootfstype=ext4 rootwait rw" arch/arm/boot/zImage
Using kexec-tools to boot a uImage also works.
Booting u-boot
--------------
First, we have to clone the u-boot repository and build u-boot:
.. code::
:lang: text
git clone git://git.denx.de/u-boot.git --depth=1 -b v2017.01
cd u-boot
make A20-OLinuXino-Lime2_defconfig
make
Once we have built u-boot, we have to pack it up as a uImage, so that kexec can boot it.
However, before we can pack it up, we have to figure out the load address and the entry address for the board that we are trying to target.
For instance, for the Allwinner boards, we can find the load address as follows:
.. code::
:lang: text
grep CONFIG_SYS_LOAD_ADDR include/configs/sunxi-common.h
grep CONFIG_SYS_TEXT_BASE include/configs/sunxi-common.h
In this case, we'll find that the load address and text base are either configured to be ``0x22000000`` and ``0x2a000000`` or ``0x42000000`` and ``0x4a000000`` respectively.
Closer inspection shows that the Allwinner A20 (sun7i) uses the latter two.
After we have found the load address and text base, we can pack up u-boot:
.. code::
:lang: text
mkimage -A arm -O linux -T kernel -C none -a 0x42000000 -e 0x4a000000 -d u-boot-dtb.bin u-boot.img
TODO: this boots up to the point where u-boot display a bit of information and then just hangs.
References
----------
* https://wiki.gentoo.org/wiki/Custom_Initramfs
* https://blogs.s-osg.org/use-mainline-u-boot-non-signed-kernels-exynos-chromebooks/
* https://www.riscosopen.org/forum/forums/5/topics/350
* https://github.com/c0d3z3r0/rockboot
* https://prabagaranvt.blogspot.nl/2012/09/kexec.html
* http://elinux.org/images/2/2f/ELC-2010-Damm-Kexec.pdf
Ładowanie…
Anuluj
Zapisz