1 /*
2 * Copyright (C) 2017 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 agree 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 #include <stdio.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21
22 #include <string>
23 #include <vector>
24
25 #include <android-base/file.h>
26 #include <android-base/properties.h>
27 #include <android-base/strings.h>
28 #include <android-base/test_utils.h>
29 #include <gtest/gtest.h>
30 #include <vintf/VintfObjectRecovery.h>
31 #include <ziparchive/zip_archive.h>
32 #include <ziparchive/zip_writer.h>
33
34 #include "install.h"
35 #include "private/install.h"
36
TEST(InstallTest,verify_package_compatibility_no_entry)37 TEST(InstallTest, verify_package_compatibility_no_entry) {
38 TemporaryFile temp_file;
39 FILE* zip_file = fdopen(temp_file.fd, "w");
40 ZipWriter writer(zip_file);
41 // The archive must have something to be opened correctly.
42 ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
43 ASSERT_EQ(0, writer.FinishEntry());
44 ASSERT_EQ(0, writer.Finish());
45 ASSERT_EQ(0, fclose(zip_file));
46
47 // Doesn't contain compatibility zip entry.
48 ZipArchiveHandle zip;
49 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
50 ASSERT_TRUE(verify_package_compatibility(zip));
51 CloseArchive(zip);
52 }
53
TEST(InstallTest,verify_package_compatibility_invalid_entry)54 TEST(InstallTest, verify_package_compatibility_invalid_entry) {
55 TemporaryFile temp_file;
56 FILE* zip_file = fdopen(temp_file.fd, "w");
57 ZipWriter writer(zip_file);
58 ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0));
59 ASSERT_EQ(0, writer.FinishEntry());
60 ASSERT_EQ(0, writer.Finish());
61 ASSERT_EQ(0, fclose(zip_file));
62
63 // Empty compatibility zip entry.
64 ZipArchiveHandle zip;
65 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
66 ASSERT_FALSE(verify_package_compatibility(zip));
67 CloseArchive(zip);
68 }
69
TEST(InstallTest,read_metadata_from_package_smoke)70 TEST(InstallTest, read_metadata_from_package_smoke) {
71 TemporaryFile temp_file;
72 FILE* zip_file = fdopen(temp_file.fd, "w");
73 ZipWriter writer(zip_file);
74 ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
75 const std::string content("abcdefg");
76 ASSERT_EQ(0, writer.WriteBytes(content.data(), content.size()));
77 ASSERT_EQ(0, writer.FinishEntry());
78 ASSERT_EQ(0, writer.Finish());
79 ASSERT_EQ(0, fclose(zip_file));
80
81 ZipArchiveHandle zip;
82 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
83 std::string metadata;
84 ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
85 ASSERT_EQ(content, metadata);
86 CloseArchive(zip);
87
88 TemporaryFile temp_file2;
89 FILE* zip_file2 = fdopen(temp_file2.fd, "w");
90 ZipWriter writer2(zip_file2);
91 ASSERT_EQ(0, writer2.StartEntry("META-INF/com/android/metadata", kCompressDeflated));
92 ASSERT_EQ(0, writer2.WriteBytes(content.data(), content.size()));
93 ASSERT_EQ(0, writer2.FinishEntry());
94 ASSERT_EQ(0, writer2.Finish());
95 ASSERT_EQ(0, fclose(zip_file2));
96
97 ASSERT_EQ(0, OpenArchive(temp_file2.path, &zip));
98 metadata.clear();
99 ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
100 ASSERT_EQ(content, metadata);
101 CloseArchive(zip);
102 }
103
TEST(InstallTest,read_metadata_from_package_no_entry)104 TEST(InstallTest, read_metadata_from_package_no_entry) {
105 TemporaryFile temp_file;
106 FILE* zip_file = fdopen(temp_file.fd, "w");
107 ZipWriter writer(zip_file);
108 ASSERT_EQ(0, writer.StartEntry("dummy_entry", kCompressStored));
109 ASSERT_EQ(0, writer.FinishEntry());
110 ASSERT_EQ(0, writer.Finish());
111 ASSERT_EQ(0, fclose(zip_file));
112
113 ZipArchiveHandle zip;
114 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
115 std::string metadata;
116 ASSERT_FALSE(read_metadata_from_package(zip, &metadata));
117 CloseArchive(zip);
118 }
119
TEST(InstallTest,verify_package_compatibility_with_libvintf_malformed_xml)120 TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) {
121 TemporaryFile compatibility_zip_file;
122 FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w");
123 ZipWriter compatibility_zip_writer(compatibility_zip);
124 ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
125 std::string malformed_xml = "malformed";
126 ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(malformed_xml.data(), malformed_xml.size()));
127 ASSERT_EQ(0, compatibility_zip_writer.FinishEntry());
128 ASSERT_EQ(0, compatibility_zip_writer.Finish());
129 ASSERT_EQ(0, fclose(compatibility_zip));
130
131 TemporaryFile temp_file;
132 FILE* zip_file = fdopen(temp_file.fd, "w");
133 ZipWriter writer(zip_file);
134 ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
135 std::string compatibility_zip_content;
136 ASSERT_TRUE(
137 android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
138 ASSERT_EQ(0,
139 writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size()));
140 ASSERT_EQ(0, writer.FinishEntry());
141 ASSERT_EQ(0, writer.Finish());
142 ASSERT_EQ(0, fclose(zip_file));
143
144 ZipArchiveHandle zip;
145 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
146 std::vector<std::string> compatibility_info;
147 compatibility_info.push_back(malformed_xml);
148 // Malformed compatibility zip is expected to be rejected by libvintf. But we defer that to
149 // libvintf.
150 std::string err;
151 bool result =
152 android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0;
153 ASSERT_EQ(result, verify_package_compatibility(zip));
154 CloseArchive(zip);
155 }
156
TEST(InstallTest,verify_package_compatibility_with_libvintf_system_manifest_xml)157 TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml) {
158 static constexpr const char* system_manifest_xml_path = "/system/manifest.xml";
159 if (access(system_manifest_xml_path, R_OK) == -1) {
160 GTEST_LOG_(INFO) << "Test skipped on devices w/o /system/manifest.xml.";
161 return;
162 }
163 std::string system_manifest_xml_content;
164 ASSERT_TRUE(
165 android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content));
166 TemporaryFile compatibility_zip_file;
167 FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w");
168 ZipWriter compatibility_zip_writer(compatibility_zip);
169 ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
170 ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(),
171 system_manifest_xml_content.size()));
172 ASSERT_EQ(0, compatibility_zip_writer.FinishEntry());
173 ASSERT_EQ(0, compatibility_zip_writer.Finish());
174 ASSERT_EQ(0, fclose(compatibility_zip));
175
176 TemporaryFile temp_file;
177 FILE* zip_file = fdopen(temp_file.fd, "w");
178 ZipWriter writer(zip_file);
179 ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
180 std::string compatibility_zip_content;
181 ASSERT_TRUE(
182 android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
183 ASSERT_EQ(0,
184 writer.WriteBytes(compatibility_zip_content.data(), compatibility_zip_content.size()));
185 ASSERT_EQ(0, writer.FinishEntry());
186 ASSERT_EQ(0, writer.Finish());
187 ASSERT_EQ(0, fclose(zip_file));
188
189 ZipArchiveHandle zip;
190 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
191 std::vector<std::string> compatibility_info;
192 compatibility_info.push_back(system_manifest_xml_content);
193 std::string err;
194 bool result =
195 android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0;
196 // Make sure the result is consistent with libvintf library.
197 ASSERT_EQ(result, verify_package_compatibility(zip));
198 CloseArchive(zip);
199 }
200
TEST(InstallTest,update_binary_command_smoke)201 TEST(InstallTest, update_binary_command_smoke) {
202 #ifdef AB_OTA_UPDATER
203 TemporaryFile temp_file;
204 FILE* zip_file = fdopen(temp_file.fd, "w");
205 ZipWriter writer(zip_file);
206 ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
207 ASSERT_EQ(0, writer.FinishEntry());
208 ASSERT_EQ(0, writer.StartEntry("payload_properties.txt", kCompressStored));
209 const std::string properties = "some_properties";
210 ASSERT_EQ(0, writer.WriteBytes(properties.data(), properties.size()));
211 ASSERT_EQ(0, writer.FinishEntry());
212 // A metadata entry is mandatory.
213 ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
214 std::string device = android::base::GetProperty("ro.product.device", "");
215 ASSERT_NE("", device);
216 std::string timestamp = android::base::GetProperty("ro.build.date.utc", "");
217 ASSERT_NE("", timestamp);
218 std::string metadata = android::base::Join(
219 std::vector<std::string>{
220 "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp,
221 },
222 "\n");
223 ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size()));
224 ASSERT_EQ(0, writer.FinishEntry());
225 ASSERT_EQ(0, writer.Finish());
226 ASSERT_EQ(0, fclose(zip_file));
227
228 ZipArchiveHandle zip;
229 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
230 ZipString payload_name("payload.bin");
231 ZipEntry payload_entry;
232 ASSERT_EQ(0, FindEntry(zip, payload_name, &payload_entry));
233 int status_fd = 10;
234 std::string package = "/path/to/update.zip";
235 std::string binary_path = "/sbin/update_engine_sideload";
236 std::vector<std::string> cmd;
237 ASSERT_EQ(0, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
238 ASSERT_EQ(5U, cmd.size());
239 ASSERT_EQ(binary_path, cmd[0]);
240 ASSERT_EQ("--payload=file://" + package, cmd[1]);
241 ASSERT_EQ("--offset=" + std::to_string(payload_entry.offset), cmd[2]);
242 ASSERT_EQ("--headers=" + properties, cmd[3]);
243 ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]);
244 CloseArchive(zip);
245 #else
246 TemporaryFile temp_file;
247 FILE* zip_file = fdopen(temp_file.fd, "w");
248 ZipWriter writer(zip_file);
249 static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
250 ASSERT_EQ(0, writer.StartEntry(UPDATE_BINARY_NAME, kCompressStored));
251 ASSERT_EQ(0, writer.FinishEntry());
252 ASSERT_EQ(0, writer.Finish());
253 ASSERT_EQ(0, fclose(zip_file));
254
255 ZipArchiveHandle zip;
256 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
257 int status_fd = 10;
258 std::string package = "/path/to/update.zip";
259 TemporaryDir td;
260 std::string binary_path = std::string(td.path) + "/update_binary";
261 std::vector<std::string> cmd;
262 ASSERT_EQ(0, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
263 ASSERT_EQ(4U, cmd.size());
264 ASSERT_EQ(binary_path, cmd[0]);
265 ASSERT_EQ("3", cmd[1]); // RECOVERY_API_VERSION
266 ASSERT_EQ(std::to_string(status_fd), cmd[2]);
267 ASSERT_EQ(package, cmd[3]);
268 struct stat sb;
269 ASSERT_EQ(0, stat(binary_path.c_str(), &sb));
270 ASSERT_EQ(static_cast<mode_t>(0755), sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
271
272 // With non-zero retry count. update_binary will be removed automatically.
273 cmd.clear();
274 ASSERT_EQ(0, update_binary_command(package, zip, binary_path, 2, status_fd, &cmd));
275 ASSERT_EQ(5U, cmd.size());
276 ASSERT_EQ(binary_path, cmd[0]);
277 ASSERT_EQ("3", cmd[1]); // RECOVERY_API_VERSION
278 ASSERT_EQ(std::to_string(status_fd), cmd[2]);
279 ASSERT_EQ(package, cmd[3]);
280 ASSERT_EQ("retry", cmd[4]);
281 sb = {};
282 ASSERT_EQ(0, stat(binary_path.c_str(), &sb));
283 ASSERT_EQ(static_cast<mode_t>(0755), sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
284
285 CloseArchive(zip);
286 #endif // AB_OTA_UPDATER
287 }
288
TEST(InstallTest,update_binary_command_invalid)289 TEST(InstallTest, update_binary_command_invalid) {
290 #ifdef AB_OTA_UPDATER
291 TemporaryFile temp_file;
292 FILE* zip_file = fdopen(temp_file.fd, "w");
293 ZipWriter writer(zip_file);
294 // Missing payload_properties.txt.
295 ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
296 ASSERT_EQ(0, writer.FinishEntry());
297 // A metadata entry is mandatory.
298 ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
299 std::string device = android::base::GetProperty("ro.product.device", "");
300 ASSERT_NE("", device);
301 std::string timestamp = android::base::GetProperty("ro.build.date.utc", "");
302 ASSERT_NE("", timestamp);
303 std::string metadata = android::base::Join(
304 std::vector<std::string>{
305 "ota-type=AB", "pre-device=" + device, "post-timestamp=" + timestamp,
306 },
307 "\n");
308 ASSERT_EQ(0, writer.WriteBytes(metadata.data(), metadata.size()));
309 ASSERT_EQ(0, writer.FinishEntry());
310 ASSERT_EQ(0, writer.Finish());
311 ASSERT_EQ(0, fclose(zip_file));
312
313 ZipArchiveHandle zip;
314 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
315 int status_fd = 10;
316 std::string package = "/path/to/update.zip";
317 std::string binary_path = "/sbin/update_engine_sideload";
318 std::vector<std::string> cmd;
319 ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
320 CloseArchive(zip);
321 #else
322 TemporaryFile temp_file;
323 FILE* zip_file = fdopen(temp_file.fd, "w");
324 ZipWriter writer(zip_file);
325 // The archive must have something to be opened correctly.
326 ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
327 ASSERT_EQ(0, writer.FinishEntry());
328 ASSERT_EQ(0, writer.Finish());
329 ASSERT_EQ(0, fclose(zip_file));
330
331 // Missing update binary.
332 ZipArchiveHandle zip;
333 ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
334 int status_fd = 10;
335 std::string package = "/path/to/update.zip";
336 TemporaryDir td;
337 std::string binary_path = std::string(td.path) + "/update_binary";
338 std::vector<std::string> cmd;
339 ASSERT_EQ(INSTALL_CORRUPT, update_binary_command(package, zip, binary_path, 0, status_fd, &cmd));
340 CloseArchive(zip);
341 #endif // AB_OTA_UPDATER
342 }
343