1*8617a60dSAndroid Build Coastguard Worker#!/bin/sh -u 2*8617a60dSAndroid Build Coastguard Worker# Copyright 2010 The ChromiumOS Authors 3*8617a60dSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8617a60dSAndroid Build Coastguard Worker# found in the LICENSE file. 5*8617a60dSAndroid Build Coastguard Worker# 6*8617a60dSAndroid Build Coastguard Worker# Run TPM diagnostics in recovery mode, and attempt to fix problems. This is 7*8617a60dSAndroid Build Coastguard Worker# specific to devices with chromeos firmware. 8*8617a60dSAndroid Build Coastguard Worker# 9*8617a60dSAndroid Build Coastguard Worker# Most of the diagnostics examine the TPM state and try to fix it. This may 10*8617a60dSAndroid Build Coastguard Worker# require clearing TPM ownership. 11*8617a60dSAndroid Build Coastguard Worker 12*8617a60dSAndroid Build Coastguard Workertpmc=${USR_BIN:=/usr/bin}/tpmc 13*8617a60dSAndroid Build Coastguard Workercrossystem=${USR_BIN}/crossystem 14*8617a60dSAndroid Build Coastguard Workerdot_recovery=${DOT_RECOVERY:=/mnt/stateful_partition/.recovery} 15*8617a60dSAndroid Build Coastguard Workerawk=/usr/bin/awk 16*8617a60dSAndroid Build Coastguard Workerinitctl=/sbin/initctl 17*8617a60dSAndroid Build Coastguard Workerdaemon_was_running= 18*8617a60dSAndroid Build Coastguard Workererr=0 19*8617a60dSAndroid Build Coastguard Workersecdata_firmware=0x1007 20*8617a60dSAndroid Build Coastguard Workersecdata_kernel=0x1008 21*8617a60dSAndroid Build Coastguard Worker 22*8617a60dSAndroid Build Coastguard Workertpm2_target() { 23*8617a60dSAndroid Build Coastguard Worker # This is not an ideal way to tell if we are running on a tpm2 target, but 24*8617a60dSAndroid Build Coastguard Worker # it will have to do for now. 25*8617a60dSAndroid Build Coastguard Worker if [ -f "/etc/init/trunksd.conf" ]; then 26*8617a60dSAndroid Build Coastguard Worker return 0 27*8617a60dSAndroid Build Coastguard Worker else 28*8617a60dSAndroid Build Coastguard Worker return 1 29*8617a60dSAndroid Build Coastguard Worker fi 30*8617a60dSAndroid Build Coastguard Worker} 31*8617a60dSAndroid Build Coastguard Worker 32*8617a60dSAndroid Build Coastguard Workeruse_v0_secdata_kernel() { 33*8617a60dSAndroid Build Coastguard Worker local fwid="$(crossystem ro_fwid)" 34*8617a60dSAndroid Build Coastguard Worker local major="$(printf "$fwid" | cut -d. -f2)" 35*8617a60dSAndroid Build Coastguard Worker local minor="$(printf "$fwid" | cut -d. -f3)" 36*8617a60dSAndroid Build Coastguard Worker 37*8617a60dSAndroid Build Coastguard Worker # TPM1 firmware never supports the v1 kernel space format. 38*8617a60dSAndroid Build Coastguard Worker if ! tpm2_target; then 39*8617a60dSAndroid Build Coastguard Worker return 0 40*8617a60dSAndroid Build Coastguard Worker fi 41*8617a60dSAndroid Build Coastguard Worker 42*8617a60dSAndroid Build Coastguard Worker # First some validity checks: X -eq X checks that X is a number. cut may 43*8617a60dSAndroid Build Coastguard Worker # return the whole string if no delimiter found, so major != minor checks that 44*8617a60dSAndroid Build Coastguard Worker # the version was at least somewhat correctly formatted. 45*8617a60dSAndroid Build Coastguard Worker if [ $major -eq $major ] && [ $minor -eq $minor ] && [ $major -ne $minor ]; then 46*8617a60dSAndroid Build Coastguard Worker # Now what we really care about: is this firmware older than CL:2041695? 47*8617a60dSAndroid Build Coastguard Worker if [ $major -lt 12953 ]; then 48*8617a60dSAndroid Build Coastguard Worker return 0 49*8617a60dSAndroid Build Coastguard Worker else 50*8617a60dSAndroid Build Coastguard Worker return 1 51*8617a60dSAndroid Build Coastguard Worker fi 52*8617a60dSAndroid Build Coastguard Worker else 53*8617a60dSAndroid Build Coastguard Worker log "Cannot parse FWID. Assuming local build that supports v1 kernel space." 54*8617a60dSAndroid Build Coastguard Worker return 1 55*8617a60dSAndroid Build Coastguard Worker fi 56*8617a60dSAndroid Build Coastguard Worker} 57*8617a60dSAndroid Build Coastguard Worker 58*8617a60dSAndroid Build Coastguard Workerlog() { 59*8617a60dSAndroid Build Coastguard Worker echo "$*" 60*8617a60dSAndroid Build Coastguard Worker} 61*8617a60dSAndroid Build Coastguard Worker 62*8617a60dSAndroid Build Coastguard Workerquit() { 63*8617a60dSAndroid Build Coastguard Worker log "ERROR: $*" 64*8617a60dSAndroid Build Coastguard Worker restart_daemon_if_needed 65*8617a60dSAndroid Build Coastguard Worker log "exiting" 66*8617a60dSAndroid Build Coastguard Worker 67*8617a60dSAndroid Build Coastguard Worker exit 1 68*8617a60dSAndroid Build Coastguard Worker} 69*8617a60dSAndroid Build Coastguard Worker 70*8617a60dSAndroid Build Coastguard Workerlog_tryfix() { 71*8617a60dSAndroid Build Coastguard Worker log "$*: attempting to fix" 72*8617a60dSAndroid Build Coastguard Worker} 73*8617a60dSAndroid Build Coastguard Worker 74*8617a60dSAndroid Build Coastguard Workerlog_error() { 75*8617a60dSAndroid Build Coastguard Worker err=$((err + 1)) 76*8617a60dSAndroid Build Coastguard Worker log "ERROR: $*" 77*8617a60dSAndroid Build Coastguard Worker} 78*8617a60dSAndroid Build Coastguard Worker 79*8617a60dSAndroid Build Coastguard Worker 80*8617a60dSAndroid Build Coastguard Workerlog_warn() { 81*8617a60dSAndroid Build Coastguard Worker log "WARNING: $*" 82*8617a60dSAndroid Build Coastguard Worker} 83*8617a60dSAndroid Build Coastguard Worker 84*8617a60dSAndroid Build Coastguard Workertpm_clear_and_reenable () { 85*8617a60dSAndroid Build Coastguard Worker $tpmc clear 86*8617a60dSAndroid Build Coastguard Worker 87*8617a60dSAndroid Build Coastguard Worker # The below commands are are no-op on tpm2, but let's keep them here for 88*8617a60dSAndroid Build Coastguard Worker # both TPM versions in case they are implemented in the future for 89*8617a60dSAndroid Build Coastguard Worker # version 2. 90*8617a60dSAndroid Build Coastguard Worker $tpmc enable 91*8617a60dSAndroid Build Coastguard Worker $tpmc activate 92*8617a60dSAndroid Build Coastguard Worker} 93*8617a60dSAndroid Build Coastguard Worker 94*8617a60dSAndroid Build Coastguard Workerwrite_space () { 95*8617a60dSAndroid Build Coastguard Worker # do not quote "$2", as we mean to expand it here 96*8617a60dSAndroid Build Coastguard Worker if ! $tpmc write $1 $2; then 97*8617a60dSAndroid Build Coastguard Worker log_error "writing to $1 failed" 98*8617a60dSAndroid Build Coastguard Worker else 99*8617a60dSAndroid Build Coastguard Worker log "$1 written successfully" 100*8617a60dSAndroid Build Coastguard Worker fi 101*8617a60dSAndroid Build Coastguard Worker} 102*8617a60dSAndroid Build Coastguard Worker 103*8617a60dSAndroid Build Coastguard Workerreset_ro_space () { 104*8617a60dSAndroid Build Coastguard Worker local index=$1 105*8617a60dSAndroid Build Coastguard Worker local bytes="$2" 106*8617a60dSAndroid Build Coastguard Worker local size=$(printf "$bytes" | wc -w) 107*8617a60dSAndroid Build Coastguard Worker local permissions=0x8001 108*8617a60dSAndroid Build Coastguard Worker 109*8617a60dSAndroid Build Coastguard Worker if tpm2_target; then 110*8617a60dSAndroid Build Coastguard Worker log "Cannot redefine RO space for TPM2 (b/140958855). Let's just hope it looks good..." 111*8617a60dSAndroid Build Coastguard Worker else 112*8617a60dSAndroid Build Coastguard Worker if ! $tpmc definespace $index $size $permissions; then 113*8617a60dSAndroid Build Coastguard Worker log_error "could not redefine RO space $index" 114*8617a60dSAndroid Build Coastguard Worker # try writing it anyway, just in case it works... 115*8617a60dSAndroid Build Coastguard Worker fi 116*8617a60dSAndroid Build Coastguard Worker fi 117*8617a60dSAndroid Build Coastguard Worker 118*8617a60dSAndroid Build Coastguard Worker write_space $index "$bytes" 119*8617a60dSAndroid Build Coastguard Worker} 120*8617a60dSAndroid Build Coastguard Worker 121*8617a60dSAndroid Build Coastguard Workerreset_rw_space () { 122*8617a60dSAndroid Build Coastguard Worker local index=$1 123*8617a60dSAndroid Build Coastguard Worker local bytes="$2" 124*8617a60dSAndroid Build Coastguard Worker local size=$(printf "$bytes" | wc -w) 125*8617a60dSAndroid Build Coastguard Worker local permissions=0x1 126*8617a60dSAndroid Build Coastguard Worker 127*8617a60dSAndroid Build Coastguard Worker if tpm2_target; then 128*8617a60dSAndroid Build Coastguard Worker permissions=0x40050001 129*8617a60dSAndroid Build Coastguard Worker fi 130*8617a60dSAndroid Build Coastguard Worker 131*8617a60dSAndroid Build Coastguard Worker if ! $tpmc definespace $index $size $permissions; then 132*8617a60dSAndroid Build Coastguard Worker log_error "could not redefine RW space $index" 133*8617a60dSAndroid Build Coastguard Worker # try writing it anyway, just in case it works... 134*8617a60dSAndroid Build Coastguard Worker fi 135*8617a60dSAndroid Build Coastguard Worker 136*8617a60dSAndroid Build Coastguard Worker write_space $index "$bytes" 137*8617a60dSAndroid Build Coastguard Worker} 138*8617a60dSAndroid Build Coastguard Worker 139*8617a60dSAndroid Build Coastguard Workerrestart_daemon_if_needed() { 140*8617a60dSAndroid Build Coastguard Worker if [ "$daemon_was_running" = 1 ]; then 141*8617a60dSAndroid Build Coastguard Worker log "Restarting ${DAEMON}..." 142*8617a60dSAndroid Build Coastguard Worker $initctl start "${DAEMON}" >/dev/null 143*8617a60dSAndroid Build Coastguard Worker fi 144*8617a60dSAndroid Build Coastguard Worker} 145*8617a60dSAndroid Build Coastguard Worker 146*8617a60dSAndroid Build Coastguard Worker# ------------ 147*8617a60dSAndroid Build Coastguard Worker# MAIN PROGRAM 148*8617a60dSAndroid Build Coastguard Worker# ------------ 149*8617a60dSAndroid Build Coastguard Worker 150*8617a60dSAndroid Build Coastguard Worker# validity check: are we executing in a recovery image? 151*8617a60dSAndroid Build Coastguard Worker 152*8617a60dSAndroid Build Coastguard Workerif [ -e $dot_recovery ]; then 153*8617a60dSAndroid Build Coastguard Worker quit "This is a developer utility, it should never run on a (production) recovery image" 154*8617a60dSAndroid Build Coastguard Workerfi 155*8617a60dSAndroid Build Coastguard Worker 156*8617a60dSAndroid Build Coastguard Worker# Did the firmware keep the TPM unlocked? 157*8617a60dSAndroid Build Coastguard Worker 158*8617a60dSAndroid Build Coastguard Workerif ! $($crossystem mainfw_type?recovery); then 159*8617a60dSAndroid Build Coastguard Worker quit "You must put a test image on a USB stick and boot it in recovery mode (this means Esc+Refresh+Power, *not* Ctrl-U!) to run this" 160*8617a60dSAndroid Build Coastguard Workerfi 161*8617a60dSAndroid Build Coastguard Worker 162*8617a60dSAndroid Build Coastguard Workerif tpm2_target; then 163*8617a60dSAndroid Build Coastguard Worker DAEMON="trunksd" 164*8617a60dSAndroid Build Coastguard Workerelse 165*8617a60dSAndroid Build Coastguard Worker DAEMON="tcsd" 166*8617a60dSAndroid Build Coastguard Workerfi 167*8617a60dSAndroid Build Coastguard Worker 168*8617a60dSAndroid Build Coastguard Worker# TPM daemon may or may not be running 169*8617a60dSAndroid Build Coastguard Worker 170*8617a60dSAndroid Build Coastguard Workerlog "Stopping ${DAEMON}..." 171*8617a60dSAndroid Build Coastguard Workerif $initctl stop "${DAEMON}" >/dev/null 2>/dev/null; then 172*8617a60dSAndroid Build Coastguard Worker daemon_was_running=1 173*8617a60dSAndroid Build Coastguard Worker log "done" 174*8617a60dSAndroid Build Coastguard Workerelse 175*8617a60dSAndroid Build Coastguard Worker daemon_was_running=0 176*8617a60dSAndroid Build Coastguard Worker log "(was not running)" 177*8617a60dSAndroid Build Coastguard Workerfi 178*8617a60dSAndroid Build Coastguard Worker 179*8617a60dSAndroid Build Coastguard Worker# Is the state of the PP enable flags correct? 180*8617a60dSAndroid Build Coastguard Worker 181*8617a60dSAndroid Build Coastguard Workerif ! tpm2_target; then 182*8617a60dSAndroid Build Coastguard Worker if ! ($tpmc getpf | grep -q "physicalPresenceLifetimeLock 1" && 183*8617a60dSAndroid Build Coastguard Worker $tpmc getpf | grep -q "physicalPresenceHWEnable 0" && 184*8617a60dSAndroid Build Coastguard Worker $tpmc getpf | grep -q "physicalPresenceCMDEnable 1"); then 185*8617a60dSAndroid Build Coastguard Worker log_tryfix "bad state of physical presence enable flags" 186*8617a60dSAndroid Build Coastguard Worker if $tpmc ppfin; then 187*8617a60dSAndroid Build Coastguard Worker log "physical presence enable flags are now correctly set" 188*8617a60dSAndroid Build Coastguard Worker else 189*8617a60dSAndroid Build Coastguard Worker quit "could not set physical presence enable flags" 190*8617a60dSAndroid Build Coastguard Worker fi 191*8617a60dSAndroid Build Coastguard Worker fi 192*8617a60dSAndroid Build Coastguard Worker 193*8617a60dSAndroid Build Coastguard Worker # Is physical presence turned on? 194*8617a60dSAndroid Build Coastguard Worker 195*8617a60dSAndroid Build Coastguard Worker if $tpmc getvf | grep -q "physicalPresence 0"; then 196*8617a60dSAndroid Build Coastguard Worker log_tryfix "physical presence is OFF, expected ON" 197*8617a60dSAndroid Build Coastguard Worker # attempt to turn on physical presence 198*8617a60dSAndroid Build Coastguard Worker if $tpmc ppon; then 199*8617a60dSAndroid Build Coastguard Worker log "physical presence is now on" 200*8617a60dSAndroid Build Coastguard Worker else 201*8617a60dSAndroid Build Coastguard Worker quit "could not turn physical presence on" 202*8617a60dSAndroid Build Coastguard Worker fi 203*8617a60dSAndroid Build Coastguard Worker fi 204*8617a60dSAndroid Build Coastguard Workerelse 205*8617a60dSAndroid Build Coastguard Worker if ! $tpmc getvf | grep -q 'phEnable 1'; then 206*8617a60dSAndroid Build Coastguard Worker quit "Platform Hierarchy is disabled, TPM can't be recovered" 207*8617a60dSAndroid Build Coastguard Worker fi 208*8617a60dSAndroid Build Coastguard Workerfi 209*8617a60dSAndroid Build Coastguard Worker 210*8617a60dSAndroid Build Coastguard Worker# I never learned what this does, but it's probably good just in case... 211*8617a60dSAndroid Build Coastguard Workertpm_clear_and_reenable 212*8617a60dSAndroid Build Coastguard Worker 213*8617a60dSAndroid Build Coastguard Worker# Reset firmware and kernel spaces to default (rollback version 1/1) 214*8617a60dSAndroid Build Coastguard Workerreset_ro_space $secdata_firmware "02 0 1 0 1 0 0 0 0 4f" 215*8617a60dSAndroid Build Coastguard Worker 216*8617a60dSAndroid Build Coastguard Workerif use_v0_secdata_kernel; then 217*8617a60dSAndroid Build Coastguard Worker reset_rw_space $secdata_kernel "02 4c 57 52 47 1 0 1 0 0 0 0 55" 218*8617a60dSAndroid Build Coastguard Workerelse 219*8617a60dSAndroid Build Coastguard Worker reset_rw_space $secdata_kernel "10 28 0c 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" 220*8617a60dSAndroid Build Coastguard Workerfi 221*8617a60dSAndroid Build Coastguard Worker 222*8617a60dSAndroid Build Coastguard Workerrestart_daemon_if_needed 223*8617a60dSAndroid Build Coastguard Worker 224*8617a60dSAndroid Build Coastguard Workerif [ "$err" -eq 0 ]; then 225*8617a60dSAndroid Build Coastguard Worker log "TPM has successfully been reset to factory defaults" 226*8617a60dSAndroid Build Coastguard Workerelse 227*8617a60dSAndroid Build Coastguard Worker log_error "TPM was not fully recovered." 228*8617a60dSAndroid Build Coastguard Worker exit 1 229*8617a60dSAndroid Build Coastguard Workerfi 230