Cannot write protect eMMC user partition

The boot partition can be protected

sudo ./mmc writeprotect boot get /dev/mmcblk0
Boot write protection status registers [BOOT_WP_STATUS]: 0x05
Boot Area Write protection [BOOT_WP]: 0x01
 Power ro locking: possible
 Permanent ro locking: possible
 ro lock status: locked until next power on
sudo ./mmc writeprotect user get /dev/mmcblk0

Generates no output and returns exit code 1.

sudo ./mmc writeprotect user set pwron 0 14000 /dev/mmcblk0
Operation not supported for this device

hello richardsearle,

may I know what’s your use-case of write protect. you may enable security features for setting up a secure environment.
for example,
please refer to security documentation, Trusty, a Trusted Execution Environment.
thanks

My goal is to ensure the Jetson does not retain any state between power cycles.

I already have a read-only root filesystem, where all changes are only made in a ramdisk.
The read-only filesystem is only enforced by software and can be bypassed by root.

The eMMC read-only flag cannot be bypassed by the software.

I am aware of Trusty and the Secure Boot support; but do not see how those enforce the lack of state requirement.

richardsearle,
When you said between power cycle, there are cold boot, warm boot and entering/waking up power save mode. If there is an issue that prior Jetson state impacts subsequent operating mode then that’s a bug we should address. is this your preventive approach or an issue was observed? Not to retain any state means a totally fresh start of the system?

During a device operation, there could be update on emmc content depending on the application. If you write protect, then some required update might fail. Is there an example of your concern of state retaining between power cycle? Thanks

We will flash the Jetson with the operating system and our specific application code.
The application is stateless, with no data being retained between restarts.

The Jetson is shipped to the customer and installed in their network.
A central server provides the Jetson with the customer specific data after it has booted and is connected to a network.

When maintenance is required (due to hardware failure or software updates), the Jetson will be shipped back to us. We will then reflash the Jetson.

The goal is provide a guarantee to the customer that none of their proprietary data will be retained by the Jetson.

The read-only filesystem places all the changes made while the system is running into RAM.
The contents of that RAM are discarded when system reboots or is powered down.
That satisfies the requirement, assuming all is well.

Unfortunately, root can still write to the eMMC and we would like to eliminate that potential vulnerability.
Making the eMMC read only (until the next boot) eliminates this vulnerability.

This discussion thus has nothing to do with the boot process.
It is only concerned about the root filesystem.

If EMMC is mounted as root partition in kernel command line root= , it has to be read write for journaling.
If you are OK with passing initrd or ramfs, then you dont need to pass root and mount emmc as external drive.
We can mark emmc as read only in kernel DT in that case.

I could use ext2 and so avoid filesystem journaling.
The rootfs will not be changing so journal is not needed.

initrd is already required to implement the overlayfs.

I could not find how to mark emmc as read only in the kernel DT.
Checked mmc.txt, sdhci-tegra.txt, tegra186-soc-sdhci.dtsi

mmc-dev-parts.txt indicates a read-only flag but this part of DT does not appear in the Jetson kernel DTS.

Could you provide a pointer to the relevant dtsi/documentation?

Found the following in flash.sh

cmdline+="root=/dev/${target_rootdev} rw rootwait rootfstype=ext4 "

Implies I can change that to ro and ext2

A suggestion which might make testing easier…if you have serial console, then you can interrupt boot and pick different entries in extlinux.conf. During boot, with serial console, you can interrupt either at the U-Boot command line (too early for what you want), or at the selection of which command line/kernel to boot (this latter is what you’d want if you’ve added a second entry and that entry contains your command line edits). Then you just do a quick extlinux.conf edit and try the second entry without changing the default entry…if it fails, just don’t use the second entry.

An example boot on serial console will show something like this as U-Boot is reached (delay times where you can interrupt with a keystroke are short…and if you interrupt too early just type “boot” and continue and then interrupt during kernel select stage…any key will interrupt, and you want to interrupt when it gets to the “1: primary kernel” part):

U-Boot 2016.07-g0eb73f4 (Mar 13 2019 - 00:20:34 -0700)

TEGRA186
Model: NVIDIA P2771-0000-500
DRAM:  7.8 GiB
MC:   Tegra SD/MMC: 0, Tegra SD/MMC: 1
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   eth0: ethernet@2490000
Hit any key to stop autoboot:  0 
Tegra186 (P2771-0000-500) # boot
MMC: no card present
switch to partitions #0, OK
mmc0(part 0) is current device
Scanning mmc 0:1...
Found /boot/extlinux/extlinux.conf
Retrieving file: /boot/extlinux/extlinux.conf
213 bytes read in 114 ms (1000 Bytes/s)
p2771-0000 eMMC boot options
1:	primary kernel
Enter choice:

If you look at “/boot/extlinux/extlinux.conf”, then you will see a block like this:

LABEL primary                                                
      MENU LABEL primary kernel                              
      LINUX /boot/Image
      APPEND ${cbootargs} root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4

Most of this file’s APPEND is no longer available for edit since earlier stages use a device tree and edit content, but the part of this file you see above is still available for customization directly in extlinux.conf. You can change this without flashing.

So as an example, you could duplicate this entry and edit, followed by using serial console to try it out. That single entry would instead become something like this:

LABEL primary                                                
      MENU LABEL primary kernel                              
      LINUX /boot/Image
      APPEND ${cbootargs} root=/dev/mmcblk0p1 <b>rw</b> rootwait rootfstype=ext4

LABEL <b>test_read_only</b>                                                
      MENU LABEL <b>test read only</b>
      LINUX /boot/Image
      APPEND ${cbootargs} root=/dev/mmcblk0p1 <b>ro</b> rootwait rootfstype=ext4

The earlier boot text I showed from an example serial console would then change to this:

Retrieving file: /boot/extlinux/extlinux.conf
213 bytes read in 114 ms (1000 Bytes/s)
p2771-0000 eMMC boot options
1:	primary kernel
<i><b>2:      test read only</b></i>
Enter choice:

Entering nothing would use the default entry “1”. Entering “2” would boot the alternate APPEND in the second entry. You can add several entries.

Serial console setting is 115200 8N1 with a 3.3V TTL logic level:
http://www.jetsonhacks.com/2017/03/24/serial-console-nvidia-jetson-tx2/

Hi,

You can update the file /etc/fstab by changing default to RO and the filesystem will be readonly
Once changed root also will not be able to update it

/dev/root / ext4 ro

I had previously tried

APPEND ${cbootargs} root=/dev/mmcblk0p1 ro rootwait rootfstype=ext4

But found that the ro was ignored.

R32.x.y no longer has those references.

It appears possible to modify the block driver to force readonly https://github.com/msuhanov/Linux-write-blocker/blob/master/kernel/linux-4.10-enforce-ro.patch

NOTE: What @bbasu mentioned is that even if the kernel receives a “ro”, then later on in init when “/etc/fstab” is read, the options there can cause a remount read-write. In that file you will see an “options” parameter, and the rootfs shows as “defaults” there. The man page for fstab says:

<b>defaults</b>
        use default options: rw, suid, dev, exec, auto, nouser, and async.

So if you were to replace the token “defaults” with this there would essentially be no change at all (comma delimited with no spaces):

<b>rw</b>,suid,dev,exec,auto,nouser,async

So I will suggest to keep the “ro” in the kernel command line, and then to change “defaults” in “/etc/fstab” to be the same thing as above, but “ro” instead of “rw”:

<b>ro</b>,suid,dev,exec,auto,nouser,async

Also, if still failing, then after boot, verify if “cat /proc/cmdline” shows “ro”.

Setting ro in /etc/fstab is honored by kernel.

BUT
root can simply remount the filesystem as rw

The goal with the eMMC write protection was to provide a hardware level enforcement that root cannot bypass

You can make the filesystem RO by making the below change to flash.sh file

— a/flash.sh
+++ b/flash.sh
@@ -526,6 +526,7 @@ build_fsimg ()
sync; sync; sleep 5; # Give FileBrowser time to terminate gracefully.
echo “done.”;
umount “${loop_dev}” > /dev/null 2>&1;

  •   tune2fs -O read-only "${loop_dev}"
      losetup -d "${loop_dev}" > /dev/null 2>&1;
      rmdir mnt > /dev/null 2>&1;