# 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()