Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(506)

Side by Side Diff: utility/chromeos_tpm_recovery

Issue 3838008: Script to diagnose and fix TPM problems in recovery mode. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/vboot_reference.git
Patch Set: remove confusing and at best marginally useful statement Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | utility/chromeos_tpm_recovery_test » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/bin/sh -u
2 # Copyright (c) 2010 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 # Run TPM diagnostics in recovery mode, and attempt to fix problems. This is
7 # specific to devices with chromeos firmware.
8 #
9 # Usage: chromeos_tpm_recovery <log file>
10 #
11 # Most of the diagnostics examine the TPM state and try to fix it. This may
12 # require clearing TPM ownership.
13
14 tpmc=${USR_BIN:=/usr/bin}/tpmc
15 nvtool=$USR_BIN/tpm-nvtool
16 tpm_takeownership=${USR_SBIN:=/usr/sbin}/tpm_takeownership
17 tcsd=$USR_SBIN/tcsd
18 dot_recovery=${DOT_RECOVERY:=/mnt/stateful_partition/.recovery}
19 acpi=${ACPI_DIR:=/sys/devices/platform/chromeos_acpi}
20 awk=/usr/bin/awk
21
22 # At the time this script starts, we assume the following holds:
23 #
24 # - TPM may be owned, but not with the well-known password
25 # - tcsd has not been started
26
27 tpm_owned_with_well_known_password=0
28 tpm_unowned=0
29 tcsd_pid=0
30
31 log() {
32 echo "$(date): $*" >> $RECOVERY_LOG
33 }
34
35 quit() {
36 log "ERROR: $*"
37 log "exiting"
38 exit 1
39 }
40
41 log_tryfix() {
42 log "$*: attempting to fix"
43 }
44
45 # bit <n> <i> outputs bit i of number n, with bit 0 being the lsb.
46
47 bit () {
48 echo $(( ( $1 >> $2 ) & 1 ))
49 }
50
51 ensure_tcsd_is_running () {
52 if [ $tcsd_pid = 0 ]; then
53 $tcsd -f &
54 tcsd_pid=$!
55 fi
56 }
57
58 ensure_tcsd_is_not_running () {
59 if [ $tcsd_pid != 0 ]; then
60 kill $tcsd_pid
61 wait $tcsd_pid > /dev/null 2>&1 # we trust that tcsd will agree to die
62 tcsd_pid=0
63 fi
64 }
65
66 tpm_clear_and_reenable () {
67 ensure_tcsd_is_not_running
68 $tpmc clear
69 $tpmc enable
70 $tpmc activate
71 tpm_owned_with_well_known_password=0
72 tpm_unowned=1
73 }
74
75 ensure_tpm_is_owned () {
76 if [ $tpm_owned_with_well_known_password = 0 -a \
77 $tpm_unowned = 0 ]; then
78 tpm_clear_and_reenable
79 ensure_tcsd_is_running
80 $tpm_takeownership -y -z || log "takeownership failed with status $?"
81 tpm_owned_with_well_known_password=1
82 tpm_unowned=0
83 fi
84 }
85
86 ensure_tpm_is_unowned () {
87 if [ $tpm_unowned = 0 ]; then
88 tpm_clear_and_reenable
89 fi
90 }
91
92 remove_space () {
93 index=$1
94 log "removing space $index"
95 ensure_tpm_is_owned
96 ensure_tcsd_is_running
97 $nvtool --release --index "$index" --owner_password "" >> $RECOVERY_LOG 2>&1
98 log "nvtool --release: status $?"
99 }
100
101 # Makes some room by removing a TPM space it doesn't recognize. It would be
102 # nice to let the user choose which space, but we may not have a UI.
103
104 make_room () {
105
106 # Check NVRAM spaces.
107 AWK_PROGRAM=/tmp/tpm_recovery_$$.awk
108 cat > $AWK_PROGRAM <<"EOF"
109 /# NV Index 0xffffffff/ { next } # NV_INDEX_LOCK
110 /# NV Index 0x00000000/ { next } # NV_INDEX0
111 /# NV Index 0x00000001/ { next } # NV_INDEX_DIR
112 /# NV Index 0x0000f.../ { next } # reserved for TPM use
113 /# NV Index 0x0001..../ { next } # reserved for TCG WGs
114 /# NV Index 0x00001007/ { next } # firmware space index
115 /# NV Index 0x00001008/ { next } # kernel space index
116 /# NV Index / { print $4 } #unexpected space
117 EOF
118
119 ensure_tcsd_is_running
120 ensure_tpm_is_owned
121 unexpected_spaces=$($nvtool --list | $awk -f $AWK_PROGRAM)
122
123 status=1
124
125 if ("$unexpected_spaces" != ""); then
126 log_tryfix "unexpected spaces: $unexpected_spaces"
127 for index in $unexpected_spaces; do
128 if remove_space $index; then
129 status=0
130 break;
131 fi
132 done
133 fi
134
135 return $status
136 }
137
138 # define_space <index> <size> <permissions>
139
140 define_space () {
141 local index=$1
142 local size=$2
143 local permissions=$3
144 # 0xf004 is for testing if there is enough room without side effects.
145 local test_space=0xf004
146 local perm_ppwrite=0x1
147 local enough_room
148
149 ensure_tpm_is_unowned
150 while true; do
151 if $tpmc definespace $test_space $size $perm_ppwrite; then
152 enough_room=1
153 break
154 else
155 if ! make_room; then
156 enough_room=0
157 break
158 fi
159 fi
160 done
161
162 if [ $enough_room -eq 0 ]; then
163 log "not enough room to define space $index"
164 return 1
165 fi
166 $tpmc definespace $index $size $permissions
167 }
168
169 fix_space () {
170 local index=$1
171 local permissions=$2
172 local size=$3
173 local bytes="$4"
174
175 local space_exists=1
176
177 ensure_tcsd_is_not_running
178 observed_permissions=$($tpmc getp $index | $awk '{print $5;}')
179 if [ $? -ne 0 ]; then
180 space_exists=0
181 fi
182
183 # Check kernel space ID.
184 if [ $space_exists -eq 1 -a $index = 0x1008 ]; then
185 if ! $tpmc read 0x1008 0x5 | grep -q " 4c 57 52 47[ ]*$"; then
186 log "bad kernel space id"
187 remove_space $index
188 space_exists=0
189 fi
190 fi
191
192 # Check that space is large enough (we don't care if it's larger)
193 if [ $space_exists -eq 1 ]; then
194 if ! $tpmc read $index $size > /dev/null; then
195 log "space $index read of size $size failed"
196 remove_space $index
197 space_exists=0
198 fi
199 fi
200
201 # If space exists but permissions are bad, delete the space.
202 if [ $space_exists -eq 1 -a $observed_permissions != $permissions ]; then
203 log "space $index has unexpected permissions $permissions"
204 remove_space $index
205 space_exists=0
206 fi
207
208 # If space does not exist, reconstruct it.
209 if [ $space_exists -eq 0 ]; then
210 log_tryfix "space $index is gone"
211 if ! define_space $index $size $permissions; then
212 log "could not redefine space $index"
213 return 1
214 fi
215 # do not quote "$bytes", as we mean to expand it here
216 $tpmc write $index $bytes || log "writing to $index failed with code $?"
217 log "space $index was recreated successfully"
218 fi
219 }
220
221
222 # ------------
223 # MAIN PROGRAM
224 # ------------
225
226 # Set up logging and announce ourselves.
227
228 if [ $# = 1 ]; then
229 RECOVERY_LOG="$1"
230 /usr/bin/logger "$0 started, output in $RECOVERY_LOG"
231 log "starting"
232 else
233 /usr/bin/logger "$0 usage error"
234 echo "usage: $0 <log file>"
235 exit 1
236 fi
237
238 # Sanity check: are we executing in a recovery image?
239
240 if [ ! -e $dot_recovery ]; then
241 quit "not a recovery image"
242 fi
243
244 # Mnemonic: "B, I, N, F, O, and BINFO was his name-o."
245 # Except it's a zero (0), not an O.
246 BINF0=$acpi/BINF.0
247 CRSW=$acpi/CRSW
248
249 # There is no point running unless this a ChromeOS device.
250
251 if [ ! -e $BINF0 ]; then
252 log "not a chromeos device, exiting"
253 exit 0
254 fi
255
256 BOOT_REASON=$(cat $BINF0)
257 log "boot reason is $BOOT_REASON"
258
259 # Sanity check: did we boot in recovery mode?
260
261 if ! echo $BOOT_REASON | grep -q "^[345678]$"; then
262 quit "unexpected boot reason $BOOT_REASON"
263 fi
264
265 # Do we even have these tools in the image?
266
267 if [ ! -e $tpmc -o ! -e $nvtool -o ! -e $tpm_takeownership ]; then
268 quit "tpmc or nvtool or tpm_takeownership are missing"
269 fi
270
271 # Is the state of the PP enable flags correct?
272
273 if ! ($tpmc getpf | grep -q "physicalPresenceLifetimeLock 1" &&
274 $tpmc getpf | grep -q "physicalPresenceHWEnable 0" &&
275 $tpmc getpf | grep -q "physicalPresenceCMDEnable 1"); then
276 log_tryfix "bad state of physical presence enable flags"
277 if $tpmc ppfin; then
278 log "physical presence enable flags are now correctly set"
279 else
280 quit "could not set physical presence enable flags"
281 fi
282 fi
283
284 # Is physical presence turned on?
285
286 if $tpmc getvf | grep -q "physicalPresence 0"; then
287 log_tryfix "physical presence is OFF, expected ON"
288 # attempt to turn on physical presence
289 if $tpmc ppon; then
290 log "physical presence is now on"
291 else
292 quit "could not turn physical presence on"
293 fi
294 fi
295
296 DEV_MODE_NOW=$(bit $(cat $CRSW) 4)
297 DEV_MODE_AT_BOOT=$(bit $(cat $CRSW) 5)
298
299 # Check that bGlobalLock is unset
300
301 if [ $DEV_MODE_NOW != $DEV_MODE_AT_BOOT ]; then
302 # this is either too weird or malicious, so we give up
303 quit "dev mode is $DEV_MODE_NOW, but was $DEV_MODE_AT_BOOT at boot"
304 fi
305
306 BGLOBALLOCK=$($tpmc getvf | $awk '/bGlobalLock/ {print $2;}')
307
308 if [ 0 -ne $BGLOBALLOCK ]; then
309 # this indicates either TPM malfunction or firmware malfunction.
310 log "bGlobalLock is $BGLOBALLOCK (dev mode is $DEV_MODE_NOW)."
311 fi
312
313 # Check firmware and kernel spaces
314 fix_space 0x1007 0x8001 0xa "01 00 00 00 00 00 00 00 00 00" || \
315 log "could not fix firmware space"
316 fix_space 0x1008 0x1 0xd "01 4c 57 52 47 00 00 00 00 00 00 00 00" || \
317 log "could not fix kernel space"
318
319 # Cleanup: don't leave the tpm owned with the well-known password.
320 if [ $tpm_owned_with_well_known_password -eq 1 ]; then
321 tpm_clear_and_reenable
322 fi
323
324 ensure_tcsd_is_not_running
OLDNEW
« no previous file with comments | « no previous file | utility/chromeos_tpm_recovery_test » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698