blob: 0f0d773c6a0b5590ad591fc9f6ca758bc7194363 [file] [log] [blame]
Tao Baoba557702018-03-10 20:41:16 -08001#
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
Tao Baob4ec6d72018-03-15 23:21:28 -070017"""Unittests for validate_target_files.py."""
Tao Baoba557702018-03-10 20:41:16 -080018
Tao Baoba557702018-03-10 20:41:16 -080019import os
20import os.path
21import shutil
xunchangc0f77ee2019-02-20 15:03:43 -080022import zipfile
Tao Baoba557702018-03-10 20:41:16 -080023
Tao Baoba557702018-03-10 20:41:16 -080024import common
25import test_utils
xunchangc0f77ee2019-02-20 15:03:43 -080026from rangelib import RangeSet
27from validate_target_files import (ValidateVerifiedBootImages,
28 ValidateFileConsistency)
Tao Bao7549e5e2018-10-03 14:23:59 -070029from verity_utils import CreateVerityImageBuilder
Tao Baoba557702018-03-10 20:41:16 -080030
31
Tao Bao65b94e92018-10-11 21:57:26 -070032class ValidateTargetFilesTest(test_utils.ReleaseToolsTestCase):
Tao Baoba557702018-03-10 20:41:16 -080033
34 def setUp(self):
35 self.testdata_dir = test_utils.get_testdata_dir()
36
Tao Baoba557702018-03-10 20:41:16 -080037 def _generate_boot_image(self, output_file):
38 kernel = common.MakeTempFile(prefix='kernel-')
39 with open(kernel, 'wb') as kernel_fp:
40 kernel_fp.write(os.urandom(10))
41
42 cmd = ['mkbootimg', '--kernel', kernel, '-o', output_file]
Tao Bao73dd4f42018-10-04 16:25:33 -070043 proc = common.Run(cmd)
Tao Baoba557702018-03-10 20:41:16 -080044 stdoutdata, _ = proc.communicate()
45 self.assertEqual(
46 0, proc.returncode,
47 "Failed to run mkbootimg: {}".format(stdoutdata))
48
49 cmd = ['boot_signer', '/boot', output_file,
50 os.path.join(self.testdata_dir, 'testkey.pk8'),
51 os.path.join(self.testdata_dir, 'testkey.x509.pem'), output_file]
Tao Bao73dd4f42018-10-04 16:25:33 -070052 proc = common.Run(cmd)
Tao Baoba557702018-03-10 20:41:16 -080053 stdoutdata, _ = proc.communicate()
54 self.assertEqual(
55 0, proc.returncode,
56 "Failed to sign boot image with boot_signer: {}".format(stdoutdata))
57
Tao Bao82490d32019-04-09 00:12:30 -070058 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoba557702018-03-10 20:41:16 -080059 def test_ValidateVerifiedBootImages_bootImage(self):
60 input_tmp = common.MakeTempDir()
61 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
62 boot_image = os.path.join(input_tmp, 'IMAGES', 'boot.img')
63 self._generate_boot_image(boot_image)
64
65 info_dict = {
66 'boot_signer' : 'true',
67 }
68 options = {
69 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
70 }
71 ValidateVerifiedBootImages(input_tmp, info_dict, options)
72
Tao Bao82490d32019-04-09 00:12:30 -070073 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoba557702018-03-10 20:41:16 -080074 def test_ValidateVerifiedBootImages_bootImage_wrongKey(self):
75 input_tmp = common.MakeTempDir()
76 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
77 boot_image = os.path.join(input_tmp, 'IMAGES', 'boot.img')
78 self._generate_boot_image(boot_image)
79
80 info_dict = {
81 'boot_signer' : 'true',
82 }
83 options = {
84 'verity_key' : os.path.join(self.testdata_dir, 'verity.x509.pem'),
85 }
86 self.assertRaises(
87 AssertionError, ValidateVerifiedBootImages, input_tmp, info_dict,
88 options)
89
Tao Bao82490d32019-04-09 00:12:30 -070090 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoba557702018-03-10 20:41:16 -080091 def test_ValidateVerifiedBootImages_bootImage_corrupted(self):
92 input_tmp = common.MakeTempDir()
93 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
94 boot_image = os.path.join(input_tmp, 'IMAGES', 'boot.img')
95 self._generate_boot_image(boot_image)
96
97 # Corrupt the late byte of the image.
98 with open(boot_image, 'r+b') as boot_fp:
99 boot_fp.seek(-1, os.SEEK_END)
100 last_byte = boot_fp.read(1)
Tao Baoa3705452019-06-24 15:33:41 -0700101 last_byte = bytes([255 - ord(last_byte)])
Tao Baoba557702018-03-10 20:41:16 -0800102 boot_fp.seek(-1, os.SEEK_END)
103 boot_fp.write(last_byte)
104
105 info_dict = {
106 'boot_signer' : 'true',
107 }
108 options = {
109 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
110 }
111 self.assertRaises(
112 AssertionError, ValidateVerifiedBootImages, input_tmp, info_dict,
113 options)
114
xunchangc0f77ee2019-02-20 15:03:43 -0800115 def _generate_system_image(self, output_file, system_root=None,
116 file_map=None):
Tao Bao7549e5e2018-10-03 14:23:59 -0700117 prop_dict = {
118 'partition_size': str(1024 * 1024),
119 'verity': 'true',
120 'verity_block_device': '/dev/block/system',
121 'verity_key' : os.path.join(self.testdata_dir, 'testkey'),
122 'verity_fec': "true",
123 'verity_signer_cmd': 'verity_signer',
124 }
125 verity_image_builder = CreateVerityImageBuilder(prop_dict)
126 image_size = verity_image_builder.CalculateMaxImageSize()
Tao Baoba557702018-03-10 20:41:16 -0800127
128 # Use an empty root directory.
xunchangc0f77ee2019-02-20 15:03:43 -0800129 if not system_root:
130 system_root = common.MakeTempDir()
Tianjie Xu57332222018-08-15 16:16:21 -0700131 cmd = ['mkuserimg_mke2fs', '-s', system_root, output_file, 'ext4',
Tao Bao35f4ebc2018-09-27 15:31:11 -0700132 '/system', str(image_size), '-j', '0']
xunchangc0f77ee2019-02-20 15:03:43 -0800133 if file_map:
134 cmd.extend(['-B', file_map])
Tao Bao73dd4f42018-10-04 16:25:33 -0700135 proc = common.Run(cmd)
Tao Baoba557702018-03-10 20:41:16 -0800136 stdoutdata, _ = proc.communicate()
137 self.assertEqual(
138 0, proc.returncode,
Tianjie Xu57332222018-08-15 16:16:21 -0700139 "Failed to create system image with mkuserimg_mke2fs: {}".format(
Tao Baoba557702018-03-10 20:41:16 -0800140 stdoutdata))
141
142 # Append the verity metadata.
Tao Bao7549e5e2018-10-03 14:23:59 -0700143 verity_image_builder.Build(output_file)
Tao Baoba557702018-03-10 20:41:16 -0800144
Tao Bao82490d32019-04-09 00:12:30 -0700145 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoba557702018-03-10 20:41:16 -0800146 def test_ValidateVerifiedBootImages_systemImage(self):
147 input_tmp = common.MakeTempDir()
148 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
149 system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
150 self._generate_system_image(system_image)
151
152 # Pack the verity key.
153 verity_key_mincrypt = os.path.join(
154 input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
155 os.makedirs(os.path.dirname(verity_key_mincrypt))
156 shutil.copyfile(
157 os.path.join(self.testdata_dir, 'testkey_mincrypt'),
158 verity_key_mincrypt)
159
160 info_dict = {
161 'verity' : 'true',
162 }
163 options = {
164 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
165 'verity_key_mincrypt' : verity_key_mincrypt,
166 }
167 ValidateVerifiedBootImages(input_tmp, info_dict, options)
xunchangc0f77ee2019-02-20 15:03:43 -0800168
Tao Bao82490d32019-04-09 00:12:30 -0700169 @test_utils.SkipIfExternalToolsUnavailable()
xunchangc0f77ee2019-02-20 15:03:43 -0800170 def test_ValidateFileConsistency_incompleteRange(self):
171 input_tmp = common.MakeTempDir()
172 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
173 system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
174 system_root = os.path.join(input_tmp, "SYSTEM")
175 os.mkdir(system_root)
176
177 # Write the test file that contain multiple blocks of zeros, and these
178 # zero blocks will be omitted by kernel. And the test files will occupy one
179 # block range each in the final system image.
180 with open(os.path.join(system_root, 'a'), 'w') as f:
181 f.write("aaa")
182 f.write('\0' * 4096 * 3)
183 with open(os.path.join(system_root, 'b'), 'w') as f:
184 f.write("bbb")
185 f.write('\0' * 4096 * 3)
186
187 raw_file_map = os.path.join(input_tmp, 'IMAGES', 'raw_system.map')
188 self._generate_system_image(system_image, system_root, raw_file_map)
189
190 # Parse the generated file map and update the block ranges for each file.
191 file_map_list = {}
192 image_ranges = RangeSet()
193 with open(raw_file_map, 'r') as f:
194 for line in f.readlines():
195 info = line.split()
196 self.assertEqual(2, len(info))
197 image_ranges = image_ranges.union(RangeSet(info[1]))
198 file_map_list[info[0]] = RangeSet(info[1])
199
200 # Add one unoccupied block as the shared block for all test files.
201 mock_shared_block = RangeSet("10-20").subtract(image_ranges).first(1)
202 with open(os.path.join(input_tmp, 'IMAGES', 'system.map'), 'w') as f:
203 for key in sorted(file_map_list.keys()):
204 line = "{} {}\n".format(
205 key, file_map_list[key].union(mock_shared_block))
206 f.write(line)
207
208 # Prepare for the target zip file
209 input_file = common.MakeTempFile()
210 all_entries = ['SYSTEM/', 'SYSTEM/b', 'SYSTEM/a', 'IMAGES/',
211 'IMAGES/system.map', 'IMAGES/system.img']
212 with zipfile.ZipFile(input_file, 'w') as input_zip:
213 for name in all_entries:
214 input_zip.write(os.path.join(input_tmp, name), arcname=name)
215
216 input_zip = zipfile.ZipFile(input_file, 'r')
217 info_dict = {'extfs_sparse_flag': '-s'}
218
219 # Expect the validation to pass and both files are skipped due to
220 # 'incomplete' block range.
221 ValidateFileConsistency(input_zip, input_tmp, info_dict)