A custom linux based operating system built to manage software running on airgapped Bitcoin signing device. SeedSigner is both the project name and application running on airgapped hardware. This custom operating system, like all operating systems, manages the hardware resources and provides them to the application code. It's currently designed to run on common Raspberry Pi hardware with accessories. The goal of SeedSigner OS is to provide an easy, fast, and secure way to build microSD card image to securely run SeedSigner code.
SeedSigner OS is built using Buildroot. Buildroot is a simple, efficient and easy-to-use tool to generate embedded Linux systems through cross-compilation. SeedSigner OS does not fork Buildroot, but uses Buildroot with custom configurations to build microSD card images tailor made for running SeedSigner.
SeedSigner OS is built to reduce the attack surface area and enable additional application functionality. The OS is an order of magnatude smaller in size than Raspberry Pi OS (which is what typically is used to run software on a Pi device). Here are a list of some security and functional advantages of using SeedSigner OS.
- Boots 100% from RAM. This means, once you see the SeedSigner splash screen, you can remove the microSD card because no disk I/O is needed after boot!
- One FAT32 partition on the microSD card
- Removes these standard Raspberry Pi OS Kernel modules:
- Networking and Bluetooth
- SWAP
- I2C
- Serial
- USB
- Pulse-Width Modulation (PWM)
- NO HDMI support
- NO Serial connection TTL support
- NO Software supporting any wireless or networking chips
- A single read only zImage file on the boot partition containing the entire Linux kernel and filesystem
Easiest way to build SeedSigner OS is using docker. This keeps the build process repeatable and the build system clean.
- Clone the repository in your machine:
git clone --recursive https://github.com/SeedSigner/seedsigner-os.git
- Go into the repo directory:
cd seedsigner-os
- Build images using docker compose (expect this to take more than 1 hour). You can change the
--pi0
option to the board type you wish to build or use--all
to build all images types. Theexport DOCKER_DEFAULT_PLATFORM=linux/amd64
is required to make the build reproducible. If you leave out this option on a ARM64 mac it will build faster. The--force-recreate
and--build
are there to make sure the latest image and container are used (not a local one cached).export DOCKER_DEFAULT_PLATFORM=linux/amd64 SS_ARGS="--pi0" docker compose up --force-recreate --build
This command will build a docker image from the Dockerfile and in the background (as a daemon) run a container used to compile SeedSigner OS. You can monitor the seedsigner-os-build-images container in Docker Dashboard (if using Docker Desktop) or by running the docker contain list command waiting for the container to complete with an Exit (0) status. The container will create the image(s) in the images directory.
docker container list --all
Run SS_ARGS="--help" docker compose up
to see the possible build options you can pass in via the SS_ARGS env variable.
By default, the docker-compose.yml is configured to create a container volume to the images directory in the repo. This is where all the image files are written out after the container completes building the OS from source. The images are named following this convension:
seedsigner_os.<app_repo_branch>.<board_config>.img
Example name for a pi0 built off the 0.5.2 branch would be named:
seedsigner_os.0.5.2.pi0.img
Here is a table Raspberry Pi boards to image filenames/configs
Board | Image Name | Build Script Option |
---|---|---|
Raspberry Pi Zero | seedsigner_os.<tag>.pi0.img |
--pi0 |
Raspberry Pi Zero W | seedsigner_os.<tag>.pi0.img |
--pi0 |
Raspberry Pi 2 Model B | seedsigner_os.<tag>.pi2.img |
--pi2 |
Raspberry Pi Zero 2 W | seedsigner_os.<tag>.pi02w.img |
--pi02w |
Raspberry Pi 3 Model B | seedsigner_os.<tag>.pi02w.img |
--pi02w |
Raspberry Pi 4 Model B | seedsigner_os.<tag>.pi4.img |
--pi4 |
Each time the docker compose up
command runs a full build from scratch is performed. You can optionally run docker compose up -d
in detached mode by adding the -d
flag. This will run the container in the background. To have faster development cycles you'll likely want to avoid building the OS from scratch each time. You can avoid recreating the docker image/container a few different ways. One way is to pass the options --no-op
(which is the default) to the SS_ARGS
env variable when running docker-compse up
. This will cause the container to skip build steps but keep the container running in the background until you explicitly stop it. You can then launch a shell session into the container and work interactively running any specific build commands you desire.
Using docker compose will start the container (create new container if on does not already exist) without building an image
SS_ARGS="--no-op" docker compose up -d --no-recreate
If you want to start a new container environment, use --force-recreate
instead of --no-create
SS_ARGS="--no-op" docker compose up -d --force-recreate --build
Start a shell session inside the container by running
docker exec -it seedsigner-os-build-images-1 bash
Once you are in the container you can use the build script directly from the /opt
directory
./build.sh --pi0 --app-repo=https://github.com/seedsigner/seedsigner.git --app-branch=dev --no-clean
or
./build.sh --pi0 --app-repo=https://github.com/seedsigner/seedsigner.git --app-commit-id=9c36f5c --no-clean
Or you can use any of the Buildroot customization commands like make menuconfig
or linux-menuconfig
from the /output
directory
Move images manually built with make
with the command mv images/seedsigner_os.img /images/
Each board also has a developer configuration (dev config). Inside the /opt
folder are all the build configs for each board matching the name of the build script option. The dev configs are built to work on each board but enable many of the kernel and OS features needed for development. This also makes this the image built less secure, so please do not use with real funds. Dev configs are only used when the --dev
option is passed in to the build.sh script.
If you are not using the docker image, then these build tools will be required for cross-compiling with Buildroot. This is only tested and expected to work on a debian based OS using apt package manager (not MacOS). This single command will install required dependencies for a debian based linux os.
sudo apt update && sudo apt install make binutils build-essential gcc g++ patch gzip bzip2 perl tar cpio unzip rsync file bc libssl-dev
Then to build to image(s), run the build script passing in the desired options
cd opt
./build.sh --pi0
You can see the different build options with ./build.sh --help
See the Buildroot quick start guide first
Buildroot:
make menuconfig
Linux Kernel:
make linux-menuconfig
Busybox:
busybox-menuconfig
Kernel and User space all built from scratch.
- First layer is the hardware. Normally this is the raspberry pi board, camera, LCD Waveshare HAT, and microSD card.
- Second layer is the linux kernel. Using buildroot specific and minimum required modules have been hand selected to use in the kernel. This layer is required to make use of hardware functionality.
- Third layer is user space. This is were all the libraries and applications preside. The SeedSigner applications lives in this space. This is also where libraries typically live to do networking, display drivers, external port communications, etc. However on SeedSignerOS none of these drivers or libraries are loaded (that are typically found in a linux OS).
The zImage a compressed version of the Linux kernel that is self-extracting. In that compressed image, we added RootFS. The entire system in a single file!
- When Raspberry Pi is powered on, the bootloader starts on GPU and read the MicroSD (SDRAM disabled at this point)
- GPU reads bootcode.bin and starts the bootloader to enable SDRAM
- Then start_x.elf reads config.txt, cmdline.txt and kernel
- CPU starts working and then boot the kernel
Source: https://raspberrypi.stackexchange.com/questions/10442/what-is-the-boot-sequence