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# Test the chromeos TPM recovery script by faking the entire execution
7# environment.
8
9rm -rf tpm-recovery-test-workdir
10mkdir  tpm-recovery-test-workdir
11cd     tpm-recovery-test-workdir
12
13test_kind=
14if [ $# -ge 1 ]; then
15  test_kind="$1"
16fi
17
18if [ "$test_kind" != "" -a "$test_kind" != "fake" ]; then
19  echo "$0: usage: $0 [fake]"
20  echo "With fake as the argument, use a simulated TPM instead of the real one"
21fi
22
23if [ "$test_kind" = "fake" ]; then
24  export USR_BIN=.
25  export USR_SBIN=.
26  export USR_LOCAL_BIN=.
27  export USR_LOCAL_SBIN=.
28  export DOT_RECOVERY=.recovery
29  export ACPI_DIR=.
30  ctr=../chromeos-tpm-recovery
31  tpmc=./tpmc
32else
33  ctr=chromeos-tpm-recovery
34  tpmc=tpmc
35fi
36
37# For simplicity, build the permanent environment as if we prepared to run the
38# fake test, even if we're running the test on a real TPM.
39
40echo > .recovery
41echo 3 > BINF.0
42echo 0 > CHSW
43
44export NVRAM_SPACE_OVERHEAD=200
45space_overhead=$NVRAM_SPACE_OVERHEAD
46
47# build tpmc
48cat > tpmc <<"EOF"
49#!/bin/sh -u
50# Fake tpmc program
51
52definespace () {
53  index=$2
54  size=$3
55  permissions=$4
56  space_overhead=$NVRAM_SPACE_OVERHEAD
57
58  if [ -e space.$index.data -a -e tpm-owned ]; then
59    echo "cannot redefine space without auth"
60  fi
61
62  totalsize=$(( $size + $space_overhead ))
63  free=$(cat nvram.freespace)
64
65  if [ $totalsize -gt $free ]; then
66    return 17  # NO_SPACE
67  fi
68
69  if [ $index != 0xf004 ]; then
70    echo $size > space.$index.size
71    echo $permissions > space.$index.perm
72    for i in $(seq 1 $(($size))); do
73      echo -n "ff " >> space.$index.data
74    done
75    echo $(( $free - $totalsize )) > nvram.freespace
76  fi
77  return 0
78}
79
80case $1 in
81
82  clear)
83    rm -f tpm-owned
84  ;;
85
86  enable)
87    # boring
88  ;;
89
90  activate)
91    # boring
92  ;;
93
94  definespace)
95    definespace $*
96  ;;
97
98  getp)
99    echo space blah has permissions $(cat space.$2.perm)
100  ;;
101
102  read)
103    index=$2
104    size=$3
105    maxsize=$(cat space.$index.size)
106    if [ $(($size > $maxsize)) -eq 1  ]; then
107      echo "size $size too large for space (max is $maxsize)"
108      exit 1
109    fi
110    dd if=space.$index.data bs=1 count=$(($3 * 3)) 2> /dev/null
111  ;;
112
113  write)
114    args="$@"
115    index=$2
116    bytes="$(echo $args | sed 's/[^ ]* [^ ]* //')"
117    size=$(echo $bytes | wc -w)
118    maxsize=$(cat space.$index.size)
119    if [ $(($size > $maxsize)) -eq 1  ]; then
120      echo "size $size too large for space (max is $(($maxsize)))"
121      exit 1
122    fi
123    re=$(echo "$bytes " | sed 's/././g')
124    sed "s/$re/$bytes /" < space.$index.data > _tmp_
125    mv _tmp_ space.$index.data
126  ;;
127
128  getpf)
129    echo "disable 0"
130    echo "deactivated 0"
131    echo "nvLocked 1"
132    echo "physicalPresenceLifetimeLock 1"
133    echo "physicalPresenceHWEnable 0"
134    echo "physicalPresenceCMDEnable 1"
135  ;;
136
137  getvf)
138    echo "bGlobalLock 1"
139    echo "physicalPresence 1"
140    echo "physicalPresenceLock 0"
141  ;;
142
143  ppfin)
144    # boring
145  ;;
146
147  ppon)
148    # boring
149  ;;
150
151  *)
152    echo "tpmc: invalid command $1"
153    exit 1
154  ;;
155esac
156
157EOF
158
159# build nvtool
160cat > tpm-nvtool <<"EOF"
161#!/bin/sh -u
162
163space_overhead=$NVRAM_SPACE_OVERHEAD
164
165print_space () {
166  local index=$1
167  printf "# NV Index 0x%08x" $(( $index ))
168  echo " uninteresting random garbage"
169  echo " further random garbage"
170  echo ""
171}
172
173if [ "$1" = "--release" ]; then
174  if [ "$2" != "--index" -o \
175       "$4" != "--owner_password" ]; then
176    echo "sorry, picky tpm-nvtool"
177    exit 1
178  fi
179  index=$3
180  if [ ! -f tpm-owned ]; then
181    echo "tpm is unowned"
182    exit 1
183  fi
184  size=$(cat space.$index.size)
185  free=$(cat nvram.freespace)
186  rm space.$index.*
187  echo $(( $size + $space_overhead + $free )) > nvram.freespace
188elif [ "$1" = "--list" ]; then
189  for s in space.*.data; do
190    print_space $(echo $s | sed -e "s/[^.]*\.//" -e "s/\..*//")
191  done
192fi
193EOF
194
195# build tpm_takeownership
196cat > tpm_takeownership <<"EOF"
197#!/bin/sh -u
198if [ -f tpm-owned ]; then
199  echo "tpm is already owned"
200  exit 1
201fi
202echo > tpm-owned
203EOF
204
205# build tcsd
206cat > tcsd <<"EOF"
207#!/bin/sh -u
208trap "{ rm tcsd_is_running; }" EXIT
209echo > tcsd_is_running
210sleep 365d
211EOF
212
213tcsd_pid=0
214
215start_tcsd () {
216  if [ $tcsd_pid -ne 0 ]; then
217    echo TCSD is already started
218    exit 1
219  fi
220  tcsd -f &
221  tcsd_pid=$!
222  sleep 2
223}
224
225stop_tcsd () {
226  if [ $tcsd_pid -eq 0 ]; then
227    echo TCSD is already stopped
228    exit 1
229  fi
230  kill $tcsd_pid
231  sleep 0.5
232  kill $tcsd_pid > /dev/null 2>&1
233  sleep 0.5
234  wait $tcsd_pid > /dev/null 2>&1  # we trust that tcsd will agree to die
235  tcsd_pid=0
236}
237
238tpm_clear_and_reenable () {
239  tpmc clear
240  tpmc enable
241  tpmc activate
242}
243
244takeownership () {
245  if [ "$test_kind" = "fake" ]; then
246    touch tpm_owned
247  else
248    tpm_clear_and_reenable
249    start_tcsd
250    tpm_takeownership -y -z
251    stop_tcsd
252  fi
253}
254
255remove_chromeos_spaces () {
256  if [ "$test_kind" = "fake" ]; then
257    rm -f space.*
258    echo 1500 > nvram.freespace
259  else
260    takeownership
261    start_tcsd
262    tpm-nvtool --release --index 0x1007 --owner_password ""
263    tpm-nvtool --release --index 0x1008 --owner_password ""
264    stop_tcsd
265    tpm_clear_and_reenable
266  fi
267}
268
269chmod 755 tpmc tpm-nvtool tpm_takeownership tcsd
270
271echo "starting test, results in $(pwd)/log"
272echo "starting TPM recovery test" > log
273
274if ps ax | grep "tcs[d]"; then
275  echo "a tcsd is process appears to be running, please kill it first"
276  exit 1
277fi
278
279# normal run
280test_normal_run () {
281  echo "TEST: normal run" >> log
282
283  remove_chromeos_spaces
284  $tpmc definespace 0x1007 0xa 0x8001
285  $tpmc definespace 0x1008 0xd 0x1
286  $tpmc write 0x1008 01 4c 57 52 47
287  takeownership
288
289  $ctr log
290}
291
292# Kernel space with wrong ID
293test_wrong_id () {
294  echo "TEST: bad kernel space ID" >> log
295
296  remove_chromeos_spaces
297  $tpmc definespace 0x1007 0xa 0x8001
298  $tpmc definespace 0x1008 0xd 0x1
299  takeownership
300
301  $ctr log
302}
303
304# Kernel space with wrong size
305test_wrong_size () {
306  echo "TEST: bad kernel space size" >> log
307
308  remove_chromeos_spaces
309  $tpmc definespace 0x1007 0xa 0x8001
310  $tpmc definespace 0x1008 0xc 0x1
311  takeownership
312
313  $ctr log
314}
315
316# Kernel space with wrong size AND bogus space to exhaust nvram
317test_wrong_size_hog () {
318  echo "TEST: bad kernel space size and no room" >> log
319
320  remove_chromeos_spaces
321  $tpmc definespace 0x1007 0xa 0x8001
322  $tpmc definespace 0x1008 0x1 0x1
323  if [ "$test_kind" = "fake" ]; then
324    space_hog_size=$(( $(cat nvram.freespace) - $space_overhead - 1 ))
325    echo "remaining $(cat nvram.freespace) bytes" >> log
326  else
327    space_hog_size=$(( $(tpm-nvsize) - 2 ))
328  fi
329  echo "hogging $(( $space_hog_size )) bytes" >> log
330  $tpmc definespace 0xcafe $(printf "0x%x" $space_hog_size) 0x1 \
331    || echo "hogging failed!" >> log
332  takeownership
333
334  $ctr log
335}
336
337test_normal_run
338test_wrong_id
339test_wrong_size
340test_wrong_size_hog
341
342echo "test completed" >> log
343echo "test completed"
344