# 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. import logging, re from autotest_lib.client.bin import test, utils from autotest_lib.client.common_lib import error from autotest_lib.client.cros import service_stopper # Expected results of 'tpmc getX' commands. TPMC_EXPECTED = { 'getvf': # volatile (ST_CLEAR) flags set([('deactivated', '0'), ('physicalPresence', '0'), ('physicalPresenceLock', '1'), ('bGlobalLock', '1')]), 'getpf': # permanent flags set([('disable', '0'), ('ownership', '1'), ('deactivated', '0'), ('physicalPresenceHWEnable', '0'), ('physicalPresenceCMDEnable', '1'), ('physicalPresenceLifetimeLock', '1'), ('nvLocked', '1')])} def missing_firmware_version(): """Check for empty fwid. @return True if no fwid else False. """ cmd = 'crossystem fwid' return not utils.system_output(cmd, ignore_status=True).strip() def __run_tpmc_cmd(subcommand): """Make this test more readable by simplifying commonly used tpmc command. @param subcommand: String of the tpmc subcommand (getvf, getpf, getp, ...) @return String output (which may be empty). """ cmd = 'tpmc %s' % subcommand return utils.system_output(cmd, ignore_status=True).strip() def check_tpmc(subcommand, expected): """Runs tpmc command and checks the output against an expected result. The expected results take 2 different forms: 1. A regular expression that is matched. 2. A set of tuples that are matched. @param subcommand: String of the tpmc subcommand (getvf, getpf, getp, ...) @param expected: Either a String re or the set of expected tuples. @raises error.TestError() for invalidly matching expected. """ error_msg = 'invalid response to tpmc %s' % subcommand if isinstance(expected, str): out = __run_tpmc_cmd(subcommand) if (not re.match(expected, out)): raise error.TestError('%s: %s' % (error_msg, out)) else: result_set = utils.set_from_keyval_output(__run_tpmc_cmd(subcommand)) if set(expected) <= result_set: return raise error.TestError('%s: expected=%s.' % (error_msg, sorted(set(expected) - result_set))) class hardware_TPMCheck(test.test): """Check that the state of the TPM is as expected.""" version = 1 def initialize(self): # Must stop the TCSD process to be able to collect TPM status, # then restart TCSD process to leave system in a known good state. # Must also stop services which depend on tcsd. self._services = service_stopper.ServiceStopper(['cryptohomed', 'chapsd', 'tcsd']) self._services.stop_services() def run_once(self): """Run a few TPM state checks.""" if missing_firmware_version(): logging.warning('no firmware version, skipping test') return # Check volatile and permanent flags for subcommand in ['getvf', 'getpf']: check_tpmc(subcommand, TPMC_EXPECTED[subcommand]) # Check space permissions check_tpmc('getp 0x1007', '.*0x8001') check_tpmc('getp 0x1008', '.*0x1') # Check kernel space UID check_tpmc('read 0x1008 0x5', '.* 4c 57 52 47$') def cleanup(self): self._services.restore_services()