Kernel encryption through Secureboot

I am trying to enable kernel/dtb signing and encryption on my TX2 NX, I have burned the SBK and PKC fuses with keys that I generated and then flashed a device with the same keys. To test to see if encryption was working I generated an unsigned, unencrypted version of my kernel and copied the Image file to /boot/Image without changing the Image.sig in /boot. After restarting the device the new kernel booted just fine, as I could tell from a print statement showing up in the dmesg output. Do any additional steps need to be taken to enable kernel encryption that I am missing?

hello jacob46,

it’s cboot to compare the size of the kernel image file to the size field from the signature file.

assume that unfused board is used, when kernel developers are developing kernel, the best practice is to delete Image.sig every time when your kernel Image has updated.
once the kernel development is complete, a valid Image.sig must be generated and placed under /boot/ folder.

This does not answer my question. I am using a fused board with the PKC and SBK fuses burned, I mentioned this in the first sentence of my original post.

If I understand correctly if I replace the /boot/Image file with a modified kernel that is not encrypted WITHOUT updating the Image.sig file, the bootloader should recognize that:

  1. The image file being read lacks the expected encryption, and
  2. The image file does not match the sign header
    Combined this means the kernel should not boot. However, it does boot with the modified kernel. This is a security risk for my project so I ask again: what am I missing here that is allowing this modified untrusted kernel to boot even with secure-boot and public key fuses burned.

Additionally I would like to confirm that the TX2 NX supports kernel encryption. Is this the case? The developer documentation states that only NX and Xavier products support kernel encryption but the 32.6 release notes explicitly state that this feature was added for TX2 products.

1 Like

When fuses are burned the “/boot” kernel and device trees are ignored even if specified in extlinux.conf. Only the partitions are then allowed, and those are the ones which are signed. Thus, you can only actually boot from partition content now. If the kernel in “/boot” works, and it isn’t just coincidentally the same kernel as in the partition, then something is wrong.

I have disk encryption and rootfs_ab enabled as well. According to disk encryption the kernel Image/dtb/initrd are all loaded from /boot/ on the unencrypted partition.

I have been picking through flash.sh and it seems like the boot files are never encrypted/signed when disk encryption is enabled for T18x. Im currently modifying it to see if I can get it to behave how I would like.

If you are ok with flashing again, or if you do flash again for some reason, I will suggest logging from command line to see what the flash actually uses. Example (use whatever command line you would normally use, but add the following):
sudo ...command... 2>&1 | tee log_flash.txt

This will preserve a list of exactly which file is sourced or copied to where, and which have a signature.

I can confidently say that the kernel gets loaded from the APP partition which contains only the /boot directory. In this case the kernel partition contains Uboot as I’m sure you are aware.

I’m kind of at an impasse however. If the kernel image gets properly encrypted (this required modifying flash.sh to enable) then uboot does not properly decrypt it. The docs state that kernel encryption is only available on Xavier NX and AGX devices but at the same time the release notes for L4T version 32.6.1 explicitly state that support for kernel encryption on the TX2 was added.

Secure boot is enhanced for Jetson TX2 series to extend encryption support to kernel, kernel-dtb and initrd.

Later releases of R32.x use only CBoot, and UBoot is no longer used. It is possible that the “/boot/extlinux/extlinux.conf” is accessed, but it is still questionable (until boot logs show which kernel is used) which kernel is actually loaded. If the “/boot” kernel is loaded when the fuses are burned, then there is likely a hardware issue, e.g., perhaps the fuse burn failed and it is really still using the non-fused version (I believe there are actually two fuse burn specifications which must both run at the same time for fuse burning to succeed, but I don’t have a unit to experiment on for fuse burning and have not done this myself).

Let’s say you copy the default extlinux.conf entry and make it some other label such that it still boots the original kernel and device tree as the original entry. However, if you change the name of the Image file to something like Image-backup, and similar for the tree, and adjust this non-default entry to point to the new names, then you have a backup. You would be free to remove the original “/boot/Image” and any reference in the default boot to that (or to the device tree). If it boots and it looks like the same kernel, then I question if the kernel in the partition is really different than the one in “/boot”. If something went wrong, then you could still use serial console to boot the backup entry.

If a fuse is not burned, and if there is no LINUX entry in extlinux.conf (or no FDT for device tree), then it pulls kernel and tree from a partition. Can you verify, with a backed up entry in case things go wrong, that the entry with no LINUX and no FDT entry still boots the same? Or differently? A serial console boot log would be quite helpful when booting both the entry with no LINUX or FDT value, plus again when booting the backup entry.

hello jacob46,

by default uboot doesn’t verify the images, it loads kernel image through file system even though it’s fused device.
since there’s UBoot feature called Verified Boot. you might have to execute tool to create a signed image, by add signatures to FIT (Flat Image Tree).
please refer to below for reference,
[U-Boot] Need help with verified u-boot on Tegra TX2
Verified boot on the Raspberry Pi – CrySyS Blog

so, the steps should be…

  1. download U-boot source code
  2. create a signed image.
  3. compile uboot with FIT image support.
  4. install the image for boot-up
  5. interrupt uboot auto boot sequence, use setenv for setting the initrd_high and fdt_high to specify the location where initrd and device tree loads into RAM,
  6. check the TX2 boot-up logs, which should have verification for hash values.
1 Like

I have resolved my issue and will document my solution below.

In order to get kernel encryption and rootfs/disk encryption to play nice together, it is required that cboot be used as the primary bootloader. Despite what you said @linuxdev Uboot is still the default primary bootloader for TX2 NX devices. To enable cboot as the primary bootloader you must either

  1. Set the USE_UBOOT environment var to 0, either in the board config file or before running flash.sh
  2. Use the -K option for flash.sh to specify the kernel image to flash to the kernel partition, this overrides the default use of UBoot which would normally be bundled into boot_sigheader.img and written to the kernel partition

Unlike UBoot, cboot will always read from the kernel partition as its source for the boot image. As I stated previously however, the disk encryption implementation provided by Nvidia loads the kernel from an unencrypted APP partition by reading the extlinux.conf file. Cboot for t186 devices does not have the ability to read this config file.

Because of this, without any modification from this point, cboot will load the kernel from partition, but will fail to load the initrd which contains the init script with the necessary commands to decrypt the rootfs partition. This can be fixed by setting the INITRD_IN_BOOTIMG environment variable to the string “yes.” I should highlight here that the variable must be set to the string “yes” and not to the int 1 as other configuration vars are (this tripped me up for quite a while). With this set, the proper initrd will be loaded by cboot and it can decrypt the APP_ENC partition.

From here, if the sbk, rsa, and user key have been properly supplied and the right fuses have been burned(secureboot is enabled), flash.sh will encrypt the boot.img file (which now contains the kernel Image and the initrd) and cboot will verify and decrypt the kernel, initrd, and dtb.

This leaves one issue. Enabling disk encryption means the generation of an unencrypted APP and APP_b partition which contain unencrypted copies of the kernel and initrd. I have yet to do anything about this but it should be simple enough to modify flash.sh and the partition config files to either remove these partitions, or by modifying flash.sh to encrypt these files, even though they go unused in this new disk/kernel encryption scheme.

With these changes I am able to have both my kernel and rootfs encrypted. What I see as the main issue here is that the developer documentation fails to mention any of the config flags I have used for this setup. It makes the assumption that either disk encryption OR kernel encryption will be enabled and makes no mention of how to get both to work together (since the default disk encryption setup requires UBoot and the default kernel encryption setup requires cboot). Additionally the documentation and release notes provide a confusing contradiction about if kernel encryption is supported on TX2 devices.

Please consider including additional information about how these features might be modified by developers to work together in future releases. Encryption is a common requirement many products and it seems useless to encrypt the rootfs without encrypting or signing the kernel, as other posts have pointed out in the past.

3 Likes

You are right, I was looking only at the Xavier and Orin.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.