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