1# 2# Copyright (C) 2018 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17"""Unittests for verity_utils.py.""" 18 19import copy 20import math 21import os.path 22import random 23 24import common 25import sparse_img 26from rangelib import RangeSet 27from test_utils import ( 28 get_testdata_dir, ReleaseToolsTestCase, SkipIfExternalToolsUnavailable) 29from verity_utils import ( 30 CalculateVbmetaDigest, CreateVerityImageBuilder) 31 32BLOCK_SIZE = common.BLOCK_SIZE 33 34 35class VerifiedBootVersion2VerityImageBuilderTest(ReleaseToolsTestCase): 36 37 DEFAULT_PROP_DICT = { 38 'partition_size': str(4096 * 1024), 39 'partition_name': 'system', 40 'avb_avbtool': 'avbtool', 41 'avb_hashtree_enable': 'true', 42 'avb_add_hashtree_footer_args': '', 43 } 44 45 def test_init(self): 46 prop_dict = copy.deepcopy(self.DEFAULT_PROP_DICT) 47 verity_image_builder = CreateVerityImageBuilder(prop_dict) 48 self.assertIsNotNone(verity_image_builder) 49 self.assertEqual(2, verity_image_builder.version) 50 51 def test_init_MissingProps(self): 52 prop_dict = copy.deepcopy(self.DEFAULT_PROP_DICT) 53 del prop_dict['avb_hashtree_enable'] 54 verity_image_builder = CreateVerityImageBuilder(prop_dict) 55 self.assertIsNone(verity_image_builder) 56 57 @SkipIfExternalToolsUnavailable() 58 def test_Build(self): 59 prop_dict = copy.deepcopy(self.DEFAULT_PROP_DICT) 60 verity_image_builder = CreateVerityImageBuilder(prop_dict) 61 self.assertIsNotNone(verity_image_builder) 62 self.assertEqual(2, verity_image_builder.version) 63 64 input_dir = common.MakeTempDir() 65 image_dir = common.MakeTempDir() 66 system_image = os.path.join(image_dir, 'system.img') 67 system_image_size = verity_image_builder.CalculateMaxImageSize() 68 cmd = ['mkuserimg_mke2fs', input_dir, system_image, 'ext4', '/system', 69 str(system_image_size), '-j', '0', '-s'] 70 common.RunAndCheckOutput(cmd) 71 verity_image_builder.Build(system_image) 72 73 # Additionally make vbmeta image so that we can verify with avbtool. 74 vbmeta_image = os.path.join(image_dir, 'vbmeta.img') 75 cmd = ['avbtool', 'make_vbmeta_image', '--include_descriptors_from_image', 76 system_image, '--output', vbmeta_image] 77 common.RunAndCheckOutput(cmd) 78 79 # Verify the verity metadata. 80 cmd = ['avbtool', 'verify_image', '--image', vbmeta_image] 81 common.RunAndCheckOutput(cmd) 82 83 def _test_CalculateMinPartitionSize_SetUp(self): 84 # To test CalculateMinPartitionSize(), by using 200MB to 2GB image size. 85 # - 51200 = 200MB * 1024 * 1024 / 4096 86 # - 524288 = 2GB * 1024 * 1024 * 1024 / 4096 87 image_sizes = [BLOCK_SIZE * random.randint(51200, 524288) + offset 88 for offset in range(BLOCK_SIZE)] 89 90 prop_dict = { 91 'partition_size': None, 92 'partition_name': 'system', 93 'avb_avbtool': 'avbtool', 94 'avb_hashtree_enable': 'true', 95 'avb_add_hashtree_footer_args': None, 96 } 97 builder = CreateVerityImageBuilder(prop_dict) 98 self.assertEqual(2, builder.version) 99 return image_sizes, builder 100 101 def test_CalculateMinPartitionSize_LinearFooterSize(self): 102 """Tests with footer size which is linear to partition size.""" 103 image_sizes, builder = self._test_CalculateMinPartitionSize_SetUp() 104 for image_size in image_sizes: 105 for ratio in 0.95, 0.56, 0.22: 106 expected_size = common.RoundUpTo4K(int(math.ceil(image_size / ratio))) 107 self.assertEqual( 108 expected_size, 109 builder.CalculateMinPartitionSize( 110 image_size, lambda x, ratio=ratio: int(x * ratio))) 111 112 def test_AVBCalcMinPartitionSize_SlowerGrowthFooterSize(self): 113 """Tests with footer size which grows slower than partition size.""" 114 115 def _SizeCalculator(partition_size): 116 """Footer size is the power of 0.95 of partition size.""" 117 # Minus footer size to return max image size. 118 return partition_size - int(math.pow(partition_size, 0.95)) 119 120 image_sizes, builder = self._test_CalculateMinPartitionSize_SetUp() 121 for image_size in image_sizes: 122 min_partition_size = builder.CalculateMinPartitionSize( 123 image_size, _SizeCalculator) 124 # Checks min_partition_size can accommodate image_size. 125 self.assertGreaterEqual( 126 _SizeCalculator(min_partition_size), 127 image_size) 128 # Checks min_partition_size (round to BLOCK_SIZE) is the minimum. 129 self.assertLess( 130 _SizeCalculator(min_partition_size - BLOCK_SIZE), 131 image_size) 132 133 def test_CalculateMinPartitionSize_FasterGrowthFooterSize(self): 134 """Tests with footer size which grows faster than partition size.""" 135 136 def _SizeCalculator(partition_size): 137 """Max image size is the power of 0.95 of partition size.""" 138 # Max image size grows less than partition size, which means 139 # footer size grows faster than partition size. 140 return int(math.pow(partition_size, 0.95)) 141 142 image_sizes, builder = self._test_CalculateMinPartitionSize_SetUp() 143 for image_size in image_sizes: 144 min_partition_size = builder.CalculateMinPartitionSize( 145 image_size, _SizeCalculator) 146 # Checks min_partition_size can accommodate image_size. 147 self.assertGreaterEqual( 148 _SizeCalculator(min_partition_size), 149 image_size) 150 # Checks min_partition_size (round to BLOCK_SIZE) is the minimum. 151 self.assertLess( 152 _SizeCalculator(min_partition_size - BLOCK_SIZE), 153 image_size) 154 155 @SkipIfExternalToolsUnavailable() 156 def test_CalculateVbmetaDigest(self): 157 prop_dict = copy.deepcopy(self.DEFAULT_PROP_DICT) 158 verity_image_builder = CreateVerityImageBuilder(prop_dict) 159 self.assertEqual(2, verity_image_builder.version) 160 161 input_dir = common.MakeTempDir() 162 image_dir = common.MakeTempDir() 163 os.mkdir(os.path.join(image_dir, 'IMAGES')) 164 system_image = os.path.join(image_dir, 'IMAGES', 'system.img') 165 system_image_size = verity_image_builder.CalculateMaxImageSize() 166 cmd = ['mkuserimg_mke2fs', input_dir, system_image, 'ext4', '/system', 167 str(system_image_size), '-j', '0', '-s'] 168 common.RunAndCheckOutput(cmd) 169 verity_image_builder.Build(system_image) 170 171 # Additionally make vbmeta image 172 vbmeta_image = os.path.join(image_dir, 'IMAGES', 'vbmeta.img') 173 cmd = ['avbtool', 'make_vbmeta_image', '--include_descriptors_from_image', 174 system_image, '--output', vbmeta_image] 175 common.RunAndCheckOutput(cmd) 176 177 # Verify the verity metadata. 178 cmd = ['avbtool', 'verify_image', '--image', vbmeta_image] 179 common.RunAndCheckOutput(cmd) 180 digest = CalculateVbmetaDigest(image_dir, 'avbtool') 181 self.assertIsNotNone(digest) 182