1# Copyright (c) 2011 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 logging
6import os
7import struct
8from autotest_lib.client.common_lib import error, utils
9from autotest_lib.client.cros import verity_utils
10
11class platform_DMVerityBitCorruption(verity_utils.VerityImageTest):
12    version = 1
13
14    _adjustment = 0
15    _mask = 0x80
16
17    def mod_tweak_block(self, run_count, backing_path, block_size,
18                            block_count):
19        logging.info('mod_tweak_block(%d, %s, %d, %d)' % (
20                     run_count, backing_path, block_size, block_count))
21        run_count = run_count % block_count
22        with open(backing_path, 'r+b') as dev:
23            dev.seek(run_count * block_size + self._adjustment)
24            (byte,) = struct.unpack('B', dev.read(1))  # Get raw byte value.
25            dev.seek(run_count * block_size + self._adjustment)
26            dev.write(struct.pack('B', byte ^ self._mask))
27
28
29    def mod_tweak_hash_block(self, run_count, backing_path, block_size,
30                             block_count):
31        logging.info('mod_tweak_hash_block(%d, %s, %d, %d)' % (
32                     run_count, backing_path, block_size, block_count))
33        with open(backing_path, 'r+b') as dev:
34            # move to the start of the appropriate hash block
35            dev.seek(block_count * block_size, os.SEEK_SET)
36            dev.seek(run_count * block_size + self._adjustment, os.SEEK_CUR)
37            (byte,) = struct.unpack('B', dev.read(1))
38            # return to the start of the appropriate hash block
39            dev.seek(block_count * block_size, os.SEEK_SET)
40            dev.seek(run_count * block_size + self._adjustment, os.SEEK_CUR)
41            dev.write(struct.pack('B', byte ^ self._mask))
42
43
44    def run_once(self, bit_loc='first'):
45        if bit_loc == 'first':
46            pass
47        elif bit_loc == 'last':
48            self._adjustment = verity_utils.BLOCK_SIZE - 1
49            self._mask = 0x01
50        elif bit_loc == 'middle':
51            self._adjustment = verity_utils.BLOCK_SIZE/2
52        else:
53            raise error.TestError('bit_loc must be first, last, or middle')
54
55        # Corrupt the |bit_loc| bit of each block (on a per-block basis).
56        self.mod_and_test(self.mod_tweak_block, self.image_blocks, False)
57
58        # Repeat except on each block in the hash tree data.
59        hash_blocks = (os.path.getsize(self.verity.hash_file) /
60                       verity_utils.BLOCK_SIZE)
61        self.mod_and_test(self.mod_tweak_hash_block, hash_blocks, False)
62