| #!/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" |