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 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 <update_verifier/update_verifier.h>
18 
19 #include <functional>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include <android-base/file.h>
25 #include <android-base/properties.h>
26 #include <android-base/strings.h>
27 #include <google/protobuf/repeated_field.h>
28 #include <gtest/gtest.h>
29 
30 #include "care_map.pb.h"
31 
32 using namespace std::string_literals;
33 
34 class UpdateVerifierTest : public ::testing::Test {
35  protected:
SetUp()36   void SetUp() override {
37     std::string verity_mode = android::base::GetProperty("ro.boot.veritymode", "");
38     verity_supported = android::base::EqualsIgnoreCase(verity_mode, "enforcing");
39 
40     care_map_prefix_ = care_map_dir_.path + "/care_map"s;
41     care_map_pb_ = care_map_dir_.path + "/care_map.pb"s;
42     care_map_txt_ = care_map_dir_.path + "/care_map.txt"s;
43     // Overrides the the care_map_prefix.
44     verifier_.set_care_map_prefix(care_map_prefix_);
45 
46     property_id_ = "ro.build.fingerprint";
47     fingerprint_ = android::base::GetProperty(property_id_, "");
48     // Overrides the property_reader if we cannot read the given property on the device.
49     if (fingerprint_.empty()) {
50       fingerprint_ = "mock_fingerprint";
51       verifier_.set_property_reader([](const std::string& /* id */) { return "mock_fingerprint"; });
52     }
53   }
54 
TearDown()55   void TearDown() override {
56     unlink(care_map_pb_.c_str());
57     unlink(care_map_txt_.c_str());
58   }
59 
60   // Returns a serialized string of the proto3 message according to the given partition info.
ConstructProto(std::vector<std::unordered_map<std::string,std::string>> & partitions)61   std::string ConstructProto(
62       std::vector<std::unordered_map<std::string, std::string>>& partitions) {
63     recovery_update_verifier::CareMap result;
64     for (const auto& partition : partitions) {
65       recovery_update_verifier::CareMap::PartitionInfo info;
66       if (partition.find("name") != partition.end()) {
67         info.set_name(partition.at("name"));
68       }
69       if (partition.find("ranges") != partition.end()) {
70         info.set_ranges(partition.at("ranges"));
71       }
72       if (partition.find("id") != partition.end()) {
73         info.set_id(partition.at("id"));
74       }
75       if (partition.find("fingerprint") != partition.end()) {
76         info.set_fingerprint(partition.at("fingerprint"));
77       }
78 
79       *result.add_partitions() = info;
80     }
81 
82     return result.SerializeAsString();
83   }
84 
85   bool verity_supported;
86   UpdateVerifier verifier_;
87 
88   TemporaryDir care_map_dir_;
89   std::string care_map_prefix_;
90   std::string care_map_pb_;
91   std::string care_map_txt_;
92 
93   std::string property_id_;
94   std::string fingerprint_;
95 };
96 
TEST_F(UpdateVerifierTest,verify_image_no_care_map)97 TEST_F(UpdateVerifierTest, verify_image_no_care_map) {
98   ASSERT_FALSE(verifier_.ParseCareMap());
99 }
100 
TEST_F(UpdateVerifierTest,verify_image_text_format)101 TEST_F(UpdateVerifierTest, verify_image_text_format) {
102   // This test relies on dm-verity support.
103   if (!verity_supported) {
104     GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
105     return;
106   }
107 
108   std::string content = "system\n2,0,1";
109   ASSERT_TRUE(android::base::WriteStringToFile(content, care_map_txt_));
110   // CareMap in text format is no longer supported.
111   ASSERT_FALSE(verifier_.ParseCareMap());
112 }
113 
TEST_F(UpdateVerifierTest,verify_image_empty_care_map)114 TEST_F(UpdateVerifierTest, verify_image_empty_care_map) {
115   ASSERT_FALSE(verifier_.ParseCareMap());
116 }
117 
TEST_F(UpdateVerifierTest,verify_image_protobuf_care_map_smoke)118 TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_smoke) {
119   // This test relies on dm-verity support.
120   if (!verity_supported) {
121     GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
122     return;
123   }
124 
125   std::vector<std::unordered_map<std::string, std::string>> partitions = {
126     {
127         { "name", "system" },
128         { "ranges", "2,0,1" },
129         { "id", property_id_ },
130         { "fingerprint", fingerprint_ },
131     },
132   };
133 
134   std::string proto = ConstructProto(partitions);
135   ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
136   ASSERT_TRUE(verifier_.ParseCareMap());
137   ASSERT_TRUE(verifier_.VerifyPartitions());
138 }
139 
TEST_F(UpdateVerifierTest,verify_image_protobuf_care_map_missing_name)140 TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_missing_name) {
141   // This test relies on dm-verity support.
142   if (!verity_supported) {
143     GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
144     return;
145   }
146 
147   std::vector<std::unordered_map<std::string, std::string>> partitions = {
148     {
149         { "ranges", "2,0,1" },
150         { "id", property_id_ },
151         { "fingerprint", fingerprint_ },
152     },
153   };
154 
155   std::string proto = ConstructProto(partitions);
156   ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
157   ASSERT_FALSE(verifier_.ParseCareMap());
158 }
159 
TEST_F(UpdateVerifierTest,verify_image_protobuf_care_map_bad_ranges)160 TEST_F(UpdateVerifierTest, verify_image_protobuf_care_map_bad_ranges) {
161   // This test relies on dm-verity support.
162   if (!verity_supported) {
163     GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
164     return;
165   }
166 
167   std::vector<std::unordered_map<std::string, std::string>> partitions = {
168     {
169         { "name", "system" },
170         { "ranges", "3,0,1" },
171         { "id", property_id_ },
172         { "fingerprint", fingerprint_ },
173     },
174   };
175 
176   std::string proto = ConstructProto(partitions);
177   ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
178   ASSERT_FALSE(verifier_.ParseCareMap());
179 }
180 
TEST_F(UpdateVerifierTest,verify_image_protobuf_empty_fingerprint)181 TEST_F(UpdateVerifierTest, verify_image_protobuf_empty_fingerprint) {
182   // This test relies on dm-verity support.
183   if (!verity_supported) {
184     GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
185     return;
186   }
187 
188   std::vector<std::unordered_map<std::string, std::string>> partitions = {
189     {
190         { "name", "system" },
191         { "ranges", "2,0,1" },
192     },
193   };
194 
195   std::string proto = ConstructProto(partitions);
196   ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
197   ASSERT_FALSE(verifier_.ParseCareMap());
198 }
199 
TEST_F(UpdateVerifierTest,verify_image_protobuf_fingerprint_mismatch)200 TEST_F(UpdateVerifierTest, verify_image_protobuf_fingerprint_mismatch) {
201   // This test relies on dm-verity support.
202   if (!verity_supported) {
203     GTEST_LOG_(INFO) << "Test skipped on devices without dm-verity support.";
204     return;
205   }
206 
207   std::vector<std::unordered_map<std::string, std::string>> partitions = {
208     {
209         { "name", "system" },
210         { "ranges", "2,0,1" },
211         { "id", property_id_ },
212         { "fingerprint", "unsupported_fingerprint" },
213     },
214   };
215 
216   std::string proto = ConstructProto(partitions);
217   ASSERT_TRUE(android::base::WriteStringToFile(proto, care_map_pb_));
218   ASSERT_FALSE(verifier_.ParseCareMap());
219 }
220