2
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3
# Use of this source code is governed by a BSD-style license that can be
4
# found in the LICENSE file.
6
# Usage: dev_debug_vboot [ --cleanup | DIRECTORY ]
8
# This extracts some useful debugging information about verified boot. A short
9
# summary is printed on stdout, more detailed information and working files are
10
# left in a log directory.
12
##############################################################################
14
# Clean up PATH for root use. Note that we're assuming [ is always built-in.
15
[ "${EUID:-0}" = 0 ] && PATH=/bin:/sbin:/usr/bin:/usr/sbin
17
PUBLOGFILE="/var/log/debug_vboot_noisy.log"
25
FLAG_SAVE_LOG_FILE=yes
30
##############################################################################
38
Usage: $prog [options] [DIRECTORY]
40
This logs as much as it can about the verified boot process. With no arguments
41
it will attempt to read the current BIOS, extract the firmware keys, and use
42
those keys to validate all the ChromeOS kernel partitions it can find. A
43
summary output is printed on stdout, and the detailed log is copied to
44
$PUBLOGFILE afterwards.
46
If a directory is given, it will attempt to use the components from that
47
directory and will leave the detailed log in that directory.
51
-b FILE, --bios FILE Specify the BIOS image to use
52
-i FILE, --image FILE Specify the disk image to use
53
-k FILE, --kernel FILE Specify the kernel partition image to use
54
-v Spew the detailed log to stdout
56
-c, --cleanup Delete the DIRECTORY when done
58
-h, --help Print this help message and exit
65
if [ -n "${FLAG_SAVE_LOG_FILE}" ]; then
66
if cp -f "${LOGFILE}" "${PUBLOGFILE}" 2>/dev/null; then
67
info "Exporting log file as ${PUBLOGFILE}"
70
if [ -n "${OPT_CLEANUP}" ] && [ -d "${TMPDIR}" ] ; then
83
echo "#" "$@" >> "$LOGFILE"
88
echo "#" "$@" >> "$LOGFILE"
92
echo "#" "$@" >> "$LOGFILE"
96
echo "+" "$@" >> "$LOGFILE"
97
"$@" >> "$LOGFILE" 2>&1
101
echo "+" "$@" "| head" >> "$LOGFILE"
102
"$@" | head >> "$LOGFILE" 2>&1
106
echo "+ERROR:" "$@" >> "$LOGFILE"
112
if [ "${LAST_RESULT}" = "0" ]; then
124
if ! type "$tool" >/dev/null 2>&1 ; then
125
missing="$missing $tool"
128
if [ -n "$missing" ]; then
129
logdie "can't find these programs: $missing"
133
extract_kerns_from_file() {
139
debug "Extracting kernel partitions from $1 ..."
140
cgpt find -v -t kernel "$1" | grep 'Label:' |
141
while read start size part rest; do
143
log dd if="$1" bs=512 skip=${start} count=${size} of="${name}" &&
148
format_as_tpm_version() {
155
a='/(Data|Kernel) key version/ {print $1,$4}'
156
b='/Kernel version/ {print $1, $3}'
157
awk "$a $b" "$1" | while read what num rest; do
158
[ "${what}" = "Data" ] && block="${num}"
159
[ "${what}" = "Kernel" ] && printf '0x%04x%04x' "${block}" "${num}"
164
# Convert any old-style names to new-style
165
[ -f GBB_Area ] && log mv -f GBB_Area GBB
166
[ -f Firmware_A_Key ] && log mv -f Firmware_A_Key VBLOCK_A
167
[ -f Firmware_B_Key ] && log mv -f Firmware_B_Key VBLOCK_B
168
[ -f Firmware_A_Data ] && log mv -f Firmware_A_Data FW_MAIN_A
169
[ -f Firmware_B_Data ] && log mv -f Firmware_B_Data FW_MAIN_B
174
##############################################################################
179
# Pre-parse args to replace actual args with a sanitized version.
180
TEMP=$(getopt -o hvb:i:k:c --long help,bios:,image:,kernel:,cleanup \
188
OPT_BIOS=$(readlink -f "$2")
193
OPT_IMAGE=$(readlink -f "$2")
198
OPT_KERNEL=$(readlink -f "$2")
220
die "Internal error in option parsing"
224
if [ -z "${1:-}" ]; then
225
TMPDIR=$(mktemp -d /tmp/debug_vboot_XXXXXXXXX)
228
[ -d ${TMPDIR} ] || die "$TMPDIR doesn't exist"
231
[ -z "${OPT_VERBOSE}" ] && LOGFILE="${TMPDIR}/noisy.log"
233
[ -d ${TMPDIR} ] || mkdir -p ${TMPDIR} || exit 1
234
cd ${TMPDIR} || exit 1
235
echo "Running $0 $*" > "$LOGFILE"
237
debug "OPT_CLEANUP=($OPT_CLEANUP)"
238
debug "OPT_BIOS=($OPT_BIOS)"
239
debug "OPT_IMAGE=($OPT_IMAGE)"
240
debug "OPT_KERNEL=($OPT_KERNEL)"
241
debug "FLAG_SAVE_LOG_FILE=($FLAG_SAVE_LOG_FILE)"
242
echo "Saving verbose log as $LOGFILE"
246
# Make sure we have the programs we need
247
need="vbutil_key vbutil_keyblock vbutil_kernel vbutil_firmware"
248
[ -z "${OPT_BIOS}" ] && need="$need flashrom"
249
[ -z "${OPT_KERNEL}" ] && need="$need cgpt"
253
# Assuming we're on a ChromeOS device, see what we know.
258
log ls -aCF /mnt/stateful_partition
259
devs=$(awk '/(mmcblk[0-9])$|(sd[a-z])$/ {print "/dev/"$4}' /proc/partitions)
263
log flashrom -V -p internal:bus=spi --wp-status
264
tpm_fwver=$(crossystem tpm_fwver) || tpm_fwver="UNKNOWN"
265
tpm_kernver=$(crossystem tpm_kernver) || tpm_kernver="UNKNOWN"
269
info "Extracting BIOS components..."
270
if [ -n "${OPT_BIOS}" ]; then
271
# If we've already got a file, just extract everything.
272
log dump_fmap -x "${OPT_BIOS}"
275
# Read it from the flash
276
if log flashrom -p internal:bus=spi -r bios.rom ; then
277
# If we can read the whole BIOS at once, great.
278
log dump_fmap -x bios.rom
281
# Otherwise pull just the components we want (implying new-style names)
282
info " ...individually..."
283
log flashrom -p internal:bus=spi -r /dev/null \
285
-i"VBLOCK_A":VBLOCK_A \
286
-i"VBLOCK_B":VBLOCK_B \
287
-i"FW_MAIN_A":FW_MAIN_A \
288
-i"FW_MAIN_B":FW_MAIN_B
292
info "Pulling root and recovery keys from GBB..."
293
log gbb_utility -g --rootkey rootkey.vbpubk --recoverykey recoverykey.vbpubk \
294
"GBB" || logdie "Unable to extract keys from GBB"
295
log vbutil_key --unpack rootkey.vbpubk
296
log vbutil_key --unpack recoverykey.vbpubk
297
vbutil_key --unpack rootkey.vbpubk |
298
grep -q b11d74edd286c144e1135b49e7f0bc20cf041f10 &&
299
info " Looks like dev-keys"
300
# Okay if one of the firmware verifications fails
303
infon "Verify firmware ${fw} with root key: "
304
log vbutil_firmware --verify "VBLOCK_${fw}" --signpubkey rootkey.vbpubk \
305
--fv "FW_MAIN_${fw}" --kernelkey "kern_subkey_${fw}.vbpubk" ; result
306
if [ "${LAST_RESULT}" = "0" ]; then
307
# rerun to get version numbers
308
vbutil_firmware --verify "VBLOCK_${fw}" --signpubkey rootkey.vbpubk \
309
--fv "FW_MAIN_${fw}" > tmp.txt
310
ver=$(format_as_tpm_version tmp.txt)
311
info " TPM=${tpm_fwver}, this=${ver}"
316
info "Examining kernels..."
317
if [ -n "${OPT_KERNEL}" ]; then
318
kernparts="${OPT_KERNEL}"
319
elif [ -n "${OPT_IMAGE}" ]; then
320
if [ -f "${OPT_IMAGE}" ]; then
321
kernparts=$(extract_kerns_from_file "${OPT_IMAGE}")
323
kernparts=$(cgpt find -t kernel "${OPT_IMAGE}")
326
kernparts=$(cgpt find -t kernel)
328
[ -n "${kernparts}" ] || logdie "No kernels found"
330
# Okay if any of the kernel verifications fails
333
for kname in ${kernparts}; do
334
if [ -f "${kname}" ]; then
338
debug "copying ${kname} to ${kfile}..."
339
log dd if="${kname}" of="${kfile}"
342
infon "Kernel ${kname}: "
343
log vbutil_keyblock --unpack "${kfile}" ; result
344
if [ "${LAST_RESULT}" != "0" ]; then
345
loghead od -Ax -tx1 "${kfile}"
347
# Test each kernel with each key
348
for key in kern_subkey_A.vbpubk kern_subkey_B.vbpubk recoverykey.vbpubk; do
349
infon " Verify ${kname} with $key: "
350
log vbutil_kernel --verify "${kfile}" --signpubkey "$key" ; result
351
if [ "${LAST_RESULT}" = "0" ]; then
352
# rerun to get version numbers
353
vbutil_kernel --verify "${kfile}" --signpubkey "$key" > tmp.txt
354
ver=$(format_as_tpm_version tmp.txt)
355
info " TPM=${tpm_kernver} this=${ver}"