Disabling console output with secure boot and closed device

Hello,

we are using Torizon OS with secure boot, including RootFS protection and encrypted partition (all done using Yocto build with tdx-signed). All is working fine, including Torizon Offline updates. We also managed to close the device by burning fuses. As the last step in security hardening process, we would like to disable the console output.
To disable the console, we called the following:

fw_setenv tdxargs ‘console=null’
fw_setenv silent yes

However, after the reboot, the hardened u-boot refuses to boot with the following error message. Apparently, setting console=null causes problems with the build-in expected boot args.
I have the following questions:

  • What are the steps which we need to do in order to disable console in a safe way?
  • Is there any way how to recover the unit which refuse to boot with the state below?

Unexpected argument in variable bootargs: console=null…
WARNING: Validation of the variable part of bootargs failed; the full bootargs string (A) and its fixed part (as defined in the ‘required-bootargs’ property inside the device-tree) follow:
A: “root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 systemd.gpt_auto=0 ostree=/ostree/boot.0/torizon/acaf846b6077ed72eb4bb28cc6544b785604bbef8f078efe6a767c87d60cb640/0 console=null”
B: “root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 systemd.gpt_auto=0”
FATAL: Stopping boot process due to bootargs validation error.
ERROR: /chosen node create failed

  • must RESET the board to recover.

FDT creation failed!
resetting …

Result of tdx-info:

Software summary

Bootloader: U-Boot
Kernel version: 6.6.94-7.3.0-devel-g5a62539de8f9 #1-Torizon SMP PREEMP T Wed Jun 25 09:14:55 UTC 2025
Kernel command line: root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo v t.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 sys temd.gpt_auto=0 ostree=/ostree/boot.1/torizon/a5b366d3447e11eeb9be00c8296ef085c4 bf9684d53c6fa4c270bdc342e1c785/0 cfs.enabled=false
Distro name: NAME=“Torizon OS”
Distro version: VERSION_ID=7.3.0-devel-20251021142752-build.0
Distro variant: VARIANT=“Docker”
Hostname: verdin-imx8mp-15380432

Hardware info

HW model: XXX board second dev. version
Toradex version: 0058 V1.1B
Serial number: 15380432
Processor arch: aarch64

Thank you in advance for any help.
Best regards,
Ivo

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


Hello Ivo,

Your issue is related to the Kernel command-line protection feature in Toradex’s hardened U-Boot implementation. Let me explain what’s happening and provide solutions.

Understanding the Problem

The error you’re encountering is caused by the kernel command-line protection feature implemented in Toradex’s secure boot hardening(1). This protection prevents changes to the bootargs variable and validates that kernel arguments match the expected fixed part defined in the device tree(1).

When you set console=null, the hardened U-Boot detects this as an unexpected argument that’s not part of the required bootargs, causing the validation to fail(1).

Safe Console Disabling Solutions

Option 1: Build-Time Configuration (Recommended)

The safest approach is to configure console disabling at build time by modifying the TDX_SECBOOT_REQUIRED_BOOTARGS variable in your Yocto build(1). This ensures the console parameter is part of the expected bootargs.

In your Yocto local.conf, add or modify:

TDX_SECBOOT_REQUIRED_BOOTARGS = "root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 systemd.gpt_auto=0 console=null"

(1)

Then rebuild your image with the tdx-signed class(2).

Option 2: Device Tree Modification

Alternatively, you can modify the required-bootargs property in the device tree during your Yocto build to include the console parameter you want to use(1).

Recovery Options

For Open Devices

If your device is still in the open state (HAB/AHAB not closed), you can:

  1. Access the U-Boot console via serial connection
  2. Reset the environment variables:
    env default -a
    saveenv
    
  3. Reboot the device

For Closed Devices

Recovery for closed devices is more challenging. You may need to:

  1. Use the recovery mode if available on your hardware platform
  2. Flash a new image that includes the correct bootargs configuration
  3. Ensure any new image is properly signed with your secure boot keys

Prevention for Future Updates

When using secure boot with kernel command-line protection, always ensure that:

  • Any bootargs modifications are included in the TDX_SECBOOT_REQUIRED_BOOTARGS configuration(1)
  • The device tree’s required-bootargs property matches your intended kernel parameters(1)
  • Test changes on an open device before closing with fuses

Important Notes

The bootargs validation feature is designed to prevent tampering with kernel parameters even if an attacker gains access to modify U-Boot environment variables(1). This is why direct modification via fw_setenv fails on a hardened system.

For production deployments, the build-time approach ensures that your console configuration is part of the verified chain of trust and won’t cause boot failures.

Best regards,
Toradex AI Assistant.


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Greetings @ivo.herman,

First of all, what you observed here is documented in detail here: Security Hardening of U-Boot | Toradex Developer Center

This intention is to prevent possibly malicious manipulation of the kernel arguments on a secured device. As this could be a potential vector for attack.

What are the steps which we need to do in order to disable console in a safe way?

If you want to do this safely you have to follow the documentation and add any additional fixed kernel arguments to TDX_SECBOOT_REQUIRED_BOOTARGS in your Yocto build. This will add the kernel argument to the list of “expected” boot args.

Is there any way how to recover the unit which refuse to boot with the state below?

You should just be able to reflash the device. Unless when you burned the fuses did you already burn the final fuse that closes the device?

If so the device may not be easily recoverable anymore. It’s not advisable to close the device and then continue to make changes to the device’s security configuration after it has been closed. It makes it very easy to make mistakes like this that essentially lock the device.

Also are you unable to access the U-Boot terminal to undo the modified bootargs? Or was this locked down too?

Best Regards,
Jeremias

Dear Jeremias,
thank you for a quick reply and for pointing us to the documentation. We tried to follow the approach. However, in our case it did not work as expected.

  1. When setting the parameter
TDX_SECBOOT_REQUIRED_BOOTARGS = "root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 systemd.gpt_auto=0 console=null

nothing changes in the output build. When we looked at what is really used in the file add-secboot-kargs-overlay.inc, the content of the variable is unchanged. As a result, the kernel arguments are not modified. We checked also with a clean build without any other layer than default, and the result was the same - no change in bootags.
2. When we for test purposes edited the file add-secboot-kargs-overlay.inc, we managed to modify the expected parameters. Then, in u-boot, when we tried to disable console by setting setenv tdxargs console='null', we got the following error:

WARNING: Initial part of passed bootargs string (A) does not match 'required-bootargs' property (B) in device-tree.
A: "root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 systemd.gpt_auto=0 ostree=/ostree/boot.1/torizon/35983cf89308b7dd82b9ed29db119cb6b8426860f54d17b4d26cb125a88531d7/0 console=null"
B: "root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 systemd.gpt_auto=0 console=null"

The ostree parameters got before tdxargs, so the check did not pass. This we can overcome by changing the order in u-boot-distro-boot-harden.inc - the tdxargs were moved before other parameters. After that, the system booted without errors.

Even though we managed to overcome the problems, our solution does not seem nice enough. Is there any better way?

Thank you for the feedback, looking at the spots in the code you specified I can see what you are talking about here. Let me forward this feedback to our security team as there may be something here to improve on our side. At least for the time-being you were able to overcome the problem as you said.

When setting the parameter

Regarding this point I think I know what happened. Looking at the file here: meta-toradex-security/classes/include/signed/tdx-signed-harden.inc at scarthgap-7.x.y · toradex/meta-toradex-security · GitHub

There is a variable TDX_SECBOOT_REQUIRED_BOOTARGS but as seen in the file we override the value of this depending on the machine being built. I think what happened is that since you only set the generic TDX_SECBOOT_REQUIRED_BOOTARGS this got overridden by the values in this file. Which would explain why it seems like the bootargs did not change for you.

Another point of feedback I will provide to the team.

Best Regards,
Jeremias

Just to give feedback, I discussed your points with our security team.

They recommended the following. If you want to set any additional fixed bootargs in a secure way you should set the following variable in Yocto TOS_SECBOOT_REQUIRED_BOOTARGS. For example, in your case with console=null you want to set the following:

TOS_SECBOOT_REQUIRED_BOOTARGS = "${TOS_SECBOOT_REQUIRED_BOOTARGS_COMMON} console=null"

This appends your additional bootarg unto the list of default bootargs. One thing to keep in mind, these variables are only defined if building an image based on Torizon OS in yocto. If you’re using a non-Torizon OS image as the base these variables will not be defined.

In that case you can also set TDX_SECBOOT_REQUIRED_BOOTARGS:<machine-name>, as I suggested prior. This should work regardless of the base image.

The team advised not using tdxargs to apply additional bootargs. This is not how it’s intended to be used at the moment.

Best Regards,
Jeremias

Dear Jeremias,
thank you for your response. I can confirm that setting TOS_SECBOOT_REQUIRED_BOOTARGS as suggested works and that it modifies the expected kernel boot arguments.
I want to have the ability to switch the console on and off before closing the unit. So, I want to set some of the parameters of u-boot, that becomes part of the kernel arguments. To have the fixed part boot arguments really fixed, I need to use parameter, that is in the kernel arguments before the ostree commit hash. Therefore, I chose defargs, so I set:

setenv defargs 'console=ttynull'

This settings allows to boot without problems, even when I use silent parameter of the u-boot to disable console also in u-boot. Thanks to defargs, I managed to have a closed unit with console off both in kernel and in u-boot.

Is using defargs a good idea? If not, how can I disable the console by u-boot parameter?

Is using defargs a good idea? If not, how can I disable the console by u-boot parameter?

Typically defargs is for storing hardware/module specific kernel arguments. In this case it happens to work out, though it’s not something we intentionally planned for to be honest.

Question though, for your final production image are you just going to always have console=ttynull?

In which case it’d be fine to use TOS_SECBOOT_REQUIRED_BOOTARGS, correct?

Or are you going to have some devices deployed with and without the console? In which case you would need this optional setting of console=ttynull.

Best Regards,
Jeremias