Protecting U-Boot Command Line

The bootloader is a critical part of the device firmware. Often, it is the first piece of software the developers have control over (after all, it’s quite difficult to modify the ROM bootloader), and it is responsible for loading the operating system. Preferably, it also verifies the integrity of the operating system, ensuring secure and trusted boot processes.

U-Boot is a popular bootloader for embedded systems. Unfortunately, it tends to be somewhat unsafe with the default settings (at least in Yocto builds). One quite commonly used feature of the U-Boot is the command line console that allows using a CLI for interactive boot flows, debugging, and maintenance. This, in practice, allows writing boot scripts on the fly. Unfortunately, access to this command line isn’t really secured, as you can usually use any key to stop the boot and start messing around.

This is good for debugging and maintenance. Unfortunately, it is also good for the possible adversaries as well, as they can easily modify how the bootloader operates, what artefacts it loads, etc. Therefore, the developers should take care of securing access to the console interface. I’ll share in this blog post how to add a password to the command line interface (technically, a stop string, more on that later), and how to disable the CLI if so desired.

Securing the Command Line with a Stop String

A common method for securing anything is a password. The security of password-based authentication can be debated, but when working with something as limited as the bootloader, it is difficult to come up with reliable multi-factor authentication schemes, etc. Also, the developer should stay in control of the bootloader password, meaning that they can make it secure without the end user being able to make it weaker. The physical access to the bootloader console is usually limited as well. And finally, the bootloader password in general is rarely used, so it doesn’t have to be “convenient” to enter.

U-Boot supports protecting the command line interface with a “password”. Technically, this is called “autoboot stop string” in U-Boot, which is a very literal description. With U-Boot, we almost always have the autoboot feature enabled, which boots the device without user intervention. However, a special “stop string” can be used to abort this autoboot process, and once the autoboot aborts, the U-Boot by default drops to the command line interface. So this “stop string” is not really a password that allows access for the user; the access just happens to be a byproduct of stopping the usual functionality.

The configuration of the stop string feature is a bit complex. I mean, in the build configuration, you have three ways of defining the stop string: plaintext, SHA256-hashed string, and crypt-hashed password. For security purposes, you’ll want to use the last one, but the performance considerations may force you to use other options. Just try to avoid plaintext, as this will be readable in the U-Boot binary.

Longer passwords are usually harder to brute force, so we should have a password of preferably 20+ characters. However, having a long password should not mean that there is a 10-second delay in the U-Boot to allow someone to enter a 32-character password before the device autoboots. Fortunately, U-Boot has CONFIG_AUTOBOOT_NEVER_TIMEOUT to help with this. If the user presses the Enter key, the bootloader will patiently wait for the password before attempting to autoboot.

The following configuration enables the autoboot abort with key input, configures the expected input as a string, and then sets the input string to be a hashed password (if I remember right, the password is “test”, but do not use it on production, please):

enable_password_login.cfg
# Set short boot delay to have shorter boot times
CONFIG_BOOTDELAY=1
# Allow stopping autoboot with keypress / input string
CONFIG_AUTOBOOT_KEYED=y
# Enable stop string
CONFIG_AUTOBOOT_STOP_STR_ENABLE=y
# Enable password wait on Enter key
CONFIG_AUTOBOOT_NEVER_TIMEOUT=y
# Enable encryption on autoboot stop strings
CONFIG_AUTOBOOT_ENCRYPTION=y
# Enable crypt-hashed passwords
CONFIG_CRYPT_PW=y
# Enable SHA512 for the passwords
CONFIG_CRYPT_PW_SHA512=y
# The stop string 
CONFIG_AUTOBOOT_STOP_STR_CRYPT="$6$rounds=10000$CwfTYUwQyi4YrTSn$yYhVlaKRdSypHnsN3sm50CsceWoFiFvSPXie8vSf.Ml8l0ZsdgOw6lzvfkf0GWnI7jBBaLMz8q6GXd5kCoytK0"

You can generate a suitable password with the following command:

generate_password.sh
# SHA512 hashed password "test" with 10000 rounds
# Add rounds if necessary
mkpasswd -m sha-512 -R 10000 test

Additional Security Considerations for Stop Strings

All is good. Kind of. You see, U-Boot actually loads the expected stop string from an environment variable named bootstopkeycrypt by default. Now, if an adversary has control over the U-Boot environment (for example, with fw_setenv), it is possible to add a known password to the environment, and U-Boot will happily use it instead of the built-in password.

Therefore, you may want to consider disabling this functionality. Something like the patch below could do the trick. I’ve given it a few tests, and it seems to work, but I recommend that you test it thoroughly and check that it fits your use case:

Diff
From 20445e77661d58efc65b9571ca96af1fca33e392 Mon Sep 17 00:00:00 2001
From: ejaaskel <esa.jaaskela@suomi24.fi>
Date: Wed, 29 Oct 2025 10:51:19 +0000
Subject: [PATCH] Do not read stop string from bootstopkeycrypt

Do not read the stop string from bootstopkeycrypt environment variable.
This variable can be used to set the default stop string to use when
using the crypted stop strings. However, this poses a security risk on
systems where the boot environment can be modified, as it can be used to
set the stop string into a known value and bypass the stop string set
during the compilation.
---
 common/autoboot.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/common/autoboot.c b/common/autoboot.c
index 5d331991c19..12fb6381420 100644
--- a/common/autoboot.c
+++ b/common/autoboot.c
@@ -77,16 +77,13 @@ static int menukey;
  */
 static int passwd_abort_crypt(uint64_t etime)
 {
-	const char *crypt_env_str = env_get("bootstopkeycrypt");
+	const char *crypt_env_str = AUTOBOOT_STOP_STR_CRYPT;
 	char presskey[DELAY_STOP_STR_MAX_LENGTH];
 	u_int presskey_len = 0;
 	int abort = 0;
 	int never_timeout = 0;
 	int err;
 
-	if (IS_ENABLED(CONFIG_AUTOBOOT_STOP_STR_ENABLE) && !crypt_env_str)
-		crypt_env_str = AUTOBOOT_STOP_STR_CRYPT;
-
 	if (!crypt_env_str)
 		return 0;
 
-- 
2.34.1

Expand

Similar environment variable logic applies also to SHA256-hashed and plaintext stop strings, so you may want to modify those instead if you’re using them. Applying this patch means that you’ll have to update the whole bootloader if you need to change the password. It may sound inconvenient, but all things considered, it is safer than storing critical information like the autoboot stop string in an environment that may be modified.

It’s worth mentioning that U-Boot provides an option of falling back to SHA256 hash in case the bootstopusesha256 environment variable is set to 1. I recommend disabling this configuration, as it allows bypassing the crypt-hashed stop string. Once again, it results in a less flexible system, but hopefully increases the security.

Disabling the Command Line (and Console)

However, the easiest and most foolproof way to secure anything is to remove it. Therefore, if there’s no need for the U-Boot command line interface, we can remove it with the following configuration:

# CONFIG_CMDLINE is not set

Needless to say, after this, you cannot alter the boot process interactively and are at the mercy of the autoboot. Except if your autoboot process uses U-Boot environment extensively. Then you may still be able to control the bootloader, but using the U-Boot environment is discouraged for this exact reason, because the malicious entities may be able to alter it as well. In any case, the debugging and device maintenance become quite a pain if there’s no interface, so you should be quite certain about this action.

On the other hand, if you want to take this one step further, you can disable the console altogether. This prevents anything from going in or out of U-Boot. It is effective for locking out adversaries and developers. This can be achieved with the following configuration:

CONFIG_DISABLE_CONSOLE=y

After this, you can set GD_FLG_SILENT and GD_FLG_DISABLE_CONSOLE flags in arch_cpu_init or other early initialisation function:

gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;

gd is the U-Boot struct that contains global configuration. This tip comes from the Timesys blog.

Conclusion

This text should help you harden U-Boot by fixing the lowest-hanging fruit: unfettered access to the bootloader control interface. If you’re interested in seeing how this can be achieved in Yocto, you can check out the BSP meta-layer of my hardened Yocto distribution, Sulka. It has this stop string functionality and much more. That’s all for now, thanks for reading.

Recommended Reading

Share