1 /*
2  * Copyright (C) 2020 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 
17 #include <string>
18 
19 #include <errno.h>
20 #include <sys/stat.h>
21 
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <gtest/gtest.h>
26 
27 #include "apex_file.h"
28 #include "apex_preinstalled_data.h"
29 #include "apexd_test_utils.h"
30 #include "apexd_verity.h"
31 
32 namespace android {
33 namespace apex {
34 
35 using namespace std::literals;
36 
37 using android::apex::testing::IsOk;
38 using android::base::GetExecutableDirectory;
39 using android::base::ReadFileToString;
40 using android::base::StringPrintf;
41 
GetTestDataDir()42 static std::string GetTestDataDir() { return GetExecutableDirectory(); }
GetTestFile(const std::string & name)43 static std::string GetTestFile(const std::string& name) {
44   return GetTestDataDir() + "/" + name;
45 }
46 
TEST(ApexdVerityTest,ReusesHashtree)47 TEST(ApexdVerityTest, ReusesHashtree) {
48   ASSERT_TRUE(IsOk(collectPreinstalledData({"/system_ext/apex"})));
49   TemporaryDir td;
50 
51   auto apex = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree.apex"));
52   ASSERT_TRUE(IsOk(apex));
53   auto verity_data = apex->VerifyApexVerity();
54   ASSERT_TRUE(IsOk(verity_data));
55 
56   auto hashtree_file = StringPrintf("%s/hashtree", td.path);
57   auto status = PrepareHashTree(*apex, *verity_data, hashtree_file);
58   ASSERT_TRUE(IsOk(status));
59   ASSERT_EQ(KRegenerate, *status);
60 
61   std::string first_hashtree;
62   ASSERT_TRUE(ReadFileToString(hashtree_file, &first_hashtree))
63       << "Failed to read " << hashtree_file;
64 
65   // Now call PrepareHashTree again. Since digest matches, hashtree should be
66   // reused.
67   status = PrepareHashTree(*apex, *verity_data, hashtree_file);
68   ASSERT_TRUE(IsOk(status));
69   ASSERT_EQ(kReuse, *status);
70 
71   std::string second_hashtree;
72   ASSERT_TRUE(ReadFileToString(hashtree_file, &second_hashtree))
73       << "Failed to read " << hashtree_file;
74 
75   // Hashtree file shouldn't be modified.
76   ASSERT_EQ(first_hashtree, second_hashtree)
77       << hashtree_file << " was regenerated";
78 }
79 
TEST(ApexdVerityTest,RegenerateHashree)80 TEST(ApexdVerityTest, RegenerateHashree) {
81   ASSERT_TRUE(IsOk(collectPreinstalledData({"/system_ext/apex"})));
82   TemporaryDir td;
83 
84   auto apex = ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree.apex"));
85   ASSERT_TRUE(IsOk(apex));
86   auto verity_data = apex->VerifyApexVerity();
87   ASSERT_TRUE(IsOk(verity_data));
88 
89   auto hashtree_file = StringPrintf("%s/hashtree", td.path);
90   auto status = PrepareHashTree(*apex, *verity_data, hashtree_file);
91   ASSERT_TRUE(IsOk(status));
92   ASSERT_EQ(KRegenerate, *status);
93 
94   std::string first_hashtree;
95   ASSERT_TRUE(ReadFileToString(hashtree_file, &first_hashtree))
96       << "Failed to read " << hashtree_file;
97 
98   auto apex2 =
99       ApexFile::Open(GetTestFile("apex.apexd_test_no_hashtree_2.apex"));
100   ASSERT_TRUE(IsOk(apex2));
101   auto verity_data2 = apex2->VerifyApexVerity();
102   ASSERT_TRUE(IsOk(verity_data2));
103 
104   // Now call PrepareHashTree again. Since digest doesn't match, hashtree
105   // should be regenerated.
106   status = PrepareHashTree(*apex2, *verity_data2, hashtree_file);
107   ASSERT_TRUE(IsOk(status));
108   ASSERT_EQ(KRegenerate, *status);
109 
110   std::string second_hashtree;
111   ASSERT_TRUE(ReadFileToString(hashtree_file, &second_hashtree))
112       << "Failed to read " << hashtree_file;
113 
114   // Hashtree file should be regenerated.
115   ASSERT_NE(first_hashtree, second_hashtree) << hashtree_file << " was reused";
116 }
117 
118 }  // namespace apex
119 }  // namespace android
120