blob: 9c816eb4169b572a7f6435b1c05bb923d1deef44 [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 Baoc9981932019-09-16 12:10:43 -0700146 def test_ValidateVerifiedBootImages_systemRootImage(self):
Tao Baoba557702018-03-10 20:41:16 -0800147 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.
Tao Baoc9981932019-09-16 12:10:43 -0700153 verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
Tao Baoba557702018-03-10 20:41:16 -0800154 os.makedirs(os.path.dirname(verity_key_mincrypt))
155 shutil.copyfile(
156 os.path.join(self.testdata_dir, 'testkey_mincrypt'),
157 verity_key_mincrypt)
158
159 info_dict = {
Tao Baoc9981932019-09-16 12:10:43 -0700160 'system_root_image' : 'true',
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)
168
169 @test_utils.SkipIfExternalToolsUnavailable()
170 def test_ValidateVerifiedBootImages_nonSystemRootImage(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 self._generate_system_image(system_image)
175
176 # Pack the verity key into the root dir in system.img.
177 verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
178 os.makedirs(os.path.dirname(verity_key_mincrypt))
179 shutil.copyfile(
180 os.path.join(self.testdata_dir, 'testkey_mincrypt'),
181 verity_key_mincrypt)
182
183 # And a copy in ramdisk.
184 verity_key_ramdisk = os.path.join(
185 input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
186 os.makedirs(os.path.dirname(verity_key_ramdisk))
187 shutil.copyfile(
188 os.path.join(self.testdata_dir, 'testkey_mincrypt'),
189 verity_key_ramdisk)
190
191 info_dict = {
Tao Baoba557702018-03-10 20:41:16 -0800192 'verity' : 'true',
193 }
194 options = {
195 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
196 'verity_key_mincrypt' : verity_key_mincrypt,
197 }
198 ValidateVerifiedBootImages(input_tmp, info_dict, options)
xunchangc0f77ee2019-02-20 15:03:43 -0800199
Tao Bao82490d32019-04-09 00:12:30 -0700200 @test_utils.SkipIfExternalToolsUnavailable()
Tao Baoc9981932019-09-16 12:10:43 -0700201 def test_ValidateVerifiedBootImages_nonSystemRootImage_mismatchingKeys(self):
202 input_tmp = common.MakeTempDir()
203 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
204 system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
205 self._generate_system_image(system_image)
206
207 # Pack the verity key into the root dir in system.img.
208 verity_key_mincrypt = os.path.join(input_tmp, 'ROOT', 'verity_key')
209 os.makedirs(os.path.dirname(verity_key_mincrypt))
210 shutil.copyfile(
211 os.path.join(self.testdata_dir, 'testkey_mincrypt'),
212 verity_key_mincrypt)
213
214 # And an invalid copy in ramdisk.
215 verity_key_ramdisk = os.path.join(
216 input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
217 os.makedirs(os.path.dirname(verity_key_ramdisk))
218 shutil.copyfile(
219 os.path.join(self.testdata_dir, 'verity_mincrypt'),
220 verity_key_ramdisk)
221
222 info_dict = {
223 'verity' : 'true',
224 }
225 options = {
226 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
227 'verity_key_mincrypt' : verity_key_mincrypt,
228 }
229 self.assertRaises(
230 AssertionError, ValidateVerifiedBootImages, input_tmp, info_dict,
231 options)
232
233 @test_utils.SkipIfExternalToolsUnavailable()
xunchangc0f77ee2019-02-20 15:03:43 -0800234 def test_ValidateFileConsistency_incompleteRange(self):
235 input_tmp = common.MakeTempDir()
236 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
237 system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
238 system_root = os.path.join(input_tmp, "SYSTEM")
239 os.mkdir(system_root)
240
241 # Write the test file that contain multiple blocks of zeros, and these
242 # zero blocks will be omitted by kernel. And the test files will occupy one
243 # block range each in the final system image.
244 with open(os.path.join(system_root, 'a'), 'w') as f:
245 f.write("aaa")
246 f.write('\0' * 4096 * 3)
247 with open(os.path.join(system_root, 'b'), 'w') as f:
248 f.write("bbb")
249 f.write('\0' * 4096 * 3)
250
251 raw_file_map = os.path.join(input_tmp, 'IMAGES', 'raw_system.map')
252 self._generate_system_image(system_image, system_root, raw_file_map)
253
254 # Parse the generated file map and update the block ranges for each file.
255 file_map_list = {}
256 image_ranges = RangeSet()
257 with open(raw_file_map, 'r') as f:
258 for line in f.readlines():
259 info = line.split()
260 self.assertEqual(2, len(info))
261 image_ranges = image_ranges.union(RangeSet(info[1]))
262 file_map_list[info[0]] = RangeSet(info[1])
263
264 # Add one unoccupied block as the shared block for all test files.
265 mock_shared_block = RangeSet("10-20").subtract(image_ranges).first(1)
266 with open(os.path.join(input_tmp, 'IMAGES', 'system.map'), 'w') as f:
267 for key in sorted(file_map_list.keys()):
268 line = "{} {}\n".format(
269 key, file_map_list[key].union(mock_shared_block))
270 f.write(line)
271
272 # Prepare for the target zip file
273 input_file = common.MakeTempFile()
274 all_entries = ['SYSTEM/', 'SYSTEM/b', 'SYSTEM/a', 'IMAGES/',
275 'IMAGES/system.map', 'IMAGES/system.img']
276 with zipfile.ZipFile(input_file, 'w') as input_zip:
277 for name in all_entries:
278 input_zip.write(os.path.join(input_tmp, name), arcname=name)
279
280 input_zip = zipfile.ZipFile(input_file, 'r')
281 info_dict = {'extfs_sparse_flag': '-s'}
282
283 # Expect the validation to pass and both files are skipped due to
284 # 'incomplete' block range.
285 ValidateFileConsistency(input_zip, input_tmp, info_dict)