chromeos-tpm-recovery 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. # Most of the diagnostics examine the TPM state and try to fix it. This may
  10. # require clearing TPM ownership.
  11. tpmc=${USR_BIN:=/usr/bin}/tpmc
  12. crossystem=${USR_BIN}/crossystem
  13. dot_recovery=${DOT_RECOVERY:=/mnt/stateful_partition/.recovery}
  14. awk=/usr/bin/awk
  15. initctl=/sbin/initctl
  16. daemon_was_running=
  17. err=0
  18. tpm2_target() {
  19. # This is not an ideal way to tell if we are running on a tpm2 target, but
  20. # it will have to do for now.
  21. if [ -f "/etc/init/trunksd.conf" ]; then
  22. return 0
  23. else
  24. return 1
  25. fi
  26. }
  27. log() {
  28. echo "$*"
  29. }
  30. quit() {
  31. log "ERROR: $*"
  32. restart_daemon_if_needed
  33. log "exiting"
  34. exit 1
  35. }
  36. log_tryfix() {
  37. log "$*: attempting to fix"
  38. }
  39. log_error() {
  40. err=$((err + 1))
  41. log "ERROR: $*"
  42. }
  43. log_warn() {
  44. log "WARNING: $*"
  45. }
  46. tpm_clear_and_reenable () {
  47. $tpmc clear
  48. # The below commands are are no-op on tpm2, but let's keep them here for
  49. # both TPM versions in case they are implemented in the future for
  50. # version 2.
  51. $tpmc enable
  52. $tpmc activate
  53. }
  54. reset_space () {
  55. local index=$1
  56. local permissions=$2
  57. local size=$3
  58. local bytes="$4"
  59. if ! tpm2_target; then
  60. # definespace is not yet supported for tpm2 (crosbug.com/p/59361), let's
  61. # just rely on the firmware having created the required spaces for now.
  62. if ! $tpmc definespace $index $size $permissions; then
  63. log "could not redefine space $index"
  64. return 1
  65. fi
  66. fi
  67. # do not quote "$bytes", as we mean to expand it here
  68. if ! $tpmc write $index $bytes; then
  69. log "writing to $index failed"
  70. return 1
  71. fi
  72. log "space $index was recreated successfully"
  73. }
  74. restart_daemon_if_needed() {
  75. if [ "$daemon_was_running" = 1 ]; then
  76. log "Restarting ${DAEMON}..."
  77. $initctl start "${DAEMON}" >/dev/null
  78. fi
  79. }
  80. # ------------
  81. # MAIN PROGRAM
  82. # ------------
  83. # Sanity check: are we executing in a recovery image?
  84. if [ -e $dot_recovery ]; then
  85. quit "This is a developer utility, it should never run on a (production) recovery image"
  86. fi
  87. # Did the firmware keep the TPM unlocked?
  88. if ! $($crossystem mainfw_type?recovery); then
  89. quit "You must put a test image on a USB stick and boot it in recovery mode to run this"
  90. fi
  91. if tpm2_target; then
  92. DAEMON="trunksd"
  93. else
  94. DAEMON="tcsd"
  95. fi
  96. # TPM daemon may or may not be running
  97. log "Stopping ${DAEMON}..."
  98. if $initctl stop "${DAEMON}" >/dev/null 2>/dev/null; then
  99. daemon_was_running=1
  100. log "done"
  101. else
  102. daemon_was_running=0
  103. log "(was not running)"
  104. fi
  105. # Is the state of the PP enable flags correct?
  106. if ! tpm2_target; then
  107. if ! ($tpmc getpf | grep -q "physicalPresenceLifetimeLock 1" &&
  108. $tpmc getpf | grep -q "physicalPresenceHWEnable 0" &&
  109. $tpmc getpf | grep -q "physicalPresenceCMDEnable 1"); then
  110. log_tryfix "bad state of physical presence enable flags"
  111. if $tpmc ppfin; then
  112. log "physical presence enable flags are now correctly set"
  113. else
  114. quit "could not set physical presence enable flags"
  115. fi
  116. fi
  117. # Is physical presence turned on?
  118. if $tpmc getvf | grep -q "physicalPresence 0"; then
  119. log_tryfix "physical presence is OFF, expected ON"
  120. # attempt to turn on physical presence
  121. if $tpmc ppon; then
  122. log "physical presence is now on"
  123. else
  124. quit "could not turn physical presence on"
  125. fi
  126. fi
  127. else
  128. if ! $tpmc getvf | grep -q 'phEnable 1'; then
  129. quit "Platform Hierarchy is disabled, TPM can't be recovered"
  130. fi
  131. fi
  132. # I never learned what this does, but it's probably good just in case...
  133. tpm_clear_and_reenable
  134. # Reset firmware and kernel spaces to default (rollback version 1/1)
  135. reset_space 0x1007 0x8001 0xa "02 00 01 00 01 00 00 00 00 4f" || \
  136. log_error "could not fix firmware space"
  137. reset_space 0x1008 0x1 0xd "02 4c 57 52 47 01 00 01 00 00 00 00 55" || \
  138. log_error "could not fix kernel space"
  139. restart_daemon_if_needed
  140. if [ "$err" -eq 0 ]; then
  141. log "TPM has successfully been reset to factory defaults"
  142. else
  143. log_error "TPM was not fully recovered."
  144. exit 1
  145. fi