summaryrefslogtreecommitdiff
path: root/utility/dev_debug_vboot
blob: ceb865888edf2168795bf3066ee7ec860f69c429 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/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