1# Copyright (c) 2014 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
5import contextlib
6import time
7
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.common_lib.cros import tpm_utils
10from autotest_lib.server import autotest, test
11
12@contextlib.contextmanager
13def ensure_tpm_reset(client):
14    """This context manager ensures we clears the TPM and restore the system to
15    a reasonable state at the end of the test, even when an error occurs.
16    """
17    try:
18        yield
19    finally:
20        tpm_utils.ClearTPMOwnerRequest(client)
21
22class platform_CompromisedStatefulPartition(test.test):
23    """Tests how the system recovers with the corrupted stateful partition.
24    """
25    version = 2
26
27    CMD_CORRUPT = 'rm -fr /mnt/stateful_partition/*.*'
28    OOBE_FILE = '/home/chronos/.oobe_completed'
29    _WAIT_DELAY = 2
30    FILES_LIST = [
31        '/mnt/stateful_partition/dev_image',
32        '/mnt/stateful_partition/encrypted.block',
33        '/mnt/stateful_partition/unencrypted',
34    ]
35    ENCRYPTION_KEY_FILES = [
36        '/mnt/stateful_partition/encrypted.key',
37        '/mnt/stateful_partition/encrypted.needs-finalization',
38    ]
39
40    def _test_stateful_corruption(self, autotest_client, host, client_test):
41        """Corrupts the stateful partition and reboots; checks if the client
42        goes through OOBE again and if encstateful is recreated.
43        """
44        if not host.run(self.CMD_CORRUPT,
45                        ignore_status=True).exit_status == 0:
46            raise error.TestFail('Unable to corrupt stateful partition')
47        host.run('sync', ignore_status=True)
48        time.sleep(self._WAIT_DELAY)
49        host.reboot()
50        host.run('sync', ignore_status=True)
51        time.sleep(self._WAIT_DELAY)
52        if host.path_exists(self.OOBE_FILE):
53            raise error.TestFail('Did not get OOBE screen after '
54                                 'rebooting the device with '
55                                 'corrupted statefull partition')
56        autotest_client.run_test(client_test,
57                                 exit_without_logout=True)
58        time.sleep(self._WAIT_DELAY)
59        for new_file in self.FILES_LIST:
60            if not host.path_exists(new_file):
61                raise error.TestFail('%s is missing after rebooting '
62                                     'the device with corrupted '
63                                     'stateful partition' % new_file)
64        encryption_key_exists = False
65        for encryption_key_file in self.ENCRYPTION_KEY_FILES:
66            if host.path_exists(encryption_key_file):
67                encryption_key_exists = True
68        if encryption_key_exists is False:
69            raise error.TestFail('An encryption key is missing after '
70                                 'rebooting the device with corrupted stateful '
71                                 'partition')
72
73    def run_once(self, host, client_test):
74        """This test verify that user should get OOBE after booting
75        the device with corrupted stateful partition.
76        Test fails if not able to recover the device with corrupted
77        stateful partition.
78        TPM is reset at the end to restore the system to a reasonable state.
79        """
80        if host.get_board_type() == 'OTHER':
81            raise error.TestNAError('Test can not processed on OTHER board '
82                                    'type devices')
83        autotest_client = autotest.Autotest(host)
84        host.reboot()
85        autotest_client.run_test(client_test,
86                                 exit_without_logout=True)
87        with ensure_tpm_reset(host):
88            self._test_stateful_corruption(autotest_client, host, client_test)
89