Guide to Busybox Compilation on Automotive Build Platforms
What is busybox?
Busybox is an GPL2 software project that combines tiny versions of many common UNIX utilities into a single small executable. It has been around since the early 90’s, and it’s used in a vast variety of embedded systems, this is why it gained the title Swiss Army Knife of Embedded Linux.
Intro to (some) using Busybox security issues
In Busybox, each utility is called an applet. Calling make config, users can customize applets and compile only applets relevant to them into one unified and easy to use binary.
Calling the make install command, Busybox will install itself on the system by copying your customized Busybox binary to the /bin folder. Busybox automatically creates symlinks for all compiled applets. Each symlink will call the Busybox binary with the relevant applet name.
This means that if we call an applet, busybox will be executed with the applet as the first parameter (argv[0]).
Securing the Busybox binary is challenging because it is difficult to change permissions or track each individual applet for the following reasons:
- Since operating system access control is file-system based, different applets run from the same executable, it is difficult to apply different permissions to each applet.
- Different environments (production, development, debug etc…) need different kinds of configurations.
- When busybox is compiled to one binary, it is harder to track which applets are included in this binary than it will be when separating the applet to different standalone binaries, also there can be more than one instance of busybox in the target file system, which makes it even harder to validate in the release process.
Separating the applets to different binaries
Creating different binaries for different applets is a great solution for maintaining busybox functionality without introducing the security issues raised by running all the applets in one binary.
You can find an example of compiling busybox to different applets in the busybox source code in a make_single_applets.sh script.
The script requires you to provide a busybox config file by either calling make config or by providing one pre-made.
The next step will be to find all the applets in the config file. Remove all the applets from the config file, except the one that you want to include and compile busybox.
The script will continue until all the applets are compiled.
Challenges in industrial build platforms
Industrial build platforms require adaptation and more functionality than a single script. For example, you may be required to do any or all of the following:
- Execute in a make file format
- Support different types of cross platform compilers
- Use environment specific variables and locations
- Support different configuration files
- Perform a Cleaning process
- Perform an installation process on target filesystem
Script adaptations to industrial build platforms
Make file format: You will need to adapt the process to work in a makefile format to support specific commands:
- Make
- Make config
- Make clean
- Make install
Each command has its own details that are build-platform specific and require an understanding of the target build system.
Compiling process
Different build systems have different compilation processes, some need to use different environment variables in order for the compiler to work with the right prerequisites.
One example can be the cross compiler, which can be changed from different build environments and if not supported correctly, the binaries won’t work on the target.
$(MAKE) CROSS_COMPILE=$(CROSS_COMPILER)- $@;
You also need to support the installation process, so you need to create a list of all applets that need to be compiled.
applets=(“$$(grep ^IF_ include/applets.h | grep -v ‘^IF_FEATURE_’ | sed ‘s/IF_([A-Z0-9._-]*)(.*/1/’ | grep -v ‘^BUSYBOX$$’ )”) ;
for applet in $${applets[@]}; do
echo “$${applet} ” >> busybox_applet_list.config;
You should keep all the configuration files in a separate directory so you can verify that the applet configuration is as intended.
mv .config “busybox_config_$${applet}” ;
Configuring process
The config process can vary across environments, some config processes need to support different configurations depending on its use. I.e. for release, development, and debug.
.config:
cp ${WORK_DIR}/busybox.config .config;
You may want to keep the busybox support for menuconfig, in which case you will need to decide how you are going to implement it in your environment.
Cleaning process
In the compiling process you not only create the regular busybox compiled artifacts but you also create different binaries that may be located in different paths in your build system. You will need to customize your cleaning process to suit your environment.
clean distclean:
$(MAKE) $@
rm -rf ./bin
rm -f busybox_applet_list.config
Installation process
After you compiled all the applets to different binaries, install them on your build system. In order to do so you will need to know which applets were compiled and where they are located in the build system.
applets=($$(cat busybox_applet_list.config));
It is necessary to know where each applet is going to be located in the file system. Luckily, you can extract this information in the file include/applets.h and place each applet in the right folder.
target_dir_const=”$$(cat ./include/applets.h | grep “IF_$${applet^^}(” | grep -o ‘BB_DIR_[A-Z|_]*’)”;
case “$$target_dir_const” in
“BB_DIR_SBIN”)
target_dir=”sbin”
;;
“BB_DIR_BIN”)
target_dir=”bin”
;;
“BB_DIR_USR_SBIN”)
target_dir=”sbin”
;;
“BB_DIR_USR_BIN”)
target_dir=”bin”
;;
*)
echo “Unknown installation directory: $${target_dir_const}”;
exit 1;
;;
It is necessary to know how busybox will call the binary file in the system (this is different from the name in the config file we are parsing in the compilation stage) by parsing the applets.h file from the include directory.
target_applet_const=”$$(cat ./include/applets.h | grep “IF_$${applet^^}(” | grep -o ‘APPLET[A-Z|_]*(s*[a-z]*’| grep -o ‘[a-z]*’)”;
Finally, copy the applet to its correct location in the target build
cp”./bin/${applet}” “$(buildroot)//${target_dir}/${target_applet_const}”;
Summary
Busybox is a GPL2 tool that is used in many embedded systems and linux distributions, it provides us with many useful tools that are easy to use, but in some cases when packaged in one binary file it can increase your security risks. By separating each applet to a different binary, we are able to maintain full functionally while reducing exposure to cyber risk.
Industrial (and automotive) build systems require adaptations to the generic process of separating each applet to a different binary and some stages need to be customized to the specific build environment as illustrated in this document.
Author: Isaac Milstain, Embedded Linux Software Developer
at PlaxidityX