verity_utils.py revision 8f94e349991500eb18e000a69be963075339a03e
1b6d2993fb77f771a886c41ace0850773f5498bedbarfab@chromium.org# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 28ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry# Use of this source code is governed by a BSD-style license that can be 38ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry# found in the LICENSE file. 48ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 5b6d2993fb77f771a886c41ace0850773f5498bedbarfab@chromium.orgimport logging, mmap, os, time 6b6d2993fb77f771a886c41ace0850773f5498bedbarfab@chromium.org 7b6d2993fb77f771a886c41ace0850773f5498bedbarfab@chromium.orgimport common 88ec34006ec1b024fde7d2804df237fde4a15a347Will Drewryfrom autotest_lib.client.bin import os_dep, test 95dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masonefrom autotest_lib.client.common_lib import error, logging_manager, utils 108ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 118ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry""" a wrapper for using verity/dm-verity with a test backing store """ 128ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 138ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry# enum for the 3 possible values of the module parameter. 142ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will DrewryERROR_BEHAVIOR_ERROR = 'eio' 152ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will DrewryERROR_BEHAVIOR_REBOOT = 'panic' 162ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will DrewryERROR_BEHAVIOR_IGNORE = 'none' 172ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will DrewryERROR_BEHAVIOR_NOTIFIER = 'notify' # for platform specific behavior. 188ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 198ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry# Default configuration for verity_image 208ec34006ec1b024fde7d2804df237fde4a15a347Will DrewryDEFAULT_TARGET_NAME = 'verity_image' 212ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will DrewryDEFAULT_ALG = 'sha1' 228ec34006ec1b024fde7d2804df237fde4a15a347Will DrewryDEFAULT_IMAGE_SIZE_IN_BLOCKS = 100 232ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will DrewryDEFAULT_ERROR_BEHAVIOR = ERROR_BEHAVIOR_ERROR 248ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry# TODO(wad) make this configurable when dm-verity doesn't hard-code 4096. 258ec34006ec1b024fde7d2804df237fde4a15a347Will DrewryBLOCK_SIZE = 4096 268ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 275dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masonedef system(command, timeout=None): 285dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone """Delegate to utils.system to run |command|, logs stderr only on fail. 295dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone 305dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone Runs |command|, captures stdout and stderr. Logs stdout to the DEBUG 315dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone log no matter what, logs stderr only if the command actually fails. 325dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone Will time the command out after |timeout|. 335dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone """ 345dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone utils.run(command, timeout=timeout, ignore_status=False, 355dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone stdout_tee=utils.TEE_TO_LOGS, stderr_tee=utils.TEE_TO_LOGS, 365dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone stderr_is_expected=True) 375dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone 388ec34006ec1b024fde7d2804df237fde4a15a347Will Drewryclass verity_image(object): 398ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ a helper for creating dm-verity targets for testing. 408ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 418ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry To use, 428ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry vi = verity_image() 438ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry vi.initialize(self.tmpdir, "dmveritytesta") 448ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Create a 409600 byte image with /bin/ls on it 458ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # The size in bytes is returned. 468ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry backing_path = vi.create_backing_image(100, copy_files=['/bin/ls']) 478ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Performs hashing of the backing_path and sets up a device. 488ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry loop_dev = vi.prepare_backing_device() 498ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Sets up the mapped device and returns the path: 508ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # E.g., /dev/mapper/autotest_dmveritytesta 518ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry dev = vi.create_verity_device() 528ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Access the mapped device using the returned string. 538ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 548ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry TODO(wad) add direct verified and backing store access functions 558ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry to make writing modifiers easier (e.g., mmap). 568ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ 578ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Define the command template constants. 588c5e9811506282a54c487d20b33f7a1928c33db8Elly Jones verity_cmd = \ 598c5e9811506282a54c487d20b33f7a1928c33db8Elly Jones 'verity mode=create alg=%s payload=%s payload_blocks=%d hashtree=%s' 608ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry dd_cmd = 'dd if=/dev/zero of=%s bs=4096 count=0 seek=%d' 618ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry mkfs_cmd = 'mkfs.ext3 -b 4096 -F %s' 628ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry dmsetup_cmd = "dmsetup -r create autotest_%s --table '%s'" 638ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 64e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook def _device_release(self, cmd, device): 65e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook if utils.system(cmd, ignore_status=True) == 0: 66e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook return 6704be2bd5e4666a5c253e9c30ab20555e04286032Ilja H. Friedel logging.warning("Could not release %s. Retrying..." % (device)) 68e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook # Other things (like cros-disks) may have the device open briefly, 69e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook # so if we initially fail, try again and attempt to gather details 70e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook # on who else is using the device. 71e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook fuser = utils.system_output('fuser -v %s' % (device), 728f94e349991500eb18e000a69be963075339a03eFilipe Brandenburger retain_output=True, 738f94e349991500eb18e000a69be963075339a03eFilipe Brandenburger ignore_status=True) 74e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook lsblk = utils.system_output('lsblk %s' % (device), 758f94e349991500eb18e000a69be963075339a03eFilipe Brandenburger retain_output=True, 768f94e349991500eb18e000a69be963075339a03eFilipe Brandenburger ignore_status=True) 77e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook time.sleep(1) 78e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook if utils.system(cmd, ignore_status=True) == 0: 79e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook return 80e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook raise error.TestFail('"%s" failed: %s\n%s' % (cmd, fuser, lsblk)) 81e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook 828ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def reset(self): 838ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Idempotent call which will free any claimed system resources""" 848ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Pre-initialize these values to None 858ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry for attr in ['mountpoint', 'device', 'loop', 'file', 'hash_file']: 868ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if not hasattr(self, attr): 878ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry setattr(self, attr, None) 888ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry logging.info("verity_image is being reset") 898ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 908ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.mountpoint is not None: 915dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone system('umount %s' % self.mountpoint) 928ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.mountpoint = None 938ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 948ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.device is not None: 95e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook self._device_release('dmsetup remove %s' % (self.device), 96e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook self.device) 978ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.device = None 988ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 998ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.loop is not None: 100e627b22187d158ca3a41bc182c7c7a363dd86120Kees Cook self._device_release('losetup -d %s' % (self.loop), self.loop) 1018ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.loop = None 1028ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1038ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.file is not None: 1048ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry os.remove(self.file) 1058ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.file = None 1068ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1078ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.hash_file is not None: 1088ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry os.remove(self.hash_file) 1098ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.hash_file = None 1108ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1118ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.alg = DEFAULT_ALG 1122ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.error_behavior = DEFAULT_ERROR_BEHAVIOR 1132ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.blocks = DEFAULT_IMAGE_SIZE_IN_BLOCKS 1148ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.file = None 1152ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.has_fs = False 1168ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.hash_file = None 1178ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.table = None 1188ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.target_name = DEFAULT_TARGET_NAME 1198ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1208ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.__initialized = False 1218ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1228ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def __init__(self): 1238ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Sets up the defaults for the object and then calls reset() 1248ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ 1258ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.reset() 1268ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1278ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def __del__(self): 1288ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Release any and all system resources. 1298ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.reset() 1308ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1318ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def _create_image(self): 1328ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Creates a dummy file.""" 1338ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # TODO(wad) replace with python 1345dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone utils.system_output(self.dd_cmd % (self.file, self.blocks)) 1358ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1368ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def _create_fs(self, copy_files): 1378ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """sets up ext3 on the image""" 1388ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.has_fs = True 1395dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone system(self.mkfs_cmd % self.file) 1408ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if type(copy_files) is list: 1418ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry for file in copy_files: 1428ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry pass # TODO(wad) 1438ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1448ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def _hash_image(self): 1458ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """runs verity over the image and saves the device mapper table""" 146fca525620c114eb9bfb9cf75cab15b98fb7ece92Mandeep Singh Baines self.table = utils.system_output(self.verity_cmd % (self.alg, 1478ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.file, 1488ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.blocks, 1498ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.hash_file)) 1502ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry # The verity tool doesn't include a templated error value. 1512ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry # For now, we add one. 15270857538e86b624564984775b2c4b0a45e086b44Elly Jones self.table += " error_behavior=ERROR_BEHAVIOR" 1538ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry logging.info("table is %s" % self.table) 1548ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1558ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def _append_hash(self): 1565dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone f = open(self.file, 'ab') 1575dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone f.write(utils.read_file(self.hash_file)) 1585dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone f.close() 1598ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1608ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def _setup_loop(self): 1618ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Setup a loop device 16274b3cefa0f2e6cc86dcaa2b0977594d00b93a5a7Kees Cook self.loop = utils.system_output('losetup -f --show %s' % (self.file)) 1638ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1648ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def _setup_target(self): 1658ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Update the table with the loop dev 1668ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.table = self.table.replace('HASH_DEV', self.loop) 1678ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.table = self.table.replace('ROOT_DEV', self.loop) 1682ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.table = self.table.replace('ERROR_BEHAVIOR', self.error_behavior) 1698ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1705dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone system(self.dmsetup_cmd % (self.target_name, self.table)) 1718ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.device = "/dev/mapper/autotest_%s" % self.target_name 1728ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1738ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def initialize(self, 1748ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry tmpdir, 1758ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry target_name, 1768ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry alg=DEFAULT_ALG, 1772ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry size_in_blocks=DEFAULT_IMAGE_SIZE_IN_BLOCKS, 1782ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry error_behavior=DEFAULT_ERROR_BEHAVIOR): 1798ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Performs any required system-level initialization before use. 1808ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ 1818ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry try: 1828ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry os_dep.commands('losetup', 'mkfs.ext3', 'dmsetup', 'verity', 'dd', 1838ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 'dumpe2fs') 1848ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry except ValueError, e: 1858ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry logging.error('verity_image cannot be used without: %s' % e) 1868ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return False 1878ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1888ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Used for the mapper device name and the tmpfile names. 1898ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.target_name = target_name 1908ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1918ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Reserve some files to use. 1928ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.file = os.tempnam(tmpdir, '%s.img.' % self.target_name) 1938ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.hash_file = os.tempnam(tmpdir, '%s.hash.' % self.target_name) 1948ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 1952ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry # Set up the configurable bits. 1962ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.alg = alg 1972ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.error_behavior = error_behavior 1982ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry self.blocks = size_in_blocks 1992ca8207fd236ba44b9b6222a7a4ee6ecae4c2688Will Drewry 2008ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.__initialized = True 2018ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return True 2028ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2038ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def create_backing_image(self, size_in_blocks, with_fs=True, 2048ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry copy_files=None): 2058ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Creates an image file of the given number of blocks and if specified 2068ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry will create a filesystem and copy any files in a copy_files list to 2078ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry the fs. 2088ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ 2098ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.blocks = size_in_blocks 2108ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self._create_image() 2118ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2128ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if with_fs is True: 2138ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self._create_fs(copy_files) 2148ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry else: 2158ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if type(copy_files) is list and len(copy_files) != 0: 21604be2bd5e4666a5c253e9c30ab20555e04286032Ilja H. Friedel logging.warning("verity_image.initialize called with " \ 2178ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry "files to copy but no fs") 2188ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2198ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return self.file 2208ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2218ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def prepare_backing_device(self): 2228ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Hashes the backing image, appends it to the backing image, points 2238ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry a loop device at it and returns the path to the loop.""" 2248ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self._hash_image() 2258ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self._append_hash() 2268ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self._setup_loop() 2278ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return self.loop 2288ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2298ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def create_verity_device(self): 2308ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Sets up the device mapper node and returns its path""" 2318ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self._setup_target() 2328ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return self.device 2338ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2348ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def verifiable(self): 2358ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Returns True if the dm-verity device does not throw any errors 2368ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry when being walked completely or False if it does.""" 2378ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry try: 2388ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.has_fs is True: 2395dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone system('dumpe2fs %s' % self.device) 2408ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # TODO(wad) replace with mmap.mmap-based access 2415dbef89559e3e84dace5b5e55efdcf8e5da8690eChris Masone system('dd if=%s of=/dev/null bs=4096' % self.device) 2428ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return True 2438ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry except error.CmdError, e: 2448ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry return False 2458ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2468ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2478ec34006ec1b024fde7d2804df237fde4a15a347Will Drewryclass VerityImageTest(test.test): 2488ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """VerityImageTest provides a base class for verity_image tests 2498ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry to be derived from. It sets up a verity_image object for use 2508ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry and provides the function mod_and_test() to wrap simple test 2518ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry cases for verity_images. 2528ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2538ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry See platform_DMVerityCorruption as an example usage. 2548ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ 2558ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry version = 1 2568ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry image_blocks = DEFAULT_IMAGE_SIZE_IN_BLOCKS 2578ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2588ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def initialize(self): 2598ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Overrides test.initialize() to setup a verity_image""" 2608ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.verity = verity_image() 2618ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2628ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Example callback for mod_and_test that does nothing 2638ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def mod_nothing(self, run_count, backing_path, block_size, block_count): 2648ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry pass 2658ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2668ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry def mod_and_test(self, modifier, count, expected): 2678ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """Takes in a callback |modifier| and runs it |count| times over 2688ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry the verified image checking for |expected| out of verity.verifiable() 2698ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry """ 2708ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry tries = 0 2718ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry while tries < count: 2728ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Start fresh then modify each block in the image. 2738ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.verity.reset() 2748ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.verity.initialize(self.tmpdir, self.__class__.__name__) 2758ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry backing_path = self.verity.create_backing_image(self.image_blocks) 2768ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry loop_dev = self.verity.prepare_backing_device() 2778ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2788ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry modifier(tries, 2798ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry backing_path, 2808ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry BLOCK_SIZE, 2818ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry self.image_blocks) 2828ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2838ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry mapped_dev = self.verity.create_verity_device() 2848ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry 2858ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry # Now check for failure. 2868ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry if self.verity.verifiable() is not expected: 2878ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry raise error.TestFail( 2888ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry '%s: verity.verifiable() not as expected (%s)' % 2898ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry (modifier.__name__, expected)) 2908ec34006ec1b024fde7d2804df237fde4a15a347Will Drewry tries += 1 291