#!/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="${TMPDIR}/noisy.log" PUBLOGFILE="/var/log/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 cp -f "${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} || exit 1 echo "$0 $*" > "$LOGFILE" log date echo "Saving verbose log as $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