| #!/bin/sh |
| # Copyright (c) 2010 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. |
| # |
| |
| TMPDIR=/tmp/debug_vboot |
| LOGFILE=noisy.log |
| |
| # TODO(wfrichar): Need to support ARM. The hard disk path is likely different. |
| HD=/dev/sda |
| ACPI=/sys/devices/platform/chromeos_acpi |
| |
| cleanup() { |
| if [ -n "${CLEANUP}" ]; then |
| find "${TMPDIR}" -type f -not -name "${LOGFILE}" -exec rm {} ";" |
| 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 |
| if [ ! -e "${ACPI}/HWID" ]; then |
| info "Not running Chrome OS BIOS, no further information available" |
| exit 0 |
| fi |
| # including /dev/null just to get final "\n" |
| log head "${ACPI}"/*ID "${ACPI}"/BINF* "${ACPI}"/CHSW /dev/null |
| log reboot_mode |
| log ls -la /mnt/stateful_partition/.need_firmware_update |
| log ls -la /root/.force_update_firmware |
| } |
| |
| # 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 |