1 /* 2 * Copyright (C) 2016 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 <fcntl.h> 18 #include <gtest/gtest.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <sys/stat.h> 22 #include <sys/statvfs.h> 23 #include <sys/types.h> 24 #include <time.h> 25 26 #include <memory> 27 #include <string> 28 #include <vector> 29 30 #include <android-base/file.h> 31 #include <android-base/stringprintf.h> 32 #include <android-base/test_utils.h> 33 #include <openssl/sha.h> 34 35 #include "applypatch/applypatch.h" 36 #include "applypatch/applypatch_modes.h" 37 #include "common/test_constants.h" 38 #include "print_sha1.h" 39 40 static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) { 41 ASSERT_NE(nullptr, sha1); 42 43 std::string data; 44 ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); 45 46 if (fsize != nullptr) { 47 *fsize = data.size(); 48 } 49 50 uint8_t digest[SHA_DIGEST_LENGTH]; 51 SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest); 52 *sha1 = print_sha1(digest); 53 } 54 55 static void mangle_file(const std::string& fname) { 56 std::string content; 57 content.reserve(1024); 58 for (size_t i = 0; i < 1024; i++) { 59 content[i] = rand() % 256; 60 } 61 ASSERT_TRUE(android::base::WriteStringToFile(content, fname)); 62 } 63 64 static bool file_cmp(const std::string& f1, const std::string& f2) { 65 std::string c1; 66 android::base::ReadFileToString(f1, &c1); 67 std::string c2; 68 android::base::ReadFileToString(f2, &c2); 69 return c1 == c2; 70 } 71 72 class ApplyPatchTest : public ::testing::Test { 73 public: 74 static void SetUpTestCase() { 75 // set up files 76 old_file = from_testdata_base("old.file"); 77 new_file = from_testdata_base("new.file"); 78 patch_file = from_testdata_base("patch.bsdiff"); 79 rand_file = "/cache/applypatch_test_rand.file"; 80 cache_file = "/cache/saved.file"; 81 82 // write stuff to rand_file 83 ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file)); 84 85 // set up SHA constants 86 sha1sum(old_file, &old_sha1, &old_size); 87 sha1sum(new_file, &new_sha1, &new_size); 88 srand(time(nullptr)); 89 bad_sha1_a = android::base::StringPrintf("%040x", rand()); 90 bad_sha1_b = android::base::StringPrintf("%040x", rand()); 91 } 92 93 static std::string old_file; 94 static std::string new_file; 95 static std::string rand_file; 96 static std::string cache_file; 97 static std::string patch_file; 98 99 static std::string old_sha1; 100 static std::string new_sha1; 101 static std::string bad_sha1_a; 102 static std::string bad_sha1_b; 103 104 static size_t old_size; 105 static size_t new_size; 106 }; 107 108 std::string ApplyPatchTest::old_file; 109 std::string ApplyPatchTest::new_file; 110 111 static void cp(const std::string& src, const std::string& tgt) { 112 std::string cmd = "cp " + src + " " + tgt; 113 system(cmd.c_str()); 114 } 115 116 static void backup_old() { 117 cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file); 118 } 119 120 static void restore_old() { 121 cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file); 122 } 123 124 class ApplyPatchCacheTest : public ApplyPatchTest { 125 public: 126 virtual void SetUp() { 127 backup_old(); 128 } 129 130 virtual void TearDown() { 131 restore_old(); 132 } 133 }; 134 135 class ApplyPatchFullTest : public ApplyPatchCacheTest { 136 public: 137 static void SetUpTestCase() { 138 ApplyPatchTest::SetUpTestCase(); 139 140 output_f = new TemporaryFile(); 141 output_loc = std::string(output_f->path); 142 143 struct FileContents fc; 144 145 ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc)); 146 patches.push_back( 147 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); 148 149 ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); 150 patches.push_back( 151 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); 152 } 153 154 static void TearDownTestCase() { 155 delete output_f; 156 patches.clear(); 157 } 158 159 static std::vector<std::unique_ptr<Value>> patches; 160 static TemporaryFile* output_f; 161 static std::string output_loc; 162 }; 163 164 class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest { 165 public: 166 virtual void SetUp() { 167 ApplyPatchCacheTest::SetUp(); 168 cp(cache_file, "/cache/reallysaved.file"); 169 } 170 171 virtual void TearDown() { 172 cp("/cache/reallysaved.file", cache_file); 173 ApplyPatchCacheTest::TearDown(); 174 } 175 }; 176 177 std::string ApplyPatchTest::rand_file; 178 std::string ApplyPatchTest::patch_file; 179 std::string ApplyPatchTest::cache_file; 180 std::string ApplyPatchTest::old_sha1; 181 std::string ApplyPatchTest::new_sha1; 182 std::string ApplyPatchTest::bad_sha1_a; 183 std::string ApplyPatchTest::bad_sha1_b; 184 size_t ApplyPatchTest::old_size; 185 size_t ApplyPatchTest::new_size; 186 187 std::vector<std::unique_ptr<Value>> ApplyPatchFullTest::patches; 188 TemporaryFile* ApplyPatchFullTest::output_f; 189 std::string ApplyPatchFullTest::output_loc; 190 191 TEST_F(ApplyPatchTest, CheckModeSkip) { 192 std::vector<std::string> sha1s; 193 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 194 } 195 196 TEST_F(ApplyPatchTest, CheckModeSingle) { 197 std::vector<std::string> sha1s = { old_sha1 }; 198 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 199 } 200 201 TEST_F(ApplyPatchTest, CheckModeMultiple) { 202 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; 203 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 204 } 205 206 TEST_F(ApplyPatchTest, CheckModeFailure) { 207 std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b }; 208 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); 209 } 210 211 TEST_F(ApplyPatchTest, CheckModeEmmcTarget) { 212 // EMMC:old_file:size:sha1 should pass the check. 213 std::string src_file = 214 "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + old_sha1; 215 std::vector<std::string> sha1s; 216 ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); 217 218 // EMMC:old_file:(size-1):sha1:(size+1):sha1 should fail the check. 219 src_file = "EMMC:" + old_file + ":" + std::to_string(old_size - 1) + ":" + old_sha1 + ":" + 220 std::to_string(old_size + 1) + ":" + old_sha1; 221 ASSERT_EQ(1, applypatch_check(src_file.c_str(), sha1s)); 222 223 // EMMC:old_file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check. 224 src_file = "EMMC:" + old_file + ":" + 225 std::to_string(old_size - 1) + ":" + old_sha1 + ":" + 226 std::to_string(old_size) + ":" + old_sha1 + ":" + 227 std::to_string(old_size + 1) + ":" + old_sha1; 228 ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); 229 230 // EMMC:old_file:(size+1):sha1:(size-1):sha1:size:sha1 should pass the check. 231 src_file = "EMMC:" + old_file + ":" + 232 std::to_string(old_size + 1) + ":" + old_sha1 + ":" + 233 std::to_string(old_size - 1) + ":" + old_sha1 + ":" + 234 std::to_string(old_size) + ":" + old_sha1; 235 ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); 236 237 // EMMC:new_file:(size+1):old_sha1:(size-1):old_sha1:size:old_sha1:size:new_sha1 238 // should pass the check. 239 src_file = "EMMC:" + new_file + ":" + 240 std::to_string(old_size + 1) + ":" + old_sha1 + ":" + 241 std::to_string(old_size - 1) + ":" + old_sha1 + ":" + 242 std::to_string(old_size) + ":" + old_sha1 + ":" + 243 std::to_string(new_size) + ":" + new_sha1; 244 ASSERT_EQ(0, applypatch_check(src_file.c_str(), sha1s)); 245 } 246 247 TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) { 248 mangle_file(old_file); 249 std::vector<std::string> sha1s = { old_sha1 }; 250 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 251 } 252 253 TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) { 254 mangle_file(old_file); 255 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; 256 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 257 } 258 259 TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) { 260 mangle_file(old_file); 261 std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b }; 262 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); 263 } 264 265 TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) { 266 unlink(&old_file[0]); 267 std::vector<std::string> sha1s = { old_sha1 }; 268 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 269 } 270 271 TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) { 272 unlink(&old_file[0]); 273 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b }; 274 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 275 } 276 277 TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) { 278 unlink(&old_file[0]); 279 std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b }; 280 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s)); 281 } 282 283 TEST(ApplyPatchModesTest, InvalidArgs) { 284 // At least two args (including the filename). 285 ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" })); 286 287 // Unrecognized args. 288 ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" })); 289 } 290 291 TEST(ApplyPatchModesTest, PatchModeEmmcTarget) { 292 std::string boot_img = from_testdata_base("boot.img"); 293 size_t boot_img_size; 294 std::string boot_img_sha1; 295 sha1sum(boot_img, &boot_img_sha1, &boot_img_size); 296 297 std::string recovery_img = from_testdata_base("recovery.img"); 298 size_t size; 299 std::string recovery_img_sha1; 300 sha1sum(recovery_img, &recovery_img_sha1, &size); 301 std::string recovery_img_size = std::to_string(size); 302 303 std::string bonus_file = from_testdata_base("bonus.file"); 304 305 // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch> 306 TemporaryFile tmp1; 307 std::string src_file = 308 "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1; 309 std::string tgt_file = "EMMC:" + std::string(tmp1.path); 310 std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); 311 std::vector<const char*> args = { 312 "applypatch", 313 "-b", 314 bonus_file.c_str(), 315 src_file.c_str(), 316 tgt_file.c_str(), 317 recovery_img_sha1.c_str(), 318 recovery_img_size.c_str(), 319 patch.c_str() 320 }; 321 ASSERT_EQ(0, applypatch_modes(args.size(), args.data())); 322 323 // applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch> 324 TemporaryFile tmp2; 325 patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); 326 tgt_file = "EMMC:" + std::string(tmp2.path); 327 std::vector<const char*> args2 = { 328 "applypatch", 329 src_file.c_str(), 330 tgt_file.c_str(), 331 recovery_img_sha1.c_str(), 332 recovery_img_size.c_str(), 333 patch.c_str() 334 }; 335 ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data())); 336 337 // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \ 338 // <src-sha1-fake>:<patch1> <src-sha1>:<patch2> 339 TemporaryFile tmp3; 340 tgt_file = "EMMC:" + std::string(tmp3.path); 341 std::string bad_sha1_a = android::base::StringPrintf("%040x", rand()); 342 std::string bad_sha1_b = android::base::StringPrintf("%040x", rand()); 343 std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p"); 344 std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p"); 345 std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p"); 346 std::vector<const char*> args3 = { 347 "applypatch", 348 "-b", 349 bonus_file.c_str(), 350 src_file.c_str(), 351 tgt_file.c_str(), 352 recovery_img_sha1.c_str(), 353 recovery_img_size.c_str(), 354 patch1.c_str(), 355 patch2.c_str(), 356 patch3.c_str() 357 }; 358 ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data())); 359 } 360 361 TEST(ApplyPatchModesTest, PatchModeInvalidArgs) { 362 // Invalid bonus file. 363 ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" })); 364 365 std::string bonus_file = from_testdata_base("bonus.file"); 366 // With bonus file, but missing args. 367 ASSERT_EQ(2, applypatch_modes(3, (const char* []){ "applypatch", "-b", bonus_file.c_str() })); 368 369 std::string boot_img = from_testdata_base("boot.img"); 370 size_t boot_img_size; 371 std::string boot_img_sha1; 372 sha1sum(boot_img, &boot_img_sha1, &boot_img_size); 373 374 std::string recovery_img = from_testdata_base("recovery.img"); 375 size_t size; 376 std::string recovery_img_sha1; 377 sha1sum(recovery_img, &recovery_img_sha1, &size); 378 std::string recovery_img_size = std::to_string(size); 379 380 // Bonus file is not supported in flash mode. 381 // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> 382 TemporaryFile tmp4; 383 std::vector<const char*> args4 = { 384 "applypatch", 385 "-b", 386 bonus_file.c_str(), 387 boot_img.c_str(), 388 tmp4.path, 389 recovery_img_sha1.c_str(), 390 recovery_img_size.c_str() 391 }; 392 ASSERT_NE(0, applypatch_modes(args4.size(), args4.data())); 393 394 // Failed to parse patch args. 395 TemporaryFile tmp5; 396 std::string bad_arg1 = 397 "invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p"); 398 std::vector<const char*> args5 = { 399 "applypatch", 400 boot_img.c_str(), 401 tmp5.path, 402 recovery_img_sha1.c_str(), 403 recovery_img_size.c_str(), 404 bad_arg1.c_str() 405 }; 406 ASSERT_NE(0, applypatch_modes(args5.size(), args5.data())); 407 408 // Target size cannot be zero. 409 TemporaryFile tmp6; 410 std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p"); 411 std::vector<const char*> args6 = { 412 "applypatch", 413 boot_img.c_str(), 414 tmp6.path, 415 recovery_img_sha1.c_str(), 416 "0", // target size 417 patch.c_str() 418 }; 419 ASSERT_NE(0, applypatch_modes(args6.size(), args6.data())); 420 } 421 422 TEST(ApplyPatchModesTest, CheckModeInvalidArgs) { 423 // Insufficient args. 424 ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" })); 425 } 426 427 TEST(ApplyPatchModesTest, SpaceModeInvalidArgs) { 428 // Insufficient args. 429 ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-s" })); 430 431 // Invalid bytes arg. 432 ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "x" })); 433 434 // 0 is invalid. 435 ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0" })); 436 437 // 0x10 is fine. 438 ASSERT_EQ(0, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0x10" })); 439 } 440 441 TEST(ApplyPatchModesTest, ShowLicenses) { 442 ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" })); 443 } 444