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