~ubuntu-branches/ubuntu/trusty/vboot-utils/trusty

« back to all changes in this revision

Viewing changes to utility/dev_debug_vboot

  • Committer: Package Import Robot
  • Author(s): Antonio Terceiro
  • Date: 2012-12-16 11:03:40 UTC
  • Revision ID: package-import@ubuntu.com-20121216110340-f7wcseecbc9jed5l
Tags: upstream-0~20121212
ImportĀ upstreamĀ versionĀ 0~20121212

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/bin/sh -ue
 
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.
 
5
#
 
6
# 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
#
 
12
##############################################################################
 
13
 
 
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
 
16
 
 
17
PUBLOGFILE="/var/log/debug_vboot_noisy.log"
 
18
 
 
19
OPT_CLEANUP=
 
20
OPT_BIOS=
 
21
OPT_IMAGE=
 
22
OPT_KERNEL=
 
23
OPT_VERBOSE=
 
24
 
 
25
FLAG_SAVE_LOG_FILE=yes
 
26
 
 
27
LOGFILE=/dev/stdout
 
28
TMPDIR=
 
29
 
 
30
##############################################################################
 
31
 
 
32
usage() {
 
33
  local prog
 
34
 
 
35
  prog=${0##*/}
 
36
  cat <<EOF
 
37
 
 
38
Usage: $prog [options] [DIRECTORY]
 
39
 
 
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.
 
45
 
 
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.
 
48
 
 
49
Options:
 
50
 
 
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
 
55
 
 
56
   -c, --cleanup               Delete the DIRECTORY when done
 
57
 
 
58
   -h, --help                  Print this help message and exit
 
59
 
 
60
EOF
 
61
exit 0
 
62
}
 
63
 
 
64
cleanup() {
 
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}"
 
68
    fi
 
69
  fi
 
70
  if [ -n "${OPT_CLEANUP}" ] && [ -d "${TMPDIR}" ] ; then
 
71
    cd /
 
72
    rm -rf "${TMPDIR}"
 
73
  fi
 
74
}
 
75
 
 
76
die() {
 
77
  echo "$*" 1>&2
 
78
  exit 1
 
79
}
 
80
 
 
81
info() {
 
82
  echo "$@"
 
83
  echo "#" "$@" >> "$LOGFILE"
 
84
}
 
85
 
 
86
infon() {
 
87
  echo -n "$@"
 
88
  echo "#" "$@" >> "$LOGFILE"
 
89
}
 
90
 
 
91
debug() {
 
92
  echo "#" "$@" >> "$LOGFILE"
 
93
}
 
94
 
 
95
log() {
 
96
  echo "+" "$@" >> "$LOGFILE"
 
97
  "$@" >> "$LOGFILE" 2>&1
 
98
}
 
99
 
 
100
loghead() {
 
101
  echo "+" "$@" "| head" >> "$LOGFILE"
 
102
  "$@" | head >> "$LOGFILE" 2>&1
 
103
}
 
104
 
 
105
logdie() {
 
106
  echo "+ERROR:" "$@" >> "$LOGFILE"
 
107
  die "$@"
 
108
}
 
109
 
 
110
result() {
 
111
  LAST_RESULT=$?
 
112
  if [ "${LAST_RESULT}" = "0" ]; then
 
113
    info "OK"
 
114
  else
 
115
    info "FAILED"
 
116
  fi
 
117
}
 
118
 
 
119
require_utils() {
 
120
  local missing
 
121
 
 
122
  missing=
 
123
  for tool in $* ; do
 
124
    if ! type "$tool" >/dev/null 2>&1 ; then
 
125
      missing="$missing $tool"
 
126
    fi
 
127
  done
 
128
  if [ -n "$missing" ]; then
 
129
    logdie "can't find these programs: $missing"
 
130
  fi
 
131
}
 
132
 
 
133
extract_kerns_from_file() {
 
134
  local start
 
135
  local size
 
136
  local part
 
137
  local rest
 
138
 
 
139
  debug "Extracting kernel partitions from $1 ..."
 
140
  cgpt find -v -t kernel "$1" | grep 'Label:' |
 
141
    while read start size part rest; do
 
142
      name="part_${part}"
 
143
      log dd if="$1" bs=512 skip=${start} count=${size} of="${name}" &&
 
144
        echo "${name}"
 
145
    done
 
146
}
 
147
 
 
148
format_as_tpm_version() {
 
149
  local a
 
150
  local b
 
151
  local what
 
152
  local num
 
153
  local rest
 
154
 
 
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}"
 
160
  done
 
161
}
 
162
 
 
163
fix_old_names() {
 
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
 
170
  true
 
171
}
 
172
 
 
173
 
 
174
##############################################################################
 
175
# Here we go...
 
176
 
 
177
umask 022
 
178
 
 
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 \
 
181
       -n $0 -- "$@")
 
182
eval set -- "$TEMP"
 
183
 
 
184
# Now look at them.
 
185
while true ; do
 
186
  case "${1:-}" in
 
187
    -b|--bios)
 
188
      OPT_BIOS=$(readlink -f "$2")
 
189
      shift 2
 
190
      FLAG_SAVE_LOG_FILE=
 
191
      ;;
 
192
    -i|--image=*)
 
193
      OPT_IMAGE=$(readlink -f "$2")
 
194
      shift 2
 
195
      FLAG_SAVE_LOG_FILE=
 
196
      ;;
 
197
    -k|--kernel)
 
198
      OPT_KERNEL=$(readlink -f "$2")
 
199
      shift 2
 
200
      FLAG_SAVE_LOG_FILE=
 
201
      ;;
 
202
    -c|--cleanup)
 
203
      OPT_CLEANUP=yes
 
204
      shift
 
205
      ;;
 
206
    -v)
 
207
      OPT_VERBOSE=yes
 
208
      shift
 
209
      FLAG_SAVE_LOG_FILE=
 
210
      ;;
 
211
    -h|--help)
 
212
      usage
 
213
      break
 
214
      ;;
 
215
    --)
 
216
      shift
 
217
      break
 
218
      ;;
 
219
    *)
 
220
      die "Internal error in option parsing"
 
221
      ;;
 
222
  esac
 
223
done
 
224
if [ -z "${1:-}" ]; then
 
225
  TMPDIR=$(mktemp -d /tmp/debug_vboot_XXXXXXXXX)
 
226
else
 
227
  TMPDIR="$1"
 
228
  [ -d ${TMPDIR} ] || die "$TMPDIR doesn't exist"
 
229
  FLAG_SAVE_LOG_FILE=
 
230
fi
 
231
[ -z "${OPT_VERBOSE}" ] && LOGFILE="${TMPDIR}/noisy.log"
 
232
 
 
233
[ -d ${TMPDIR} ] || mkdir -p ${TMPDIR} || exit 1
 
234
cd ${TMPDIR} || exit 1
 
235
echo "Running $0 $*" > "$LOGFILE"
 
236
log date
 
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"
 
243
trap cleanup EXIT
 
244
 
 
245
 
 
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"
 
250
require_utils $need
 
251
 
 
252
 
 
253
# Assuming we're on a ChromeOS device, see what we know.
 
254
set +e
 
255
log crossystem --all
 
256
log rootdev -s
 
257
log ls -aCF /root
 
258
log ls -aCF /mnt/stateful_partition
 
259
devs=$(awk '/(mmcblk[0-9])$|(sd[a-z])$/ {print "/dev/"$4}' /proc/partitions)
 
260
for d in $devs; do
 
261
  log cgpt show $d
 
262
done
 
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"
 
266
set -e
 
267
 
 
268
 
 
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}"
 
273
  fix_old_names
 
274
else
 
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
 
279
    fix_old_names
 
280
  else
 
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 \
 
284
      -i"GBB":GBB \
 
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
 
289
  fi
 
290
fi
 
291
 
 
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
 
301
set +e
 
302
for fw in A B; do
 
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}"
 
312
  fi
 
313
done
 
314
set -e
 
315
 
 
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}")
 
322
  else
 
323
    kernparts=$(cgpt find -t kernel "${OPT_IMAGE}")
 
324
  fi
 
325
else
 
326
  kernparts=$(cgpt find -t kernel)
 
327
fi
 
328
[ -n "${kernparts}" ] || logdie "No kernels found"
 
329
 
 
330
# Okay if any of the kernel verifications fails
 
331
set +e
 
332
kc=0
 
333
for kname in ${kernparts}; do
 
334
  if [ -f "${kname}" ]; then
 
335
    kfile="${kname}"
 
336
  else
 
337
    kfile="kern_${kc}"
 
338
    debug "copying ${kname} to ${kfile}..."
 
339
    log dd if="${kname}" of="${kfile}"
 
340
  fi
 
341
 
 
342
  infon "Kernel ${kname}: "
 
343
  log vbutil_keyblock --unpack "${kfile}" ; result
 
344
  if [ "${LAST_RESULT}" != "0" ]; then
 
345
    loghead od -Ax -tx1 "${kfile}"
 
346
  else
 
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}"
 
356
      fi
 
357
    done
 
358
  fi
 
359
 
 
360
  kc=$(expr $kc + 1)
 
361
done
 
362
 
 
363
exit 0