| #!/bin/sh -u | |
| # Copyright (c) 2010 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. | |
| # | |
| # Test the chromeos TPM recovery script by faking the entire execution | |
| # environment. | |
| rm -rf tpm-recovery-test-workdir | |
| mkdir tpm-recovery-test-workdir | |
| cd tpm-recovery-test-workdir | |
| test_kind= | |
| if [ $# -ge 1 ]; then | |
| test_kind="$1" | |
| fi | |
| if [ "$test_kind" != "" -a "$test_kind" != "fake" ]; then | |
| echo "$0: usage: $0 [fake]" | |
| echo "With fake as the argument, use a simulated TPM instead of the real one" | |
| fi | |
| if [ "$test_kind" = "fake" ]; then | |
| export USR_BIN=. | |
| export USR_SBIN=. | |
| export USR_LOCAL_BIN=. | |
| export USR_LOCAL_SBIN=. | |
| export DOT_RECOVERY=.recovery | |
| export ACPI_DIR=. | |
| ctr=../chromeos-tpm-recovery | |
| tpmc=./tpmc | |
| else | |
| ctr=chromeos-tpm-recovery | |
| tpmc=tpmc | |
| fi | |
| # For simplicity, build the permanent environment as if we prepared to run the | |
| # fake test, even if we're running the test on a real TPM. | |
| echo > .recovery | |
| echo 3 > BINF.0 | |
| echo 0 > CHSW | |
| export NVRAM_SPACE_OVERHEAD=200 | |
| space_overhead=$NVRAM_SPACE_OVERHEAD | |
| # build tpmc | |
| cat > tpmc <<"EOF" | |
| #!/bin/sh -u | |
| # Fake tpmc program | |
| definespace () { | |
| index=$2 | |
| size=$3 | |
| permissions=$4 | |
| space_overhead=$NVRAM_SPACE_OVERHEAD | |
| if [ -e space.$index.data -a -e tpm-owned ]; then | |
| echo "cannot redefine space without auth" | |
| fi | |
| totalsize=$(( $size + $space_overhead )) | |
| free=$(cat nvram.freespace) | |
| if [ $totalsize -gt $free ]; then | |
| return 17 # NO_SPACE | |
| fi | |
| if [ $index != 0xf004 ]; then | |
| echo $size > space.$index.size | |
| echo $permissions > space.$index.perm | |
| for i in $(seq 1 $(($size))); do | |
| echo -n "ff " >> space.$index.data | |
| done | |
| echo $(( $free - $totalsize )) > nvram.freespace | |
| fi | |
| return 0 | |
| } | |
| case $1 in | |
| clear) | |
| rm -f tpm-owned | |
| ;; | |
| enable) | |
| # boring | |
| ;; | |
| activate) | |
| # boring | |
| ;; | |
| definespace) | |
| definespace $* | |
| ;; | |
| getp) | |
| echo space blah has permissions $(cat space.$2.perm) | |
| ;; | |
| read) | |
| index=$2 | |
| size=$3 | |
| maxsize=$(cat space.$index.size) | |
| if [ $(($size > $maxsize)) -eq 1 ]; then | |
| echo "size $size too large for space (max is $maxsize)" | |
| exit 1 | |
| fi | |
| dd if=space.$index.data bs=1 count=$(($3 * 3)) 2> /dev/null | |
| ;; | |
| write) | |
| args="$@" | |
| index=$2 | |
| bytes="$(echo $args | sed 's/[^ ]* [^ ]* //')" | |
| size=$(echo $bytes | wc -w) | |
| maxsize=$(cat space.$index.size) | |
| if [ $(($size > $maxsize)) -eq 1 ]; then | |
| echo "size $size too large for space (max is $(($maxsize)))" | |
| exit 1 | |
| fi | |
| re=$(echo "$bytes " | sed 's/././g') | |
| sed "s/$re/$bytes /" < space.$index.data > _tmp_ | |
| mv _tmp_ space.$index.data | |
| ;; | |
| getpf) | |
| echo "disable 0" | |
| echo "deactivated 0" | |
| echo "nvLocked 1" | |
| echo "physicalPresenceLifetimeLock 1" | |
| echo "physicalPresenceHWEnable 0" | |
| echo "physicalPresenceCMDEnable 1" | |
| ;; | |
| getvf) | |
| echo "bGlobalLock 1" | |
| echo "physicalPresence 1" | |
| echo "physicalPresenceLock 0" | |
| ;; | |
| ppfin) | |
| # boring | |
| ;; | |
| ppon) | |
| # boring | |
| ;; | |
| *) | |
| echo "tpmc: invalid command $1" | |
| exit 1 | |
| ;; | |
| esac | |
| EOF | |
| # build nvtool | |
| cat > tpm-nvtool <<"EOF" | |
| #!/bin/sh -u | |
| space_overhead=$NVRAM_SPACE_OVERHEAD | |
| print_space () { | |
| local index=$1 | |
| printf "# NV Index 0x%08x" $(( $index )) | |
| echo " uninteresting random garbage" | |
| echo " further random garbage" | |
| echo "" | |
| } | |
| if [ "$1" = "--release" ]; then | |
| if [ "$2" != "--index" -o \ | |
| "$4" != "--owner_password" ]; then | |
| echo "sorry, picky tpm-nvtool" | |
| exit 1 | |
| fi | |
| index=$3 | |
| if [ ! -f tpm-owned ]; then | |
| echo "tpm is unowned" | |
| exit 1 | |
| fi | |
| size=$(cat space.$index.size) | |
| free=$(cat nvram.freespace) | |
| rm space.$index.* | |
| echo $(( $size + $space_overhead + $free )) > nvram.freespace | |
| elif [ "$1" = "--list" ]; then | |
| for s in space.*.data; do | |
| print_space $(echo $s | sed -e "s/[^.]*\.//" -e "s/\..*//") | |
| done | |
| fi | |
| EOF | |
| # build tpm_takeownership | |
| cat > tpm_takeownership <<"EOF" | |
| #!/bin/sh -u | |
| if [ -f tpm-owned ]; then | |
| echo "tpm is already owned" | |
| exit 1 | |
| fi | |
| echo > tpm-owned | |
| EOF | |
| # build tcsd | |
| cat > tcsd <<"EOF" | |
| #!/bin/sh -u | |
| trap "{ rm tcsd_is_running; }" EXIT | |
| echo > tcsd_is_running | |
| sleep 365d | |
| EOF | |
| tcsd_pid=0 | |
| start_tcsd () { | |
| if [ $tcsd_pid -ne 0 ]; then | |
| echo TCSD is already started | |
| exit 1 | |
| fi | |
| tcsd -f & | |
| tcsd_pid=$! | |
| sleep 2 | |
| } | |
| stop_tcsd () { | |
| if [ $tcsd_pid -eq 0 ]; then | |
| echo TCSD is already stopped | |
| exit 1 | |
| fi | |
| kill $tcsd_pid | |
| sleep 0.5 | |
| kill $tcsd_pid > /dev/null 2>&1 | |
| sleep 0.5 | |
| wait $tcsd_pid > /dev/null 2>&1 # we trust that tcsd will agree to die | |
| tcsd_pid=0 | |
| } | |
| tpm_clear_and_reenable () { | |
| tpmc clear | |
| tpmc enable | |
| tpmc activate | |
| } | |
| takeownership () { | |
| if [ "$test_kind" = "fake" ]; then | |
| touch tpm_owned | |
| else | |
| tpm_clear_and_reenable | |
| start_tcsd | |
| tpm_takeownership -y -z | |
| stop_tcsd | |
| fi | |
| } | |
| remove_chromeos_spaces () { | |
| if [ "$test_kind" = "fake" ]; then | |
| rm -f space.* | |
| echo 1500 > nvram.freespace | |
| else | |
| takeownership | |
| start_tcsd | |
| tpm-nvtool --release --index 0x1007 --owner_password "" | |
| tpm-nvtool --release --index 0x1008 --owner_password "" | |
| stop_tcsd | |
| tpm_clear_and_reenable | |
| fi | |
| } | |
| chmod 755 tpmc tpm-nvtool tpm_takeownership tcsd | |
| echo "starting test, results in $(pwd)/log" | |
| echo "starting TPM recovery test" > log | |
| if ps ax | grep "tcs[d]"; then | |
| echo "a tcsd is process appears to be running, please kill it first" | |
| exit 1 | |
| fi | |
| # normal run | |
| test_normal_run () { | |
| echo "TEST: normal run" >> log | |
| remove_chromeos_spaces | |
| $tpmc definespace 0x1007 0xa 0x8001 | |
| $tpmc definespace 0x1008 0xd 0x1 | |
| $tpmc write 0x1008 01 4c 57 52 47 | |
| takeownership | |
| $ctr log | |
| } | |
| # Kernel space with wrong ID | |
| test_wrong_id () { | |
| echo "TEST: bad kernel space ID" >> log | |
| remove_chromeos_spaces | |
| $tpmc definespace 0x1007 0xa 0x8001 | |
| $tpmc definespace 0x1008 0xd 0x1 | |
| takeownership | |
| $ctr log | |
| } | |
| # Kernel space with wrong size | |
| test_wrong_size () { | |
| echo "TEST: bad kernel space size" >> log | |
| remove_chromeos_spaces | |
| $tpmc definespace 0x1007 0xa 0x8001 | |
| $tpmc definespace 0x1008 0xc 0x1 | |
| takeownership | |
| $ctr log | |
| } | |
| # Kernel space with wrong size AND bogus space to exhaust nvram | |
| test_wrong_size_hog () { | |
| echo "TEST: bad kernel space size and no room" >> log | |
| remove_chromeos_spaces | |
| $tpmc definespace 0x1007 0xa 0x8001 | |
| $tpmc definespace 0x1008 0x1 0x1 | |
| if [ "$test_kind" = "fake" ]; then | |
| space_hog_size=$(( $(cat nvram.freespace) - $space_overhead - 1 )) | |
| echo "remaining $(cat nvram.freespace) bytes" >> log | |
| else | |
| space_hog_size=$(( $(tpm-nvsize) - 2 )) | |
| fi | |
| echo "hogging $(( $space_hog_size )) bytes" >> log | |
| $tpmc definespace 0xcafe $(printf "%#x" $space_hog_size) 0x1 \ | |
| || echo "hogging failed!" >> log | |
| takeownership | |
| $ctr log | |
| } | |
| test_normal_run | |
| test_wrong_id | |
| test_wrong_size | |
| test_wrong_size_hog | |
| echo "test completed" >> log | |
| echo "test completed" |