| OLD | NEW |
| 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import logging | 5 import logging |
| 6 import mmap | 6 import mmap |
| 7 import os | 7 import os |
| 8 import time | 8 import time |
| 9 from autotest_lib.client.bin import os_dep, test | 9 from autotest_lib.client.bin import os_dep, test |
| 10 from autotest_lib.client.common_lib import error, utils | 10 from autotest_lib.client.common_lib import error, utils |
| 11 | 11 |
| 12 """ a wrapper for using verity/dm-verity with a test backing store """ | 12 """ a wrapper for using verity/dm-verity with a test backing store """ |
| 13 | 13 |
| 14 # enum for the 3 possible values of the module parameter. | 14 # enum for the 3 possible values of the module parameter. |
| 15 ERROR_BEHAVIOR_ERROR = 'eio' | 15 ERROR_BEHAVIOR_ERROR = 'eio' |
| 16 ERROR_BEHAVIOR_REBOOT = 'panic' | 16 ERROR_BEHAVIOR_REBOOT = 'panic' |
| 17 ERROR_BEHAVIOR_IGNORE = 'none' | 17 ERROR_BEHAVIOR_IGNORE = 'none' |
| 18 ERROR_BEHAVIOR_NOTIFIER = 'notify' # for platform specific behavior. | 18 ERROR_BEHAVIOR_NOTIFIER = 'notify' # for platform specific behavior. |
| 19 | 19 |
| 20 # Default configuration for verity_image | 20 # Default configuration for verity_image |
| 21 DEFAULT_TARGET_NAME = 'verity_image' | 21 DEFAULT_TARGET_NAME = 'verity_image' |
| 22 DEFAULT_DEPTH = 1 | |
| 23 DEFAULT_ALG = 'sha1' | 22 DEFAULT_ALG = 'sha1' |
| 24 DEFAULT_IMAGE_SIZE_IN_BLOCKS = 100 | 23 DEFAULT_IMAGE_SIZE_IN_BLOCKS = 100 |
| 25 DEFAULT_ERROR_BEHAVIOR = ERROR_BEHAVIOR_ERROR | 24 DEFAULT_ERROR_BEHAVIOR = ERROR_BEHAVIOR_ERROR |
| 26 # TODO(wad) make this configurable when dm-verity doesn't hard-code 4096. | 25 # TODO(wad) make this configurable when dm-verity doesn't hard-code 4096. |
| 27 BLOCK_SIZE = 4096 | 26 BLOCK_SIZE = 4096 |
| 28 | 27 |
| 29 class verity_image(object): | 28 class verity_image(object): |
| 30 """ a helper for creating dm-verity targets for testing. | 29 """ a helper for creating dm-verity targets for testing. |
| 31 | 30 |
| 32 To use, | 31 To use, |
| 33 vi = verity_image() | 32 vi = verity_image() |
| 34 vi.initialize(self.tmpdir, "dmveritytesta") | 33 vi.initialize(self.tmpdir, "dmveritytesta") |
| 35 # Create a 409600 byte image with /bin/ls on it | 34 # Create a 409600 byte image with /bin/ls on it |
| 36 # The size in bytes is returned. | 35 # The size in bytes is returned. |
| 37 backing_path = vi.create_backing_image(100, copy_files=['/bin/ls']) | 36 backing_path = vi.create_backing_image(100, copy_files=['/bin/ls']) |
| 38 # Performs hashing of the backing_path and sets up a device. | 37 # Performs hashing of the backing_path and sets up a device. |
| 39 loop_dev = vi.prepare_backing_device() | 38 loop_dev = vi.prepare_backing_device() |
| 40 # Sets up the mapped device and returns the path: | 39 # Sets up the mapped device and returns the path: |
| 41 # E.g., /dev/mapper/autotest_dmveritytesta | 40 # E.g., /dev/mapper/autotest_dmveritytesta |
| 42 dev = vi.create_verity_device() | 41 dev = vi.create_verity_device() |
| 43 # Access the mapped device using the returned string. | 42 # Access the mapped device using the returned string. |
| 44 | 43 |
| 45 TODO(wad) add direct verified and backing store access functions | 44 TODO(wad) add direct verified and backing store access functions |
| 46 to make writing modifiers easier (e.g., mmap). | 45 to make writing modifiers easier (e.g., mmap). |
| 47 """ | 46 """ |
| 48 # Define the command template constants. | 47 # Define the command template constants. |
| 49 verity_cmd = 'verity create %d %s %s %d %s' | 48 verity_cmd = 'verity create 0 %s %s %d %s' |
| 50 dd_cmd = 'dd if=/dev/zero of=%s bs=4096 count=0 seek=%d' | 49 dd_cmd = 'dd if=/dev/zero of=%s bs=4096 count=0 seek=%d' |
| 51 mkfs_cmd = 'mkfs.ext3 -b 4096 -F %s' | 50 mkfs_cmd = 'mkfs.ext3 -b 4096 -F %s' |
| 52 dmsetup_cmd = "dmsetup -r create autotest_%s --table '%s'" | 51 dmsetup_cmd = "dmsetup -r create autotest_%s --table '%s'" |
| 53 | 52 |
| 54 def reset(self): | 53 def reset(self): |
| 55 """Idempotent call which will free any claimed system resources""" | 54 """Idempotent call which will free any claimed system resources""" |
| 56 # Pre-initialize these values to None | 55 # Pre-initialize these values to None |
| 57 for attr in ['mountpoint', 'device', 'loop', 'file', 'hash_file']: | 56 for attr in ['mountpoint', 'device', 'loop', 'file', 'hash_file']: |
| 58 if not hasattr(self, attr): | 57 if not hasattr(self, attr): |
| 59 setattr(self, attr, None) | 58 setattr(self, attr, None) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 74 | 73 |
| 75 if self.file is not None: | 74 if self.file is not None: |
| 76 os.remove(self.file) | 75 os.remove(self.file) |
| 77 self.file = None | 76 self.file = None |
| 78 | 77 |
| 79 if self.hash_file is not None: | 78 if self.hash_file is not None: |
| 80 os.remove(self.hash_file) | 79 os.remove(self.hash_file) |
| 81 self.hash_file = None | 80 self.hash_file = None |
| 82 | 81 |
| 83 self.alg = DEFAULT_ALG | 82 self.alg = DEFAULT_ALG |
| 84 self.depth = DEFAULT_DEPTH | |
| 85 self.error_behavior = DEFAULT_ERROR_BEHAVIOR | 83 self.error_behavior = DEFAULT_ERROR_BEHAVIOR |
| 86 self.blocks = DEFAULT_IMAGE_SIZE_IN_BLOCKS | 84 self.blocks = DEFAULT_IMAGE_SIZE_IN_BLOCKS |
| 87 self.file = None | 85 self.file = None |
| 88 self.has_fs = False | 86 self.has_fs = False |
| 89 self.hash_file = None | 87 self.hash_file = None |
| 90 self.table = None | 88 self.table = None |
| 91 self.target_name = DEFAULT_TARGET_NAME | 89 self.target_name = DEFAULT_TARGET_NAME |
| 92 | 90 |
| 93 self.__initialized = False | 91 self.__initialized = False |
| 94 | 92 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 109 def _create_fs(self, copy_files): | 107 def _create_fs(self, copy_files): |
| 110 """sets up ext3 on the image""" | 108 """sets up ext3 on the image""" |
| 111 self.has_fs = True | 109 self.has_fs = True |
| 112 utils.system(self.mkfs_cmd % self.file) | 110 utils.system(self.mkfs_cmd % self.file) |
| 113 if type(copy_files) is list: | 111 if type(copy_files) is list: |
| 114 for file in copy_files: | 112 for file in copy_files: |
| 115 pass # TODO(wad) | 113 pass # TODO(wad) |
| 116 | 114 |
| 117 def _hash_image(self): | 115 def _hash_image(self): |
| 118 """runs verity over the image and saves the device mapper table""" | 116 """runs verity over the image and saves the device mapper table""" |
| 119 self.table = utils.system_output(self.verity_cmd % (self.depth, | 117 self.table = utils.system_output(self.verity_cmd % (self.alg, |
| 120 self.alg, | |
| 121 self.file, | 118 self.file, |
| 122 self.blocks, | 119 self.blocks, |
| 123 self.hash_file)) | 120 self.hash_file)) |
| 124 # The verity tool doesn't include a templated error value. | 121 # The verity tool doesn't include a templated error value. |
| 125 # For now, we add one. | 122 # For now, we add one. |
| 126 self.table += " ERROR_BEHAVIOR" | 123 self.table += " ERROR_BEHAVIOR" |
| 127 logging.info("table is %s" % self.table) | 124 logging.info("table is %s" % self.table) |
| 128 | 125 |
| 129 def _append_hash(self): | 126 def _append_hash(self): |
| 130 # TODO(wad) use native python file I/O | 127 # TODO(wad) use native python file I/O |
| 131 utils.system('cat %s >> %s' % (self.hash_file, self.file)) | 128 utils.system('cat %s >> %s' % (self.hash_file, self.file)) |
| 132 | 129 |
| 133 def _setup_loop(self): | 130 def _setup_loop(self): |
| 134 # Setup a loop device | 131 # Setup a loop device |
| 135 self.loop = utils.system_output('losetup -f') | 132 self.loop = utils.system_output('losetup -f') |
| 136 utils.system('losetup %s %s' % (self.loop, self.file)) | 133 utils.system('losetup %s %s' % (self.loop, self.file)) |
| 137 | 134 |
| 138 def _setup_target(self): | 135 def _setup_target(self): |
| 139 # Update the table with the loop dev | 136 # Update the table with the loop dev |
| 140 self.table = self.table.replace('HASH_DEV', self.loop) | 137 self.table = self.table.replace('HASH_DEV', self.loop) |
| 141 self.table = self.table.replace('ROOT_DEV', self.loop) | 138 self.table = self.table.replace('ROOT_DEV', self.loop) |
| 142 self.table = self.table.replace('ERROR_BEHAVIOR', self.error_behavior) | 139 self.table = self.table.replace('ERROR_BEHAVIOR', self.error_behavior) |
| 143 | 140 |
| 144 utils.system(self.dmsetup_cmd % (self.target_name, self.table)) | 141 utils.system(self.dmsetup_cmd % (self.target_name, self.table)) |
| 145 self.device = "/dev/mapper/autotest_%s" % self.target_name | 142 self.device = "/dev/mapper/autotest_%s" % self.target_name |
| 146 | 143 |
| 147 def initialize(self, | 144 def initialize(self, |
| 148 tmpdir, | 145 tmpdir, |
| 149 target_name, | 146 target_name, |
| 150 depth=DEFAULT_DEPTH, | |
| 151 alg=DEFAULT_ALG, | 147 alg=DEFAULT_ALG, |
| 152 size_in_blocks=DEFAULT_IMAGE_SIZE_IN_BLOCKS, | 148 size_in_blocks=DEFAULT_IMAGE_SIZE_IN_BLOCKS, |
| 153 error_behavior=DEFAULT_ERROR_BEHAVIOR): | 149 error_behavior=DEFAULT_ERROR_BEHAVIOR): |
| 154 """Performs any required system-level initialization before use. | 150 """Performs any required system-level initialization before use. |
| 155 """ | 151 """ |
| 156 try: | 152 try: |
| 157 os_dep.commands('losetup', 'mkfs.ext3', 'dmsetup', 'verity', 'dd', | 153 os_dep.commands('losetup', 'mkfs.ext3', 'dmsetup', 'verity', 'dd', |
| 158 'dumpe2fs') | 154 'dumpe2fs') |
| 159 except ValueError, e: | 155 except ValueError, e: |
| 160 logging.error('verity_image cannot be used without: %s' % e) | 156 logging.error('verity_image cannot be used without: %s' % e) |
| 161 return False | 157 return False |
| 162 | 158 |
| 163 # Used for the mapper device name and the tmpfile names. | 159 # Used for the mapper device name and the tmpfile names. |
| 164 self.target_name = target_name | 160 self.target_name = target_name |
| 165 | 161 |
| 166 # Reserve some files to use. | 162 # Reserve some files to use. |
| 167 self.file = os.tempnam(tmpdir, '%s.img.' % self.target_name) | 163 self.file = os.tempnam(tmpdir, '%s.img.' % self.target_name) |
| 168 self.hash_file = os.tempnam(tmpdir, '%s.hash.' % self.target_name) | 164 self.hash_file = os.tempnam(tmpdir, '%s.hash.' % self.target_name) |
| 169 | 165 |
| 170 # Set up the configurable bits. | 166 # Set up the configurable bits. |
| 171 self.alg = alg | 167 self.alg = alg |
| 172 self.depth = depth | |
| 173 self.error_behavior = error_behavior | 168 self.error_behavior = error_behavior |
| 174 self.blocks = size_in_blocks | 169 self.blocks = size_in_blocks |
| 175 | 170 |
| 176 self.__initialized = True | 171 self.__initialized = True |
| 177 return True | 172 return True |
| 178 | 173 |
| 179 def create_backing_image(self, size_in_blocks, with_fs=True, | 174 def create_backing_image(self, size_in_blocks, with_fs=True, |
| 180 copy_files=None): | 175 copy_files=None): |
| 181 """Creates an image file of the given number of blocks and if specified | 176 """Creates an image file of the given number of blocks and if specified |
| 182 will create a filesystem and copy any files in a copy_files list to | 177 will create a filesystem and copy any files in a copy_files list to |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 | 253 |
| 259 mapped_dev = self.verity.create_verity_device() | 254 mapped_dev = self.verity.create_verity_device() |
| 260 | 255 |
| 261 # Now check for failure. | 256 # Now check for failure. |
| 262 if self.verity.verifiable() is not expected: | 257 if self.verity.verifiable() is not expected: |
| 263 raise error.TestFail( | 258 raise error.TestFail( |
| 264 '%s: verity.verifiable() not as expected (%s)' % | 259 '%s: verity.verifiable() not as expected (%s)' % |
| 265 (modifier.__name__, expected)) | 260 (modifier.__name__, expected)) |
| 266 tries += 1 | 261 tries += 1 |
| 267 | 262 |
| OLD | NEW |