intiramfs / initramfs-tools / busybox / dropbear (Ubuntu)

Originally written for Ubuntu 18.04

Changes in Ubuntu 20.04:

  • /etc/dropbear-initramfs has moved to /etc/dropbear/initramfs (automatically done by upgrade)

Initramfs Introduction

https://wiki.ubuntu.com/Initramfs

  • Kernel unpacks initramfs early in the boot process and calls /init
  • Initramfs is cpio packed inital root filesystem
  • It is mainly used for measures to mount the real root filesystem.
    Examples: load kernel drivers for disk access (raid), or manage encrypted root unlocking
  • It usually includes busybox shell and commands.

Busybox

https://busybox.net/
https://busybox.net/downloads/BusyBox.html

Many unix programs in simplified form in a single executable.

Note: Ubuntu includes only a very limited version of busybox.
To install full version see: https://www.ullright.org/ullWiki/show/install-full-busybox-in-initramfs-ubuntu-18-04

Ubuntu initramfs-tools

http://manpages.ubuntu.com/manpages/bionic/man8/initramfs-tools.8.html

Handles creation of initramfs.

After changing config, adding hooks or script you have to re-generate initramfs with

  • update-initramfs -u

Config file:

  • vi /etc/initramfs-tools/initramfs.conf

View initramfs content:

  • lsinitramfs /initrd.img

Extract initramfs to check content of files:

  • mkdir /tmp/initramfs-content
  • cd /tmp/initramfs-content
  • unmkinitramfs /initrd.img .
  • # do stuff like ls -la, cat /dir/foo

Useful commands inside initramfs

Get process id by complex name

  • ps | grep 'busybox2 crond' | grep -v grep | awk '{ print $1 }'

Kill procress by complex name

  • kill $(ps | grep 'busybox2 crond' | grep -v grep | awk '{ print $1 }')

Output to main terminal screen

  • echo foo > /dev/tty0

Initramfs generation

There are distribution hooks and scripts in /usr/share/initramfs-tools and custom hooks and scripts can be placed in /etc/initramfs-tools.

The order of the hooks and scripts can be influenced by the prequisites "PREREQ".
But the scripts in /usr/share/initramfs-tools are always executed before the hooks in /etc/initramfs-tools!

Hooks

Initramfs hooks allow to modify initramfs. E.g. install executables or copy files.

System hooks from packages (like dropbear) are in

  • /usr/share/initramfs-tools/hooks/

Custom user defined hooks go into

  • /etc/initramfs-tools/hooks/

It is not possible to prevent execution of distribution hooks in "/usr/share/initramfs-tools/hooks/".
So you can only add a custom hook in /etc/initramfs-tools/hooks/ with fixes, eg. copy a patched file.

Boot Scripts

Scripts are run inside of initramfs at different stages.

Boot scripts from packages are in

  • /usr/share/initramfs-tools/scripts/

Path for custom boot scripts:

  • /etc/initramfs-tools/scripts/

Distribution boot scripts in /usr/share/initramfs-tools/scripts/ can simply be overwritten by putting a script with the same name in /etc/initramfs-tools/scripts/.../...

 

Subdirectories of different stages:

  • init-top  the  scripts in this directory are the first scripts to be executed after
                  sysfs and procfs have been mounted.  It also runs the udev hook for populating  the
                  /dev tree (udev will keep running until init-bottom).

  • init-premount   happens  after  modules  specified  by  hooks  and  /etc/initramfs-
                  tools/modules have been loaded.

    • e.g. netconf, dropbear

  • local-top OR nfs-top After these scripts have been executed, the root  device  node
                  is expected to be present (local) or the network interface is expected to be usable
                  (NFS).      

    • eg cryptroot, mdadm     

  • local-block These scripts are called with the name of a local block device.   After
                  these  scripts  have  been  executed,  that  device node should be present.  If the
                  local-top or local-block scripts fail to create the wanted device node, the  local-
                  block scripts will be called periodically to try again.            

  • local-premount OR nfs-premount are run after the sanity of the root device has been
                  verified (local) or the network interface has been brought up (NFS), but before the
                  actual root fs has been mounted.

  • local-bottom OR nfs-bottom are run after the rootfs has been mounted (local) or the
                  NFS root share has been mounted.

  • init-bottom are the last scripts to be executed before procfs and sysfs  are  moved
                  to the real rootfs and execution is turned over to the init binary which should now
                  be found in the mounted rootfs. udev is stopped.

Examples

Package hooks

Interesting examples: (needs "apt install dropbear")

  • vi /usr/share/initramfs-tools/hooks/dropbear
  • vi /usr/share/initramfs-tools/hooks/cryptroot-unlock
    • adds message to /etc/motd (message of the day)

Custom hook to install additional executables

Executables are simply copied from the normal linux system.
If not installed, use "apt install xxx" first.

  • vi /etc/initramfs-tools/hooks/addons
    • #!/bin/sh
      
      # add hookscripts which need to be executed before this script
      PREREQ="dropbear"
      
      prereqs() {
          echo "$PREREQ"
      }
      
      case "$1" in
          prereqs)
              prereqs
              exit 0
          ;;
      esac
      
      # Load helper functions
      . /usr/share/initramfs-tools/hook-functions
      
      # Helper function to copy an executable to be available in initramfs
      copy_exec /usr/bin/jq /bin
      copy_exec /usr/bin/curl /bin
      copy_exec /usr/bin/dbclient /bin
      
  • chmod 755 /etc/initramfs-tools/hooks/addons
  • update-initramfs -u

 

Patch distribution initramfs files

Example: Ubuntu 22.04 /sbin/dhclient-script uses commands/options which are not available in initramfs

Prepare patch file

  • cd /etc/initramfs-tools/hooks/
  • cp /sbin/dhclient-script /tmp
  • vi /tmp/dhclient-script
    • #line 97
              # PATCH for initramfs:
              #if [ -f $resolv_conf ]; then
                  # chown is not available in initramfs                       
                  #chown --reference=$resolv_conf $new_resolv_conf
                  # initramfs chmod does not have option --reference
                  #chmod --reference=$resolv_conf $new_resolv_conf
              #fi

 

  • diff --unified /sbin/dhclient-script /tmp/dhclient-script > /etc/initramfs-tools/hooks/dhclient-script.22.04.patch
  • You would apply the patch like this

    • patch /mydir/mytarget -i /etc/initramfs-tools/hooks/dhclient-script.22.04.patch

  • And check it with:

    • tail --lines=+96 /tmp/dhclient-script | head --lines=10

Create hook to apply patch

  • vi /etc/initramfs-tools/hooks/dhclient-script-patch
    • #!/bin/sh
      
      # Patch dhclient-script to not use commands/options not available in initramfs
      # $DESTDIR/sbin/dhclient-script is originally copied to initramfs by /usr/share/initramfs-tools/hooks/zz-dhclient
      
      # To be idempotent never reverse the patch (--forward) and don't create .rej files
      # We also swallow the warning "Reversed (or previously applied) patch detected!  Skipping patch. 1 out of 1 hunk ignored" with " > /dev/null"
      # Further more we need to catch the exit code 1 of "hunks ignored". (appended " || [ $? -eq 1 ]")
      
      #tail --lines=+96 /sbin/dhclient-script | head --lines=10
      #tail --lines=+96 $DESTDIR/sbin/dhclient-script | head --lines=10
      patch --silent --forward --reject-file=- -i /etc/initramfs-tools/hooks/dhclient-script.22.04.patch $DESTDIR/sbin/dhclient-script > /dev/null || [ $? -eq 1 ]
      #tail --lines=+96 /sbin/dhclient-script | head --lines=10
      #tail --lines=+96 $DESTDIR/sbin/dhclient-script | head --lines=10
  • chmod 755 /etc/initramfs-tools/hooks/dhclient-script-patch

  • update-initramfs -u

 

 

dropbearconvert

Converts openssh private key to dropbear format

  • usr/lib/dropbear/dropbearconvert
    • All arguments must be specified
      Usage: /usr/lib/dropbear/dropbearconvert <inputtype> <outputtype> <inputfile> <outputfile>
      
      CAUTION: This program is for convenience only, and is not secure if used on
      untrusted input files, ie it could allow arbitrary code execution.
      All parameters must be specified in order.
      
      The input and output types are one of:
      openssh
      dropbear
      
      Example:
      dropbearconvert openssh dropbear /etc/ssh/ssh_host_rsa_key /etc/dropbear_rsa_host_key

dropbearkey

Show public key from private key:

  • dropbearkey -y -f ./root/ssh/id_dropbear

initramfs / dropbear create user / password

check this out: /usr/share.../hooks/dropbear

  • for x in passwd group; do echo "$x: files"; done >"$DESTDIR/etc/nsswitch.conf"
    echo "root:*:0:0::${home#$DESTDIR}:/bin/sh" >"$DESTDIR/etc/passwd"
    echo "root:!:0:" >"$DESTDIR/etc/group"
  • # busybox2 passwd root
    Changing password for root
    New password:
    Bad password: too weak
    Retype password:
    passwd: password for root changed by root
    # cat /etc/passwd
    root:$5$A3HlvdYi1hT3drz4$z4DFGusaqsQMQafFpKyuCQDBEOWfEwYCbqzKaioqQlB:0:0::/root:/bin/sh

  • echo "foo" | openssl passwd -stdin -6 -salt verySalty
    $6$9rQrmF1Y$sMMnndQxV3NQ3T0LRcBS/7ZXHpJOv.M7svlP9sUxcn21yKlcD5ozvFGmu2B4pgesECc7LXP96XfK1FXGjbjra1

dropbear get host key

@initramfs:

  • host key:

    • dropbearkey -y -f /etc/dropbear/dropbear_rsa_host_key

      • Public key portion is:
        
        ssh-rsa AAA...1h1 root@myhostname
        
        Fingerprint: md5 63:ab...fb:1b
  • user ssh key:
    • dropbearkey -y -f /root/.ssh/id_dropbear

@host normally booted:

  • dropbearkey -y -f /etc/dropbear-initramfs/dropbear_rsa_host_key

Get only key portion:

  • dropbearkey -y -f /etc/dropbear-initramfs/dropbear_rsa_host_key | tail -2 | head -1