blob: 800f40f92a000a45cf4da7308e9495935c57ca11 [file] [log] [blame]
#!/bin/bash
# Copyright 2024 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Disable the ssh variable expansion lint, since it is exactly what we want to
# do to expand variables at the client.
# shellcheck disable=SC2029
set -eEu
HELP="Usage: $0 DUT
Enables the rootfs verification on DUT. This script calculates the hash of
the rootfs and enables the verity of the rootfs.
"
if [[ $# -ne 1 || "$1" == -h || "$1" == --help ]]; then
echo "${HELP}"
exit 1
fi
DUT="$1"
main() {
local rootdev partition rootdev_s
echo "Before:"
rootdev="$(ssh "${DUT}" rootdev)"
partition="$(( $(echo -n "${rootdev}" | grep -o "[0-9]$") - 1 ))"
echo "rootdev: ${rootdev}"
rootdev_s="$(ssh "${DUT}" rootdev -s)"
echo "rootdev -s: ${rootdev_s}"
echo "partition: ${partition}"
if [[ "${rootdev}" =~ dm-0 ]]; then
echo "Rootfs verification is already turned on"
exit 1
fi
# FIXME:
# In theory "sync"s should suffice instead of a reboot, but we often
# observe disk change after reboot for some reason.
echo "Reboot before remounting"
reboot_and_wait "${DUT}"
echo "Remounting rootfs as RO"
ssh "${DUT}" "/usr/share/vboot/bin/make_dev_ssd.sh --save_config /tmp/config --partitions ${partition}"
ssh "${DUT}" "sed 's| rw | ro |g' -i /tmp/config.${partition}"
ssh "${DUT}" "/usr/share/vboot/bin/make_dev_ssd.sh --set_config /tmp/config --partitions ${partition}"
reboot_and_wait "${DUT}"
local root_fs_blocks root_fs_block_sz root_fs_size root_fs_blocks salt alg table
echo "Running verity"
root_fs_blocks=$(ssh "${DUT}" "dumpe2fs ${rootdev} 2>/dev/null" | grep "Block count" | tr -d ' ' | cut -f2 -d:)
echo "root_fs_blocks: ${root_fs_blocks}"
root_fs_block_sz=$(ssh "${DUT}" "dumpe2fs ${rootdev} 2>/dev/null" | grep "Block size" | tr -d ' ' | cut -f2 -d:)
echo "root_fs_block_sz: ${root_fs_block_sz}"
root_fs_size=$(( root_fs_blocks * root_fs_block_sz ))
echo "root_fs_size: ${root_fs_size}"
root_fs_blocks=$(( root_fs_size / 4096 ))
echo "root_fs_blocks: ${root_fs_blocks}"
salt=$(ssh "${DUT}" "cat /proc/cmdline" | sed 's/.*salt=\([^ \t"]\+\).*/\1/g')
echo "salt: ${salt}"
alg=$(ssh "${DUT}" "cat /proc/cmdline" | sed 's/.*alg=\([^ \t"]\+\).*/\1/g')
echo "alg: ${alg}"
table=$(ssh "${DUT}" "verity --mode=create --alg=${alg} --payload=${rootdev} --payload_blocks=${root_fs_blocks} --hashtree=/tmp/rootfs.hash --salt=${salt}")
echo "Table:"
echo "${table}"
echo
local rootdev_disk hash_offset
echo "Writing hash data to disk"
rootdev_disk=$(ssh "${DUT}" rootdev -d)
hash_offset=$(ssh "${DUT}" "cgpt show -i $(( partition + 1 )) -b ${rootdev_disk}")
hash_offset=$(( hash_offset + (root_fs_size / 512) ))
ssh "${DUT}" "dd bs=512 seek=${hash_offset} if=/tmp/rootfs.hash of=${rootdev_disk} conv=notrunc status=none"
echo
local root_hexdigest_string
echo "Modifying command line"
ssh "${DUT}" "/usr/share/vboot/bin/make_dev_ssd.sh --save_config /tmp/config --partitions ${partition}"
ssh "${DUT}" "sed 's|root=PARTUUID=%U/PARTNROFF=1|root=/dev/dm-0|g' -i /tmp/config.${partition}"
ssh "${DUT}" "sed 's|dm_verity.dev_wait=0|dm_verity.dev_wait=1|g' -i /tmp/config.${partition}"
ssh "${DUT}" "sed 's|payload=ROOT_DEV|payload=PARTUUID=%U/PARTNROFF=1|g' -i /tmp/config.${partition}"
ssh "${DUT}" "sed 's|hashtree=HASH_DEV|hashtree=PARTUUID=%U/PARTNROFF=1|g' -i /tmp/config.${partition}"
# shellcheck disable=SC2001
root_hexdigest_string=$(echo "${table}" | sed 's/.*\(root_hexdigest=\S\+\).*/\1/g')
ssh "${DUT}" "sed 's/root_hexdigest=\S\+/${root_hexdigest_string}/g' -i /tmp/config.${partition}"
ssh "${DUT}" "/usr/share/vboot/bin/make_dev_ssd.sh --set_config /tmp/config --partitions ${partition}"
ssh "${DUT}" "cat /tmp/config.${partition}"
echo
reboot_and_wait "${DUT}"
echo
local new_rootdev new_rootdev_s
echo "After:"
new_rootdev=$(ssh "${DUT}" rootdev)
echo "rootdev: ${new_rootdev}"
new_rootdev_s=$(ssh "${DUT}" rootdev -s)
echo "rootdev -s: ${new_rootdev_s}"
if [[ "${new_rootdev}" != /dev/dm-0 ]]; then
echo "The new root dev is not /dev/dm-0. Enabling rootfs verification failed."
exit 1
fi
if [[ "${new_rootdev_s}" != "${rootdev_s}" ]]; then
echo "The new and the old root dev partition don't match. Enabling rootfs verification failed."
exit 1
fi
}
reboot_and_wait() {
echo "Rebooting..."
timeout 10s ssh "$1" reboot || true
echo "Waiting for a ssh connection"
sleep 10
while ! timeout 10s ssh "$1" echo test &> /dev/null; do sleep 5; done
echo
}
main