blob: 5f619ec79a49a12a3ab00f01dada5218ee5623bd [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
58 def test_ValidateVerifiedBootImages_bootImage(self):
59 input_tmp = common.MakeTempDir()
60 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
61 boot_image = os.path.join(input_tmp, 'IMAGES', 'boot.img')
62 self._generate_boot_image(boot_image)
63
64 info_dict = {
65 'boot_signer' : 'true',
66 }
67 options = {
68 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
69 }
70 ValidateVerifiedBootImages(input_tmp, info_dict, options)
71
72 def test_ValidateVerifiedBootImages_bootImage_wrongKey(self):
73 input_tmp = common.MakeTempDir()
74 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
75 boot_image = os.path.join(input_tmp, 'IMAGES', 'boot.img')
76 self._generate_boot_image(boot_image)
77
78 info_dict = {
79 'boot_signer' : 'true',
80 }
81 options = {
82 'verity_key' : os.path.join(self.testdata_dir, 'verity.x509.pem'),
83 }
84 self.assertRaises(
85 AssertionError, ValidateVerifiedBootImages, input_tmp, info_dict,
86 options)
87
88 def test_ValidateVerifiedBootImages_bootImage_corrupted(self):
89 input_tmp = common.MakeTempDir()
90 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
91 boot_image = os.path.join(input_tmp, 'IMAGES', 'boot.img')
92 self._generate_boot_image(boot_image)
93
94 # Corrupt the late byte of the image.
95 with open(boot_image, 'r+b') as boot_fp:
96 boot_fp.seek(-1, os.SEEK_END)
97 last_byte = boot_fp.read(1)
98 last_byte = chr(255 - ord(last_byte))
99 boot_fp.seek(-1, os.SEEK_END)
100 boot_fp.write(last_byte)
101
102 info_dict = {
103 'boot_signer' : 'true',
104 }
105 options = {
106 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
107 }
108 self.assertRaises(
109 AssertionError, ValidateVerifiedBootImages, input_tmp, info_dict,
110 options)
111
xunchangc0f77ee2019-02-20 15:03:43 -0800112 def _generate_system_image(self, output_file, system_root=None,
113 file_map=None):
Tao Bao7549e5e2018-10-03 14:23:59 -0700114 prop_dict = {
115 'partition_size': str(1024 * 1024),
116 'verity': 'true',
117 'verity_block_device': '/dev/block/system',
118 'verity_key' : os.path.join(self.testdata_dir, 'testkey'),
119 'verity_fec': "true",
120 'verity_signer_cmd': 'verity_signer',
121 }
122 verity_image_builder = CreateVerityImageBuilder(prop_dict)
123 image_size = verity_image_builder.CalculateMaxImageSize()
Tao Baoba557702018-03-10 20:41:16 -0800124
125 # Use an empty root directory.
xunchangc0f77ee2019-02-20 15:03:43 -0800126 if not system_root:
127 system_root = common.MakeTempDir()
Tianjie Xu57332222018-08-15 16:16:21 -0700128 cmd = ['mkuserimg_mke2fs', '-s', system_root, output_file, 'ext4',
Tao Bao35f4ebc2018-09-27 15:31:11 -0700129 '/system', str(image_size), '-j', '0']
xunchangc0f77ee2019-02-20 15:03:43 -0800130 if file_map:
131 cmd.extend(['-B', file_map])
Tao Bao73dd4f42018-10-04 16:25:33 -0700132 proc = common.Run(cmd)
Tao Baoba557702018-03-10 20:41:16 -0800133 stdoutdata, _ = proc.communicate()
134 self.assertEqual(
135 0, proc.returncode,
Tianjie Xu57332222018-08-15 16:16:21 -0700136 "Failed to create system image with mkuserimg_mke2fs: {}".format(
Tao Baoba557702018-03-10 20:41:16 -0800137 stdoutdata))
138
139 # Append the verity metadata.
Tao Bao7549e5e2018-10-03 14:23:59 -0700140 verity_image_builder.Build(output_file)
Tao Baoba557702018-03-10 20:41:16 -0800141
142 def test_ValidateVerifiedBootImages_systemImage(self):
143 input_tmp = common.MakeTempDir()
144 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
145 system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
146 self._generate_system_image(system_image)
147
148 # Pack the verity key.
149 verity_key_mincrypt = os.path.join(
150 input_tmp, 'BOOT', 'RAMDISK', 'verity_key')
151 os.makedirs(os.path.dirname(verity_key_mincrypt))
152 shutil.copyfile(
153 os.path.join(self.testdata_dir, 'testkey_mincrypt'),
154 verity_key_mincrypt)
155
156 info_dict = {
157 'verity' : 'true',
158 }
159 options = {
160 'verity_key' : os.path.join(self.testdata_dir, 'testkey.x509.pem'),
161 'verity_key_mincrypt' : verity_key_mincrypt,
162 }
163 ValidateVerifiedBootImages(input_tmp, info_dict, options)
xunchangc0f77ee2019-02-20 15:03:43 -0800164
165 def test_ValidateFileConsistency_incompleteRange(self):
166 input_tmp = common.MakeTempDir()
167 os.mkdir(os.path.join(input_tmp, 'IMAGES'))
168 system_image = os.path.join(input_tmp, 'IMAGES', 'system.img')
169 system_root = os.path.join(input_tmp, "SYSTEM")
170 os.mkdir(system_root)
171
172 # Write the test file that contain multiple blocks of zeros, and these
173 # zero blocks will be omitted by kernel. And the test files will occupy one
174 # block range each in the final system image.
175 with open(os.path.join(system_root, 'a'), 'w') as f:
176 f.write("aaa")
177 f.write('\0' * 4096 * 3)
178 with open(os.path.join(system_root, 'b'), 'w') as f:
179 f.write("bbb")
180 f.write('\0' * 4096 * 3)
181
182 raw_file_map = os.path.join(input_tmp, 'IMAGES', 'raw_system.map')
183 self._generate_system_image(system_image, system_root, raw_file_map)
184
185 # Parse the generated file map and update the block ranges for each file.
186 file_map_list = {}
187 image_ranges = RangeSet()
188 with open(raw_file_map, 'r') as f:
189 for line in f.readlines():
190 info = line.split()
191 self.assertEqual(2, len(info))
192 image_ranges = image_ranges.union(RangeSet(info[1]))
193 file_map_list[info[0]] = RangeSet(info[1])
194
195 # Add one unoccupied block as the shared block for all test files.
196 mock_shared_block = RangeSet("10-20").subtract(image_ranges).first(1)
197 with open(os.path.join(input_tmp, 'IMAGES', 'system.map'), 'w') as f:
198 for key in sorted(file_map_list.keys()):
199 line = "{} {}\n".format(
200 key, file_map_list[key].union(mock_shared_block))
201 f.write(line)
202
203 # Prepare for the target zip file
204 input_file = common.MakeTempFile()
205 all_entries = ['SYSTEM/', 'SYSTEM/b', 'SYSTEM/a', 'IMAGES/',
206 'IMAGES/system.map', 'IMAGES/system.img']
207 with zipfile.ZipFile(input_file, 'w') as input_zip:
208 for name in all_entries:
209 input_zip.write(os.path.join(input_tmp, name), arcname=name)
210
211 input_zip = zipfile.ZipFile(input_file, 'r')
212 info_dict = {'extfs_sparse_flag': '-s'}
213
214 # Expect the validation to pass and both files are skipped due to
215 # 'incomplete' block range.
216 ValidateFileConsistency(input_zip, input_tmp, info_dict)