RAUC Update and Device Management Manual (L-1006e.A0)
Table of Contents
RAUC
Since the warrior release, the RAUC (Robust Auto-Update Controller) mechanism support has been added to Yogurt. It controls the procedure of updating a device with new firmware. This includes updating Linux kernel, Device Tree, and root filesystem. It currently does not update the bootloader. For more information about RAUC, go tohttps://rauc.readthedocs.io/en/latest/.
For the i.MX8, RAUC uses the U-Boot environment to handle the system (see https://rauc.readthedocs.io/en/latest/integration.html#id4). It can be used in different update scenarios. Take a look at the use cases below and the example setup used in the BSP.
RAUC on i.MX 8M Mini
With the FSL-i.MX8MM-PD20.1.0 BSP release, RAUC can be used with eMMC. It is not, by default, enabled but our example can be configured and activated with the instructions shown below. RAUC can be used in different update scenarios. As an example, we configured the BSP to use an A/B setup to have a completely redundant system (except for the bootloader).
The partition layout is defined in the /etc/rauc/system.conf file:
[system]
compatible=phyboard-polis-imx8mm-2
bootloader=uboot
mountprefix=/mnt/rauc
[handlers]
pre-install=/usr/bin/rauc_downgrade_barrier.sh
[keyring]
path=ca.cert.pem
# System A
[slot.rootfs.0]
device=/dev/mmcblk2p2
type=ext4
bootname=system0
[slot.boot.0]
device=/dev/mmcblk2p1
type=vfat
parent=rootfs.0
# System B
[slot.rootfs.1]
device=/dev/mmcblk2p4
type=ext4
bootname=system1
[slot.boot.1]
device=/dev/mmcblk2p3
type=vfat
parent=rootfs.1Warning
Updates with RAUC use an openSSL certificate to verify the validity of an image. The BSP includes a certificate that can be used for development. In a productive system, however, it is highly recommended to use a self-created key and certificate.
Initialize eMMC for RAUC
To use RAUC, the eMMC needs to be flashed and a U-Boot parameter must be set. To flash the eMMC with the correct partitions a line needs to be added in the local.conf file of the BSP:
# Select a preconfigured A/B system setup for SD/eMMC images. #WKS_FILES_mx6 = "imx6-rauc-sdimage.wks" #WKS_FILES_mx6ul = "imx6-rauc-sdimage.wks" WKS_FILES_mx8m = "imx8m-rauc-sdimage.wks"
Enable the correct partitioning scheme by removing the comment as shown above. Build the image as usual:
host$ bitbake phytec-headless-image
Copy the .sdcard image onto a running system of the target and flash the eMMC:
target$ dd if=<name_of_image>.sdcard of=/dev/mmcblk2 bs=1MB conv=fsync
Now the target is able to boot the flashed A/B system.
After the successful boot, a U-Boot parameter needs to be set. This command is used to view the available parameters:
target$ fw_printenv
You should see this parameter along with others in the output:
doraucboot=0
To enable booting the A/B system with RAUC, set this variable to "1":
target$ fw_setenv doraucboot 1
The parameters can also be edited in U-Boot. Restart your board and hit any key to stop the autoboot. The environment variables can now be viewed:
bootloader$ printenv
and set:
bootloader$ setenv
Boot into the system:
bootloader$ boot
You should now be able to install RAUC bundles on your machine with the A/B boot system.
Creating RAUC Bundles
To update your system with RAUC, a RAUC bundle (.raucb) needs to be created. It contains all required images and scripts for the update and a RAUC manifest.raucm that describes the content of the bundle for the RAUC update on the target. The BSP includes a Yocto target that lets you build a RAUC bundle from your Yocto build.
To create the bundle with Yocto, run:
host$ bitbake phytec-qt5demo-bundle
or
host$ bitbake phytec-headless-bundle
This results in the creation of a .raucb bundle file in deploy/images/phyboard-polis-imx8mm-2/ which can be used for an update described in Update eMMC with RAUC. There is no need to create a manifest.raucm manually as it is created automatically during the build of the bundle. As a reference, the created manifest would look something like:
[update] compatible=phyboard-polis-imx8mm-2 version=r0 description=PHYTEC rauc bundle based on 2.7.1 build=20200414092407 [image.rootfs] sha256=ec8565d6071f4d99cbaa796cb5d46e8609982dee473a447efc35a8cbb745759d size=99942000 filename=phytec-headless-image-phyboard-polis-imx8mm-2.tar.gz [image.boot] sha256=43fb9ab76764dc7029da9b51b87347de20e6ac78f4eac06bfee22b7ba427dc87 size=12410534 filename=boot.tar.gz.img
For more information about the manifest format, see https://rauc.readthedocs.io/en/latest/reference.html#manifest.
Update eMMC with RAUC
To update the eMMC with RAUC, the RAUC bundle file previously created first needs to be copied to the board or to a memory device that can be mounted in Linux. One way is to copy the bundle file with scp, but make sure that there is enough space left on the board's filesystem. To do this, boot the target board to Linux and connect it via Ethernet to your host PC.
Run on the host:
host$ scp phytec-headless-bundle-phyboard-polis-imx8mm-2.raucb root@192.168.3.11:/home/root/
On the target, the bundle can be verified:
target$ rauc info phytec-headless-bundle-phyboard-polis-imx8mm-2.raucb
and the output should look similar to this:
rauc-Message: 12:52:49.821: Reading bundle: /phytec-headless-bundle-phyboard-polis-imx8mm-2.raucb
rauc-Message: 12:52:49.830: Verifying bundle...
Compatible: 'phyboard-polis-imx8mm-2'
Version: 'r0'
Description: 'PHYTEC rauc bundle based on 2.7.1'
Build: '20200414092407'
Hooks: ''
2 Images:
(1) phytec-headless-image-phyboard-polis-imx8mm-2.tar.gz
Slotclass: rootfs
Checksum: ec8565d6071f4d99cbaa796cb5d46e8609982dee473a447efc35a8cbb745759d
Size: 99942000
Hooks:
(2) boot.tar.gz.img
Slotclass: boot
Checksum: 43fb9ab76764dc7029da9b51b87347de20e6ac78f4eac06bfee22b7ba427dc87
Size: 12410534
Hooks:
0 Files
Certificate Chain:
0 Subject: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH Development-1
Issuer: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Development
SPKI sha256: E2:47:5F:32:05:37:04:D4:8C:48:8D:A6:74:A8:21:2E:97:41:EE:88:74:B5:F4:65:75:97:76:1D:FF:1D:7B:EE
Not Before: Jan 1 00:00:00 1970 GMT
Not After: Dec 31 23:59:59 9999 GMT
1 Subject: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Development
Issuer: /O=PHYTEC Messtechnik GmbH/CN=PHYTEC Messtechnik GmbH PHYTEC BSP CA Development
SPKI sha256: AB:5C:DB:C6:0A:ED:A4:48:B9:40:AC:B1:48:06:AA:BA:92:09:83:8C:DC:6F:E1:5F:B6:FB:0C:39:3C:3B:E6:A2
Not Before: Jan 1 00:00:00 1970 GMT
Not After: Dec 31 23:59:59 9999 GMTTo check the current state of the system, run:
target$ rauc status
and get output similar to this:
Compatible: phyboard-polis-imx8mm-2
Variant:
Booted from: (null) (/dev/mmcblk2p2)
Activated: (null) ((null))
slot states:
rootfs.0: class=rootfs, device=/dev/mmcblk1p2, type=ext4, bootname=system0
state=inactive, description=, parent=(none), mountpoint=(none)
boot status=bad
boot.0: class=boot, device=/dev/mmcblk1p1, type=vfat, bootname=(null)
state=inactive, description=, parent=rootfs.0, mountpoint=(none)
rootfs.1: class=rootfs, device=/dev/mmcblk1p4, type=ext4, bootname=system1
state=inactive, description=, parent=(none), mountpoint=(none)
boot status=bad
boot.1: class=boot, device=/dev/mmcblk1p3, type=vfat, bootname=(null)
state=inactive, description=, parent=rootfs.1, mountpoint=(none)To update the currently inactive system with the downloaded bundle, run:
target$ rauc install phytec-headless-bundle-phyboard-polis-imx8mm-2.raucb
and reboot afterward:
target$ reboot
With the success of the update, RAUC automatically switches the active system to the newly updated system. Now during reboot, RAUC counts the boot attempts of the kernel and if it fails more often than specified in the state framework of the system, RAUC switches back to the old system and marks the new system as bad. If the boot attempt to the kernel is successful, the new system is marked as good and the old system can now be updated with the same instructions. After two successful rauc install and reboot, both systems are updated.
Tip
When you update from a USB stick, make sure to remove the stick after a successful update before reboot. If not, an automatic update will be started after each boot. This is due to the "Automatic Update from USB Flash Drive example" you can find below.
Changing the Active Boot Slot
It is possible to switch the active system manually:
target$ rauc status mark-active other
After a reboot, the target now starts from the other system.
Use Case 1: Automatic Update from USB Flash Drive with RAUC
One of the most prominent use cases for RAUC might be an automatic update system from a USB flash drive. This use case is implemented in the BSP as a reference example. We combine only standard Linux mechanisms with RAUC to build the system. The kernel notifies udev when a device gets plugged into the USB port. We use a custom udev rule to trigger a systemd service when this event happens.
KERNEL!="sd[a-z][0-9]", GOTO="media_by_label_auto_mount_end"
# Trigger systemd service
ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="update-usb@%k.service"
# Exit
LABEL="media_by_label_auto_mount_end"The service automatically mounts the USB flash drive and notifies the application.
[Unit] Description=usb media RAUC service After=multi-user.target Requires=rauc.service [Service] Type=oneshot Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket ExecStartPre=/bin/mkdir -p /media/%I ExecStartPre=/bin/mount -t auto /dev/%I /media/%I ExecStart=/usr/bin/update_usb.sh %I ExecStop=/bin/umount -l /media/%i ExecStopPost=-/bin/rmdir /media/%I
In our reference implementation, we simply use a bash script for the application logic.
#!/bin/sh
MOUNT=/media/$1
NUMRAUCM=$(find ${MOUNT}/*.raucb -maxdepth 0 | wc -l)
[ "$NUMRAUCM" -eq 0 ] && echo "${MOUNT}*.raucb not found" && exit
[ "$NUMRAUCM" -ne 1 ] && echo "more than one ${MOUNT}/*.raucb" && exit
rauc install $MOUNT/*.raucb
if [ "$?" -ne 0 ]; then
echo "Failed to install RAUC bundle."
else
echo "Update successful."
fi
exit $?The update logic can be integrated into an application by using systemd's D-Bus API. RAUC does not need to be called by its command-line interface but can be integrated with D-Bus.
Tip
RAUC features a D-Bus API interface (see https://rauc.readthedocs.io/en/latest/using.html#using-the-d-bus-api).
Use Case 2: Security Measurement: Downgrade Barrier
As a second reference example, we will implement a security mechanism: a downgrade barrier. When you detect a security vulnerability on your system, you will fix it and update your system. The systems with the new software will now be secure again. If an attacker gets ahold of the old software update bundle, which still has a valid signature, the attacker might have the possibility to install the old software and still take advantage of the previously fixed security vulnerability. To prevent this from happening, you could revoke the update certificate for every single update and create a new one. This might be difficult to handle, depending on the environment. A simpler solution would be to allow updates only in one direction using a version check.
#!/bin/sh
VERSION_FILE=/etc/rauc/downgrade_barrier_version
MANIFEST_FILE=${RAUC_UPDATE_SOURCE}/manifest.raucm
[ ! -f ${VERSION_FILE} ] && exit 1
[ ! -f ${MANIFEST_FILE} ] && exit 2
VERSION=`cat ${VERSION_FILE} | cut -d 'r' -f 2`
BUNDLE_VERSION=`grep "version" -rI ${MANIFEST_FILE} | cut -d 'r' -f 3`
# check from empty or unset variables
[ -z "${VERSION}" ] && exit 3
[ -z "${BUNDLE_VERSION}" ] && exit 4
# developer mode, allow all updates if version is r0
#[ ${VERSION} -eq 0 ] && exit 0
# downgrade barrier
if [ ${VERSION} -gt ${BUNDLE_VERSION} ]; then
echo "Downgrade barrier blocked rauc update! CODE5\n"
else
exit 0
fi
exit 5The script is installed on the target but it is not activated. You need to remove the developer mode line in the script to activate it.
U-Boot Environment Variables
As a reference, these are the most important U-Boot variables that are used for the A/B system with RAUC:
| Name | Function |
|---|---|
BOOT_ORDER | Contains a space-separated list of boot-targets in the order they should be tried. This parameter is automatically set by RAUC. |
| Contains the number of remaining boot attempts to perform for the respective slot. This parameter is automatically set by RAUC. |
raucboot | Contains the boot logic that sets the partitions so the correct system is loaded. |
doraucboot | Enables booting the A/B system if set to 1 and disables it if set to 0. |
raucslot | Contains the current boot slot used in BOOT_<slot>_LEFT. |
raucargs | Sets the Kernel bootargs like console, root, and RAUC slot. |
raucdev | Sets the eMMC as the boot device. |
raucrootpart | Sets the root filesystem partitions of the device. |
raucpart | Sets the boot partitions of the device. |
loadraucimage | Loads the Kernel image into RAM. |
loadraucfdt | Loads the device tree into RAM. |
Note
A change in the partition layout, e.g. when using an additional data partition, may require changing the variables raucrootpart and raucpart. Make sure to rebuild your image with the new bootloader environment after you have made the appropriate changes.