@@ -1159,3 +1159,130 @@ this, the target must provide a definition for the `boot_save_shared_data()`
11591159function which is declared in ` boot/bootutil/include/bootutil/boot_record.h ` .
11601160The ` boot_add_data_to_shared_area() ` function can be used for adding new TLV
11611161entries to the shared data area.
1162+
1163+ ## [ Testing in CI] ( #testing-in-ci )
1164+
1165+ ### [ Testing Fault Injection Hardening (FIH)] ( #testing-fih )
1166+
1167+ The CI currently tests the Fault Injection Hardening feature of MCUboot by
1168+ executing instruction skip during execution, and looking at whether a corrupted
1169+ image was booted by the bootloader or not.
1170+
1171+ The main idea is that instruction skipping can be automated by scripting a
1172+ debugger to automatically execute the following steps:
1173+
1174+ - Set breakpoint at specified address.
1175+ - Continue execution.
1176+ - On breakpoint hit increase the Program Counter.
1177+ - Continue execution.
1178+ - Detach from target after a timeout reached.
1179+
1180+ Whether or not the corrupted image was booted or not can be decided by looking
1181+ for certain entries in the log.
1182+
1183+ As MCUboot is deployed on a microcontroller, testing FI would not make much
1184+ sense in the simulator environment running on a host machine with different
1185+ architecture than the MCU's, as the degree of hardening depends on compiler
1186+ behavior. For example, (a bit counterintuitively) the code produced by gcc
1187+ with ` -O0 ` optimisation is more resilient against FI attacks than the code
1188+ generated with ` -O3 ` or ` -Os ` optimizations.
1189+
1190+ To run on a desired architecture in the CI, the tests need to be executed on an
1191+ emulator (as real devices are not available in the CI environment). For this
1192+ implementation QEMU is selected.
1193+
1194+ For the tests MCUboot needs a set of drivers and an implementation of a main
1195+ function. For the purpose of this test Trusted-Firmware-M has been selected as
1196+ it supports Armv8-M platforms that are also emulated by QEMU.
1197+
1198+ The tests run in a docker container inside the CI VMs, to make it more easy to
1199+ deploy build and test environment (QEMU, compilers, interpreters). The CI VMs
1200+ seems to be using quite old Ubuntu (16.04).
1201+
1202+ The sequence of the testing is the following (pseudo code):
1203+
1204+ ``` sh
1205+ fn main ()
1206+ # Implemented in ci/fih-tests_install.sh
1207+ generate_docker_image(Dockerfile)
1208+
1209+ # See details below. Implemented in ci/fih-tests_run.sh.
1210+ # Calling the function with different parameters is done by Travis CI based on
1211+ # the values provided in the .travis.yaml
1212+ start_docker_image(skip_sizes, build_type, damage_type, fih_level)
1213+
1214+ fn start_docker_image(skip_sizes, build_type, damage_type, fih_level)
1215+ # implemented in ci/fih_test_docker/execute_test.sh
1216+ compile_mcuboot(build_type)
1217+
1218+ # implemented in ci/fih_test_docker/damage_image.py
1219+ damage_image(damage_type)
1220+
1221+ # implemented in ci/fih_test_docker/run_fi_test.sh
1222+ ranges = generate_address_ranges ()
1223+ for s in skip_sizes
1224+ for r in ranges
1225+ do_skip_in_qemu(s, r) # See details below
1226+ evaluate_logs ()
1227+
1228+ fn do_skip_in_qemu(size, range)
1229+ for a in r
1230+ run_qemu(a, size) # See details below
1231+
1232+ # this part is implemented in ci/fih_test_docker/fi_tester_gdb.sh
1233+ fn run_qemu(a, size)
1234+ script = create_debugger_script(a, size)
1235+ start_qemu_in_bacground () # logs serial out to a file
1236+ gdb_attach_to_qemu(script)
1237+ kill_qemu ()
1238+
1239+ # This checks the debugger and the quemu logs, and decides whether the tets
1240+ # was executed successfully, and whether the image is booted or not. Then
1241+ # emits a yaml fragment on the standard out to be processed by the caller
1242+ # script
1243+ evaluate_run(qemu_log_file)
1244+ ` ` `
1245+
1246+ Further notes:
1247+
1248+ - The image is corrupted by changing its signature.
1249+ - MCUBOOT_FIH_PROFILE_MAX is not tested as it requires TRNG, and the AN521
1250+ platform has no support for it. However this profile adds the random
1251+ execution delay to the code, so should not affect the instruction skip results
1252+ too much, because break point is placed at exact address. But in practice this
1253+ makes harder the accurate timing of the attack.
1254+ - The test cases defined in .travis.yml always return ` passed` , if they were
1255+ executed successfully. A yaml file is created during test execution with the
1256+ details of the test execution results. A summary of the collected results is
1257+ printed in the log at the end of the test.
1258+
1259+ An advantage of having the tests running in a docker image is that it is
1260+ possible to run the tests on a local machine that has git and docker, without
1261+ installing any additional software.
1262+
1263+ So, running the test on the host looks like the following (The commands below
1264+ are issued from the MCUboot source directory):
1265+
1266+ ` ` ` sh
1267+ $ ./ci/fih-tests_install.sh
1268+ $ FIH_LEVEL=MCUBOOT_FIH_PROFILE_MEDIUM BUILD_TYPE=RELEASE SKIP_SIZE=2 \
1269+ DAMAGE_TYPE=SIGNATURE ./ci/fih-tests_run.sh
1270+ ` ` `
1271+ On the travis CI the environment variables in the last command are set based on
1272+ the configs provided in the ` .travis.yaml`
1273+
1274+ This starts the tests, however the shell that it is running in is not
1275+ interactive, it is not possible to examine the results of the test run. To have
1276+ an interactive shell where the results can be examined, the following can be
1277+ done:
1278+
1279+ - The docker image needs to be built with ` ci/fih-tests_install.sh` as described
1280+ above.
1281+ - Start the docker image with the following command:
1282+ ` docker run -i -t mcuboot/fih-test` .
1283+ - Execute the test with a command similar to the following:
1284+ ` /root/execute_test.sh 8 RELEASE SIGNATURE MEDIUM` . After the test finishes,
1285+ the shell returns, and it is possible to investigate the results. It is also
1286+ possible to stop the test with _Ctrl+c_. The parameters to the
1287+ ` execute_test.sh` are ` SKIP_SIZE` , ` BUILD_TYPE` , ` DAMAGE_TYPE` , ` FIH_LEVEL` in
1288+ order.
0 commit comments