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