Home | History | Annotate | Download | only in hardware_TPMCheck
      1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging, re
      6 from autotest_lib.client.bin import test, utils
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.client.cros import service_stopper
      9 
     10 
     11 # Expected results of 'tpmc getX' commands.
     12 TPMC_EXPECTED = {
     13     'getvf': # volatile (ST_CLEAR) flags
     14      set([('deactivated', '0'), ('physicalPresence', '0'),
     15           ('physicalPresenceLock', '1'), ('bGlobalLock', '1')]),
     16     'getpf': # permanent flags
     17      set([('disable', '0'), ('ownership', '1'), ('deactivated', '0'),
     18           ('physicalPresenceHWEnable', '0'), ('physicalPresenceCMDEnable', '1'),
     19           ('physicalPresenceLifetimeLock', '1'), ('nvLocked', '1')])}
     20 
     21 
     22 def missing_firmware_version():
     23     """Check for empty fwid.
     24 
     25     @return True if no fwid else False.
     26     """
     27     cmd = 'crossystem fwid'
     28     return not utils.system_output(cmd, ignore_status=True).strip()
     29 
     30 
     31 def __run_tpmc_cmd(subcommand):
     32     """Make this test more readable by simplifying commonly used tpmc command.
     33 
     34     @param subcommand: String of the tpmc subcommand (getvf, getpf, getp, ...)
     35     @return String output (which may be empty).
     36     """
     37     cmd = 'tpmc %s' % subcommand
     38     return utils.system_output(cmd, ignore_status=True).strip()
     39 
     40 
     41 def check_tpmc(subcommand, expected):
     42     """Runs tpmc command and checks the output against an expected result.
     43 
     44     The expected results take 2 different forms:
     45     1. A regular expression that is matched.
     46     2. A set of tuples that are matched.
     47 
     48     @param subcommand: String of the tpmc subcommand (getvf, getpf, getp, ...)
     49     @param expected: Either a String re or the set of expected tuples.
     50     @raises error.TestError() for invalidly matching expected.
     51     """
     52     error_msg = 'invalid response to tpmc %s' % subcommand
     53     if isinstance(expected, str):
     54         out = __run_tpmc_cmd(subcommand)
     55         if (not re.match(expected, out)):
     56             raise error.TestError('%s: %s' % (error_msg, out))
     57     else:
     58         result_set = utils.set_from_keyval_output(__run_tpmc_cmd(subcommand))
     59         if set(expected) <= result_set:
     60             return
     61         raise error.TestError('%s: expected=%s.' %
     62                               (error_msg, sorted(set(expected) - result_set)))
     63 
     64 
     65 class hardware_TPMCheck(test.test):
     66     """Check that the state of the TPM is as expected."""
     67     version = 1
     68 
     69 
     70     def initialize(self):
     71         # Must stop the TCSD process to be able to collect TPM status,
     72         # then restart TCSD process to leave system in a known good state.
     73         # Must also stop services which depend on tcsd.
     74         self._services = service_stopper.ServiceStopper(['cryptohomed',
     75                                                          'chapsd', 'tcsd'])
     76         self._services.stop_services()
     77 
     78 
     79     def run_once(self):
     80         """Run a few TPM state checks."""
     81         if missing_firmware_version():
     82             logging.warning('no firmware version, skipping test')
     83             return
     84 
     85         # Check volatile and permanent flags
     86         for subcommand in ['getvf', 'getpf']:
     87             check_tpmc(subcommand, TPMC_EXPECTED[subcommand])
     88 
     89         # Check space permissions
     90         check_tpmc('getp 0x1007', '.*0x8001')
     91         check_tpmc('getp 0x1008', '.*0x1')
     92 
     93         # Check kernel space UID
     94         check_tpmc('read 0x1008 0x5', '.* 4c 57 52 47$')
     95 
     96 
     97     def cleanup(self):
     98         self._services.restore_services()
     99