blob: 48c48a1aee0cd7e2c8dcaa2e561fb5554f7773b7 [file] [log] [blame]
Bill Richardson9b717be2011-11-08 10:06:06 -08001#!/bin/sh -ue
Bill Richardson624ee7e2011-04-08 15:27:53 -07002# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Bill Richardson60bcbe32010-09-09 14:53:56 -07003# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5#
Bill Richardsona98ad7a2010-10-29 11:12:36 -07006# Usage: dev_debug_vboot [ --cleanup | DIRECTORY ]
7#
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.
11#
Bill Richardson9b717be2011-11-08 10:06:06 -080012##############################################################################
Bill Richardson60bcbe32010-09-09 14:53:56 -070013
Bill Richardson9b717be2011-11-08 10:06:06 -080014# 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
Bill Richardson624ee7e2011-04-08 15:27:53 -070016
Bill Richardson480a3232011-04-12 20:27:54 -070017PUBLOGFILE="/var/log/debug_vboot_noisy.log"
Bill Richardson6f9a99b2010-10-25 14:58:05 -070018
Bill Richardson9b717be2011-11-08 10:06:06 -080019OPT_CLEANUP=
20OPT_BIOS=
Bill Richardsoncfe83a82014-12-04 11:29:57 -080021OPT_FORCE=
Bill Richardson9b717be2011-11-08 10:06:06 -080022OPT_IMAGE=
23OPT_KERNEL=
24OPT_VERBOSE=
Vadim Bendeburyad3e3ac2011-06-01 19:20:35 -070025
Bill Richardson9b717be2011-11-08 10:06:06 -080026FLAG_SAVE_LOG_FILE=yes
27
28LOGFILE=/dev/stdout
29TMPDIR=
30
31##############################################################################
32
33usage() {
34 local prog
35
36 prog=${0##*/}
37 cat <<EOF
38
39Usage: $prog [options] [DIRECTORY]
40
41This logs as much as it can about the verified boot process. With no arguments
42it will attempt to read the current BIOS, extract the firmware keys, and use
43those keys to validate all the ChromeOS kernel partitions it can find. A
44summary output is printed on stdout, and the detailed log is copied to
45$PUBLOGFILE afterwards.
46
47If a directory is given, it will attempt to use the components from that
48directory and will leave the detailed log in that directory.
49
50Options:
51
52 -b FILE, --bios FILE Specify the BIOS image to use
53 -i FILE, --image FILE Specify the disk image to use
54 -k FILE, --kernel FILE Specify the kernel partition image to use
55 -v Spew the detailed log to stdout
56
57 -c, --cleanup Delete the DIRECTORY when done
58
59 -h, --help Print this help message and exit
60
61EOF
62exit 0
63}
Bill Richardsona98ad7a2010-10-29 11:12:36 -070064
65cleanup() {
Bill Richardson9b717be2011-11-08 10:06:06 -080066 if [ -n "${FLAG_SAVE_LOG_FILE}" ]; then
67 if cp -f "${LOGFILE}" "${PUBLOGFILE}" 2>/dev/null; then
68 info "Exporting log file as ${PUBLOGFILE}"
69 fi
Bill Richardson624ee7e2011-04-08 15:27:53 -070070 fi
Bill Richardson9b717be2011-11-08 10:06:06 -080071 if [ -n "${OPT_CLEANUP}" ] && [ -d "${TMPDIR}" ] ; then
Bill Richardson624ee7e2011-04-08 15:27:53 -070072 cd /
73 rm -rf "${TMPDIR}"
Bill Richardsona98ad7a2010-10-29 11:12:36 -070074 fi
75}
76
Bill Richardson6f9a99b2010-10-25 14:58:05 -070077die() {
78 echo "$*" 1>&2
79 exit 1
80}
81
82info() {
83 echo "$@"
84 echo "#" "$@" >> "$LOGFILE"
85}
86
87infon() {
88 echo -n "$@"
89 echo "#" "$@" >> "$LOGFILE"
90}
91
Bill Richardson9b717be2011-11-08 10:06:06 -080092debug() {
93 echo "#" "$@" >> "$LOGFILE"
94}
95
Bill Richardson6f9a99b2010-10-25 14:58:05 -070096log() {
97 echo "+" "$@" >> "$LOGFILE"
98 "$@" >> "$LOGFILE" 2>&1
99}
100
Bill Richardson4f650a12010-11-01 15:28:12 -0700101loghead() {
102 echo "+" "$@" "| head" >> "$LOGFILE"
103 "$@" | head >> "$LOGFILE" 2>&1
104}
Bill Richardsonccdaa472011-03-03 18:08:18 -0800105
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700106logdie() {
Bill Richardson9b717be2011-11-08 10:06:06 -0800107 echo "+ERROR:" "$@" >> "$LOGFILE"
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700108 die "$@"
109}
110
111result() {
Bill Richardson9b717be2011-11-08 10:06:06 -0800112 LAST_RESULT=$?
113 if [ "${LAST_RESULT}" = "0" ]; then
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700114 info "OK"
115 else
116 info "FAILED"
117 fi
118}
119
Bill Richardson9b717be2011-11-08 10:06:06 -0800120require_utils() {
121 local missing
Bill Richardsona98ad7a2010-10-29 11:12:36 -0700122
Bill Richardson9b717be2011-11-08 10:06:06 -0800123 missing=
124 for tool in $* ; do
125 if ! type "$tool" >/dev/null 2>&1 ; then
126 missing="$missing $tool"
Bill Richardsonccdaa472011-03-03 18:08:18 -0800127 fi
128 done
Bill Richardson9b717be2011-11-08 10:06:06 -0800129 if [ -n "$missing" ]; then
130 logdie "can't find these programs: $missing"
Bill Richardsona98ad7a2010-10-29 11:12:36 -0700131 fi
Bill Richardson9b717be2011-11-08 10:06:06 -0800132}
133
134extract_kerns_from_file() {
135 local start
136 local size
137 local part
138 local rest
139
140 debug "Extracting kernel partitions from $1 ..."
141 cgpt find -v -t kernel "$1" | grep 'Label:' |
142 while read start size part rest; do
143 name="part_${part}"
144 log dd if="$1" bs=512 skip=${start} count=${size} of="${name}" &&
145 echo "${name}"
146 done
147}
148
149format_as_tpm_version() {
150 local a
151 local b
152 local what
153 local num
154 local rest
155
156 a='/(Data|Kernel) key version/ {print $1,$4}'
157 b='/Kernel version/ {print $1, $3}'
158 awk "$a $b" "$1" | while read what num rest; do
159 [ "${what}" = "Data" ] && block="${num}"
160 [ "${what}" = "Kernel" ] && printf '0x%04x%04x' "${block}" "${num}"
161 done
162}
163
164fix_old_names() {
165 # Convert any old-style names to new-style
166 [ -f GBB_Area ] && log mv -f GBB_Area GBB
167 [ -f Firmware_A_Key ] && log mv -f Firmware_A_Key VBLOCK_A
168 [ -f Firmware_B_Key ] && log mv -f Firmware_B_Key VBLOCK_B
169 [ -f Firmware_A_Data ] && log mv -f Firmware_A_Data FW_MAIN_A
170 [ -f Firmware_B_Data ] && log mv -f Firmware_B_Data FW_MAIN_B
171 true
172}
173
Bill Richardson9b717be2011-11-08 10:06:06 -0800174##############################################################################
175# Here we go...
176
177umask 022
178
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800179# defaults
180DEV_DEBUG_FORCE=
181
182# override them?
183[ -f /etc/default/vboot_reference ] && . /etc/default/vboot_reference
184
Bill Richardson9b717be2011-11-08 10:06:06 -0800185# Pre-parse args to replace actual args with a sanitized version.
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800186TEMP=$(getopt -o hvb:i:k:cf --long help,bios:,image:,kernel:,cleanup,force \
Bill Richardson9b717be2011-11-08 10:06:06 -0800187 -n $0 -- "$@")
188eval set -- "$TEMP"
189
190# Now look at them.
191while true ; do
192 case "${1:-}" in
193 -b|--bios)
194 OPT_BIOS=$(readlink -f "$2")
195 shift 2
196 FLAG_SAVE_LOG_FILE=
197 ;;
198 -i|--image=*)
199 OPT_IMAGE=$(readlink -f "$2")
200 shift 2
201 FLAG_SAVE_LOG_FILE=
202 ;;
203 -k|--kernel)
204 OPT_KERNEL=$(readlink -f "$2")
205 shift 2
206 FLAG_SAVE_LOG_FILE=
207 ;;
208 -c|--cleanup)
209 OPT_CLEANUP=yes
210 shift
211 ;;
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800212 -f|--force)
213 OPT_FORCE=yes
214 shift
215 ;;
Bill Richardson9b717be2011-11-08 10:06:06 -0800216 -v)
217 OPT_VERBOSE=yes
218 shift
219 FLAG_SAVE_LOG_FILE=
220 ;;
221 -h|--help)
222 usage
223 break
224 ;;
225 --)
226 shift
227 break
228 ;;
229 *)
230 die "Internal error in option parsing"
231 ;;
232 esac
233done
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800234
Bill Richardson9b717be2011-11-08 10:06:06 -0800235if [ -z "${1:-}" ]; then
236 TMPDIR=$(mktemp -d /tmp/debug_vboot_XXXXXXXXX)
237else
238 TMPDIR="$1"
239 [ -d ${TMPDIR} ] || die "$TMPDIR doesn't exist"
240 FLAG_SAVE_LOG_FILE=
Bill Richardson60bcbe32010-09-09 14:53:56 -0700241fi
Bill Richardson9b717be2011-11-08 10:06:06 -0800242[ -z "${OPT_VERBOSE}" ] && LOGFILE="${TMPDIR}/noisy.log"
Bill Richardson60bcbe32010-09-09 14:53:56 -0700243
Bill Richardsona98ad7a2010-10-29 11:12:36 -0700244[ -d ${TMPDIR} ] || mkdir -p ${TMPDIR} || exit 1
Bill Richardson480a3232011-04-12 20:27:54 -0700245cd ${TMPDIR} || exit 1
Bill Richardson9b717be2011-11-08 10:06:06 -0800246echo "Running $0 $*" > "$LOGFILE"
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700247log date
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800248debug "DEV_DEBUG_FORCE=($DEV_DEBUG_FORCE)"
Bill Richardson9b717be2011-11-08 10:06:06 -0800249debug "OPT_CLEANUP=($OPT_CLEANUP)"
250debug "OPT_BIOS=($OPT_BIOS)"
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800251debug "OPT_FORCE=($OPT_FORCE)"
Bill Richardson9b717be2011-11-08 10:06:06 -0800252debug "OPT_IMAGE=($OPT_IMAGE)"
253debug "OPT_KERNEL=($OPT_KERNEL)"
254debug "FLAG_SAVE_LOG_FILE=($FLAG_SAVE_LOG_FILE)"
Bill Richardson85b5c882011-04-19 12:56:30 -0700255echo "Saving verbose log as $LOGFILE"
Bill Richardson9b717be2011-11-08 10:06:06 -0800256trap cleanup EXIT
Bill Richardson60bcbe32010-09-09 14:53:56 -0700257
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800258if [ -n "${DEV_DEBUG_FORCE}" ] && [ -z "${OPT_FORCE}" ]; then
259 info "Not gonna do anything without the --force option."
260 exit 0
261fi
262
Bill Richardson60bcbe32010-09-09 14:53:56 -0700263
Bill Richardson9b717be2011-11-08 10:06:06 -0800264# Make sure we have the programs we need
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700265need="futility"
Bill Richardson9b717be2011-11-08 10:06:06 -0800266[ -z "${OPT_BIOS}" ] && need="$need flashrom"
267[ -z "${OPT_KERNEL}" ] && need="$need cgpt"
268require_utils $need
269
270
271# Assuming we're on a ChromeOS device, see what we know.
272set +e
273log crossystem --all
274log rootdev -s
275log ls -aCF /root
276log ls -aCF /mnt/stateful_partition
Gwendal Grignou08d56aa2016-10-13 13:18:37 -0700277devs=$(awk '/(mmcblk[0-9])$|(sd[a-z])$|(nvme[0-9]+n[0-9]+)$/ {print "/dev/"$4}' /proc/partitions)
Bill Richardson9b717be2011-11-08 10:06:06 -0800278for d in $devs; do
279 log cgpt show $d
280done
Hung-Te Lin798cc912013-08-20 15:08:47 +0800281log flashrom -V -p host --wp-status
Bill Richardson9b717be2011-11-08 10:06:06 -0800282tpm_fwver=$(crossystem tpm_fwver) || tpm_fwver="UNKNOWN"
283tpm_kernver=$(crossystem tpm_kernver) || tpm_kernver="UNKNOWN"
284set -e
285
286
287info "Extracting BIOS components..."
288if [ -n "${OPT_BIOS}" ]; then
289 # If we've already got a file, just extract everything.
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700290 log futility dump_fmap -x "${OPT_BIOS}"
Bill Richardson9b717be2011-11-08 10:06:06 -0800291 fix_old_names
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700292else
Bill Richardsoncfe83a82014-12-04 11:29:57 -0800293 # First try pulling just the components we want (using new-style names)
294 if log flashrom -p host -r /dev/null \
295 -i"GBB":GBB \
296 -i"FMAP":FMAP \
297 -i"VBLOCK_A":VBLOCK_A \
298 -i"VBLOCK_B":VBLOCK_B \
299 -i"FW_MAIN_A":FW_MAIN_A \
300 -i"FW_MAIN_B":FW_MAIN_B ; then
301 log futility dump_fmap FMAP
302 else
303 info "Couldn't read individual components. Read the whole thing..."
304 if log flashrom -p host -r bios.rom ; then
305 log futility dump_fmap -x bios.rom
306 fix_old_names
307 else
308 logdie "Can't read BIOS at all. Giving up."
309 fi
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700310 fi
Bill Richardson60bcbe32010-09-09 14:53:56 -0700311fi
312
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700313info "Pulling root and recovery keys from GBB..."
Hung-Te Lin01dc8182017-06-19 10:08:46 +0800314log futility gbb -g --rootkey rootkey.vbpubk \
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700315 --recoverykey recoverykey.vbpubk \
Bill Richardson9b717be2011-11-08 10:06:06 -0800316 "GBB" || logdie "Unable to extract keys from GBB"
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700317log futility vbutil_key --unpack rootkey.vbpubk
318log futility vbutil_key --unpack recoverykey.vbpubk
319futility vbutil_key --unpack rootkey.vbpubk |
Bill Richardson9b717be2011-11-08 10:06:06 -0800320 grep -q b11d74edd286c144e1135b49e7f0bc20cf041f10 &&
321 info " Looks like dev-keys"
322# Okay if one of the firmware verifications fails
323set +e
324for fw in A B; do
325 infon "Verify firmware ${fw} with root key: "
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700326 log futility vbutil_firmware --verify "VBLOCK_${fw}" \
327 --signpubkey rootkey.vbpubk \
Bill Richardson9b717be2011-11-08 10:06:06 -0800328 --fv "FW_MAIN_${fw}" --kernelkey "kern_subkey_${fw}.vbpubk" ; result
329 if [ "${LAST_RESULT}" = "0" ]; then
330 # rerun to get version numbers
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700331 futility vbutil_firmware --verify "VBLOCK_${fw}" \
332 --signpubkey rootkey.vbpubk \
Bill Richardson9b717be2011-11-08 10:06:06 -0800333 --fv "FW_MAIN_${fw}" > tmp.txt
334 ver=$(format_as_tpm_version tmp.txt)
335 info " TPM=${tpm_fwver}, this=${ver}"
336 fi
337done
338set -e
Bill Richardson60bcbe32010-09-09 14:53:56 -0700339
Bill Richardson9b717be2011-11-08 10:06:06 -0800340info "Examining kernels..."
341if [ -n "${OPT_KERNEL}" ]; then
342 kernparts="${OPT_KERNEL}"
343elif [ -n "${OPT_IMAGE}" ]; then
344 if [ -f "${OPT_IMAGE}" ]; then
345 kernparts=$(extract_kerns_from_file "${OPT_IMAGE}")
346 else
347 kernparts=$(cgpt find -t kernel "${OPT_IMAGE}")
348 fi
349else
350 kernparts=$(cgpt find -t kernel)
351fi
352[ -n "${kernparts}" ] || logdie "No kernels found"
Bill Richardson60bcbe32010-09-09 14:53:56 -0700353
Bill Richardson9b717be2011-11-08 10:06:06 -0800354# Okay if any of the kernel verifications fails
355set +e
356kc=0
357for kname in ${kernparts}; do
358 if [ -f "${kname}" ]; then
359 kfile="${kname}"
360 else
361 kfile="kern_${kc}"
362 debug "copying ${kname} to ${kfile}..."
363 log dd if="${kname}" of="${kfile}"
364 fi
365
366 infon "Kernel ${kname}: "
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700367 log futility vbutil_keyblock --unpack "${kfile}" ; result
Bill Richardson9b717be2011-11-08 10:06:06 -0800368 if [ "${LAST_RESULT}" != "0" ]; then
369 loghead od -Ax -tx1 "${kfile}"
370 else
371 # Test each kernel with each key
372 for key in kern_subkey_A.vbpubk kern_subkey_B.vbpubk recoverykey.vbpubk; do
373 infon " Verify ${kname} with $key: "
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700374 log futility vbutil_kernel --verify "${kfile}" --signpubkey "$key" ; result
Bill Richardson9b717be2011-11-08 10:06:06 -0800375 if [ "${LAST_RESULT}" = "0" ]; then
376 # rerun to get version numbers
Bill Richardsona1d9fe62014-09-05 12:52:27 -0700377 futility vbutil_kernel --verify "${kfile}" --signpubkey "$key" > tmp.txt
Bill Richardson9b717be2011-11-08 10:06:06 -0800378 ver=$(format_as_tpm_version tmp.txt)
379 info " TPM=${tpm_kernver} this=${ver}"
380 fi
381 done
382 fi
383
384 kc=$(expr $kc + 1)
Bill Richardson6f9a99b2010-10-25 14:58:05 -0700385done
Bill Richardson60bcbe32010-09-09 14:53:56 -0700386
Bill Richardson9b717be2011-11-08 10:06:06 -0800387exit 0