Home | History | Annotate | Download | only in component
      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