blob: b86aafbd1b3df2c9c2cd0b58c33f9dcafc4ce1d6 [file] [log] [blame]
#!/bin/sh -u
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Usage: dev_debug_vboot [ --cleanup | DIRECTORY ]
#
# This extracts some useful debugging information about verified boot. A short
# summary is printed on stdout, more detailed information and working files are
# left in a log directory.
#
PATH=/bin:/sbin:/usr/bin:/usr/sbin
TMPDIR=$(mktemp -d /tmp/debug_vboot_XXXXXXXXX)
LOGFILE=noisy.log
# The public file must live directly in /tmp, not in a subdirectory.
# See http://crosbug.com/8947
PUBLOGFILE=/tmp/debug_vboot_noisy.log
# TODO(wfrichar): Need to support ARM. The hard disk path is likely different.
# We can use 'crossystem arch' to distinguish between x86 and ARM.
HD=/dev/sda
cleanup() {
if [ -z "${USE_EXISTING:-}" ]; then
# See http://crosbug.com/8947
cp --no-target-directory --remove-destination "${LOGFILE}" "${PUBLOGFILE}"
info "exporting log file as ${PUBLOGFILE}"
fi
if [ -n "${CLEANUP:-}" ]; then
cd /
rm -rf "${TMPDIR}"
fi
}
die() {
echo "$*" 1>&2
exit 1
}
info() {
echo "$@"
echo "#" "$@" >> "$LOGFILE"
}
infon() {
echo -n "$@"
echo "#" "$@" >> "$LOGFILE"
}
log() {
echo "+" "$@" >> "$LOGFILE"
"$@" >> "$LOGFILE" 2>&1
}
loghead() {
echo "+" "$@" "| head" >> "$LOGFILE"
"$@" | head >> "$LOGFILE" 2>&1
}
logdie() {
echo "+" "$@" >> "$LOGFILE"
die "$@"
}
result() {
if [ "$?" = "0" ]; then
info "OK"
else
info "FAILED"
fi
}
require_chromeos_bios() {
log cgpt show "${HD}"
log rootdev -s
log crossystem --all
log ls -aCF /root
log ls -aCF /mnt/stateful_partition
}
# Search for files from the FMAP, in the order listed. Return the first one
# found or die if none are there.
find_name() {
for fn in "$@"; do
if [ -e "$fn" ]; then
echo "$fn"
return
fi
done
echo "+ no files named $@" >> "$LOGFILE"
exit 1
}
# Here we go...
umask 022
trap cleanup EXIT
# Parse args
if [ -n "${1:-}" ]; then
if [ "$1" = "--cleanup" ]; then
CLEANUP=1
else
TMPDIR="$1"
[ -d ${TMPDIR} ] || die "${TMPDIR} doesn't exist"
USE_EXISTING=yes
fi
fi
[ -d ${TMPDIR} ] || mkdir -p ${TMPDIR} || exit 1
cd ${TMPDIR}
echo "$0 $*" > "$LOGFILE"
log date
echo "Saving verbose log as $(pwd)/$LOGFILE"
BIOS=bios.rom
# Find BIOS and kernel images
if [ -n "${USE_EXISTING:-}" ]; then
info "Using images in $(pwd)/"
else
require_chromeos_bios
info "Extracting BIOS image from flash..."
log flashrom -p internal:bus=spi --wp-status
log flashrom -p internal:bus=spi -r ${BIOS}
HD_KERN_A="${HD}2"
HD_KERN_B="${HD}4"
tmp=$(rootdev -s -d)2
if [ "$tmp" != "$HD_KERN_A" ]; then
USB_KERN_A="$tmp"
fi
info "Extracting kernel images from drives..."
log dd if=${HD_KERN_A} of=hd_kern_a.blob
log dd if=${HD_KERN_B} of=hd_kern_b.blob
if [ -n "${USB_KERN_A:-}" ]; then
log dd if=${USB_KERN_A} of=usb_kern_a.blob
fi
fi
# Make sure we have something to work on
[ -f "$BIOS" ] || logdie "no BIOS image found"
ls *kern*.blob >/dev/null 2>&1 || logdie "no kernel images found"
info "Extracting BIOS components..."
log dump_fmap -x ${BIOS} || logdie "Unable to extract BIOS components"
# Find the FMAP regions we're interested in. Look first for the new names, then
# the old names.
area_gbb=$(find_name GBB GBB_Area) || \
logdie "no area_gbb"
area_vblock_a=$(find_name VBLOCK_A Firmware_A_Key) || \
logdie "no area_vblock_a"
area_vblock_b=$(find_name VBLOCK_B Firmware_B_Key) || \
logdie "no area_vblock_b"
area_fw_main_a=$(find_name FW_MAIN_A Firmware_A_Data) || \
logdie "no area_fw_main_a"
area_fw_main_b=$(find_name FW_MAIN_B Firmware_B_Data) || \
logdie "no area_fw_main_a"
info "Pulling root and recovery keys from GBB..."
log gbb_utility -g --rootkey rootkey.vbpubk --recoverykey recoverykey.vbpubk \
"$area_gbb" || logdie "Unable to extract keys from GBB"
log vbutil_key --unpack rootkey.vbpubk
log vbutil_key --unpack recoverykey.vbpubk
infon "Verify firmware A with root key... "
log vbutil_firmware --verify "$area_vblock_a" --signpubkey rootkey.vbpubk \
--fv "$area_fw_main_a" --kernelkey kernel_subkey_a.vbpubk ; result
infon "Verify firmware B with root key... "
log vbutil_firmware --verify "$area_vblock_b" --signpubkey rootkey.vbpubk \
--fv "$area_fw_main_b" --kernelkey kernel_subkey_b.vbpubk ; result
for key in kernel_subkey_a.vbpubk kernel_subkey_b.vbpubk; do
infon "Test $key... "
log vbutil_key --unpack $key ; result
done
for keyblock in *kern*.blob; do
infon "Test $keyblock... "
log vbutil_keyblock --unpack $keyblock ; result
loghead od -Ax -tx1 $keyblock
done
# Test each kernel with each key
for key in kernel_subkey_a.vbpubk kernel_subkey_b.vbpubk recoverykey.vbpubk; do
for kern in *kern*.blob; do
infon "Verify $kern with $key... "
log vbutil_kernel --verify $kern --signpubkey $key ; result
done
done