1 /*
2 * Copyright (C) 2021 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 <memory>
18
19 #include <android-base/file.h>
20 #include <android-base/properties.h>
21 #include <android/api-level.h>
22 #include <androidfw/AssetManager.h>
23 #include <androidfw/ResourceTypes.h>
24 #include <gtest/gtest.h>
25 #include <openssl/sha.h>
26 #include <stdio.h>
27 #include <utils/String8.h>
28 #include <utils/Vector.h>
29
30 #include "gsi_validation_utils.h"
31
HexDigitToByte(char c)32 uint8_t HexDigitToByte(char c) {
33 if (c >= '0' && c <= '9') {
34 return c - '0';
35 }
36 if (c >= 'a' && c <= 'f') {
37 return c - 'a' + 10;
38 }
39 if (c >= 'A' && c <= 'Z') {
40 return c - 'A' + 10;
41 }
42 return 0xff;
43 }
44
HexToBytes(const std::string & hex,std::vector<uint8_t> * bytes)45 bool HexToBytes(const std::string &hex, std::vector<uint8_t> *bytes) {
46 if (hex.size() % 2 != 0) {
47 return false;
48 }
49 bytes->resize(hex.size() / 2);
50 for (unsigned i = 0; i < bytes->size(); i++) {
51 uint8_t hi = HexDigitToByte(hex[i * 2]);
52 uint8_t lo = HexDigitToByte(hex[i * 2 + 1]);
53 if (lo > 0xf || hi > 0xf) {
54 return false;
55 }
56 bytes->at(i) = (hi << 4) | lo;
57 }
58 return true;
59 }
60
61 const char kNibble2Hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
62 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
63
BytesToHex(const std::vector<uint8_t> & bytes)64 std::string BytesToHex(const std::vector<uint8_t> &bytes) {
65 std::string retval;
66 retval.reserve(bytes.size() * 2 + 1);
67 for (uint8_t byte : bytes) {
68 retval.push_back(kNibble2Hex[0x0F & (byte >> 4)]);
69 retval.push_back(kNibble2Hex[0x0F & byte]);
70 }
71 return retval;
72 }
73
CreateShaHasher(const std::string & algorithm)74 std::unique_ptr<ShaHasher> CreateShaHasher(const std::string &algorithm) {
75 if (algorithm == "sha1") {
76 return std::make_unique<ShaHasherImpl<SHA_CTX>>(
77 SHA1_Init, SHA1_Update, SHA1_Final, SHA_DIGEST_LENGTH);
78 }
79 if (algorithm == "sha256") {
80 return std::make_unique<ShaHasherImpl<SHA256_CTX>>(
81 SHA256_Init, SHA256_Update, SHA256_Final, SHA256_DIGEST_LENGTH);
82 }
83 if (algorithm == "sha512") {
84 return std::make_unique<ShaHasherImpl<SHA512_CTX>>(
85 SHA512_Init, SHA512_Update, SHA512_Final, SHA512_DIGEST_LENGTH);
86 }
87 return nullptr;
88 }
89
ReadCommandToString(const std::string & command)90 static std::optional<std::string> ReadCommandToString(const std::string &command) {
91 std::unique_ptr<FILE, decltype(&pclose)> cmd_out_stream(popen(command.c_str(), "re"),
92 pclose);
93
94 if (!cmd_out_stream) {
95 GTEST_LOG_(ERROR) << "Invocation of cmd: " << command << " failed";
96 return std::nullopt;
97 }
98
99 int fd = fileno(cmd_out_stream.get());
100 if (fd < 0) {
101 GTEST_LOG_(ERROR) << "Unable to acquire file descriptor for cmd: " << command;
102 return std::nullopt;
103 }
104
105 std::string output;
106 if (!android::base::ReadFdToString(fd, &output)) {
107 GTEST_LOG_(ERROR) << "Unable to read cmd: " << command << " output to string";
108 return std::nullopt;
109 }
110
111 return output;
112 }
113
114 // Returns true iff the device has the specified feature.
DeviceSupportsFeature(const std::string & feature)115 static bool DeviceSupportsFeature(const std::string &feature) {
116 std::optional<std::string> features = ReadCommandToString("pm list features");
117
118 if (!features.has_value()) {
119 return false;
120 }
121
122 return features.value().find(feature) != std::string::npos;
123 }
124
125 // Returns true iff the device has the specified package installed.
DeviceHasPackage(const std::string & package_name)126 static bool DeviceHasPackage(const std::string &package_name) {
127 std::optional<std::string> packages = ReadCommandToString("pm list packages");
128
129 if (!packages.has_value()) {
130 return false;
131 }
132
133 return packages.value().find(package_name) != std::string::npos;
134 }
135
IsWatchDevice()136 static bool IsWatchDevice() {
137 return DeviceSupportsFeature("android.hardware.type.watch");
138 }
139
IsTvDevice()140 bool IsTvDevice() {
141 return DeviceSupportsFeature("android.hardware.type.television") ||
142 DeviceSupportsFeature("android.software.leanback");
143 }
144
IsAutomotiveDevice()145 bool IsAutomotiveDevice() {
146 return DeviceSupportsFeature("android.hardware.type.automotive");
147 }
148
IsVrHeadsetDevice()149 static bool IsVrHeadsetDevice() {
150 android::AssetManager assetManager;
151 // This apk is always available on devices.
152 constexpr const static char *path = "/system/framework/framework-res.apk";
153
154 if (!assetManager.addAssetPath(android::String8(path), nullptr)) {
155 GTEST_LOG_(ERROR) << "Failed to add asset path";
156 return false;
157 }
158
159 const android::ResTable& res = assetManager.getResources(false);
160 if (res.getError() != android::NO_ERROR) {
161 GTEST_LOG_(ERROR) << "getResources() invocation failed. Cannot determine device configuration.";
162 return false;
163 }
164
165 android::Vector<android::ResTable_config> configs;
166 res.getConfigurations(&configs, true);
167 // This loop iterates through various configs of the APK
168 // and searches for the UI mode, which is set to "vrheadset"
169 // for VR headsets.
170 for (const auto &config : configs) {
171 if (config.toString().find("vrheadset") != std::string::npos) {
172 return true;
173 }
174 }
175
176 return false;
177 }
178
IsArcDevice()179 static bool IsArcDevice() {
180 return DeviceSupportsFeature("org.chromium.arc") ||
181 DeviceSupportsFeature("org.chromium.arc.device_management");
182 }
183
IsUserBuild()184 static bool IsUserBuild() {
185 return android::base::GetProperty("ro.build.type", "") == "user";
186 }
187
188 // Returns whether the Play Store is installed for this build
189 // For User builds, check the Play Store package is user cert signed
190 // For Userdebug just check if the Play Store package exists.
DeviceHasPlayStore()191 static bool DeviceHasPlayStore() {
192 bool has_playstore = DeviceHasPackage("com.android.vending");
193
194 if (!has_playstore) {
195 return false;
196 }
197
198 if (IsUserBuild()) {
199 std::optional<std::string> package_dump = ReadCommandToString("pm dump com.android.vending");
200
201 if (!package_dump.has_value())
202 return false;
203
204 const std::string playstore_user_cert = "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:"
205 "33:46:C8:97:2F:AE:30:F8:EE:74:11:"
206 "DF:91:04:80:AD:6B:2D:60:DB:83";
207
208 bool certified_playstore = package_dump.value().find(playstore_user_cert) != std::string::npos;
209
210 if (!certified_playstore) {
211 GTEST_LOG_(INFO) << "Device has a user build but the version of playstore is not certified";
212 return false;
213 }
214
215 GTEST_LOG_(INFO) << "Device has a user build and a certified version of playstore";
216 return true;
217 }
218
219 GTEST_LOG_(INFO) << "Device has playstore on a non-user build";
220 return true;
221 }
222
DeviceHasGmsCore()223 static bool DeviceHasGmsCore() {
224 return DeviceHasPackage("com.google.android.gms");
225 }
226
IsLowRamDevice()227 static bool IsLowRamDevice() {
228 return (GetSdkLevel() >= __ANDROID_API_O_MR1__) &&
229 DeviceSupportsFeature("android.hardware.ram.low");
230 }
231
232 // Implementation taken from GmsUtil::isGoDevice()
233 //
234 // Android Go is only for phones and tablets. However, there is
235 // no way to identify if a device is a phone or tablet, so we
236 // must ensure that the device is not any other form factor. New
237 // form factors should be tested against here.
IsGoDevice()238 bool IsGoDevice() {
239 return IsLowRamDevice() && DeviceHasGmsCore() && DeviceHasPlayStore() &&
240 !IsWatchDevice() && !IsTvDevice() && !IsAutomotiveDevice() &&
241 !IsVrHeadsetDevice() && !IsArcDevice();
242 }
243
ValidatePublicKeyBlob(const std::string & key_blob_to_validate)244 bool ValidatePublicKeyBlob(const std::string &key_blob_to_validate) {
245 if (key_blob_to_validate.empty()) {
246 GTEST_LOG_(ERROR) << "Failed to validate an empty key";
247 return false;
248 }
249
250 const std::string exec_dir = android::base::GetExecutableDirectory();
251 std::vector<std::string> allowed_key_names = {
252 "q-gsi.avbpubkey", "r-gsi.avbpubkey", "s-gsi.avbpubkey",
253 "t-gsi.avbpubkey", "qcar-gsi.avbpubkey",
254 };
255 std::vector<std::string> allowed_oem_key_names = {
256 "gki-oem-2024.avbpubkey",
257 };
258 if (!IsGoDevice()) {
259 allowed_key_names.insert(allowed_key_names.end(),
260 allowed_oem_key_names.begin(),
261 allowed_oem_key_names.end());
262 }
263 for (const auto &key_name : allowed_key_names) {
264 const auto key_path = exec_dir + "/" + key_name;
265 std::string allowed_key_blob;
266 if (android::base::ReadFileToString(key_path, &allowed_key_blob)) {
267 if (key_blob_to_validate == allowed_key_blob) {
268 GTEST_LOG_(INFO) << "Found matching GSI key: " << key_path;
269 return true;
270 }
271 }
272 }
273 return false;
274 }
275
276 const uint32_t kCurrentApiLevel = 10000;
277
ReadApiLevelProps(const std::vector<std::string> & api_level_props)278 static uint32_t ReadApiLevelProps(
279 const std::vector<std::string> &api_level_props) {
280 uint32_t api_level = kCurrentApiLevel;
281 for (const auto &api_level_prop : api_level_props) {
282 api_level = android::base::GetUintProperty<uint32_t>(api_level_prop,
283 kCurrentApiLevel);
284 if (api_level != kCurrentApiLevel) {
285 break;
286 }
287 }
288 return api_level;
289 }
290
GetSdkLevel()291 uint32_t GetSdkLevel() {
292 uint32_t sdk_level = ReadApiLevelProps({"ro.build.version.sdk"});
293 if (sdk_level == kCurrentApiLevel) {
294 ADD_FAILURE() << "Failed to determine SDK level";
295 return 0;
296 }
297 return sdk_level;
298 }
299
GetProductFirstApiLevel()300 uint32_t GetProductFirstApiLevel() {
301 uint32_t product_api_level =
302 ReadApiLevelProps({"ro.product.first_api_level", "ro.build.version.sdk"});
303 if (product_api_level == kCurrentApiLevel) {
304 ADD_FAILURE() << "Failed to determine product first API level";
305 return 0;
306 }
307 return product_api_level;
308 }
309
GetVendorApiLevel()310 uint32_t GetVendorApiLevel() {
311 // "ro.vendor.api_level" is added in Android T.
312 uint32_t vendor_api_level = ReadApiLevelProps({"ro.vendor.api_level"});
313 if (vendor_api_level != kCurrentApiLevel) {
314 return vendor_api_level;
315 }
316 // For pre-T devices, determine the board API level by ourselves.
317 uint32_t product_api_level = GetProductFirstApiLevel();
318 uint32_t board_api_level =
319 ReadApiLevelProps({"ro.board.api_level", "ro.board.first_api_level"});
320 uint32_t api_level = std::min(board_api_level, product_api_level);
321 if (api_level == kCurrentApiLevel) {
322 ADD_FAILURE() << "Failed to determine vendor API level";
323 return 0;
324 }
325 return api_level;
326 }
327
GetBoardApiLevel()328 std::optional<uint32_t> GetBoardApiLevel() {
329 uint32_t board_api_level =
330 ReadApiLevelProps({"ro.board.api_level", "ro.board.first_api_level"});
331 if (board_api_level == kCurrentApiLevel) {
332 return std::nullopt;
333 }
334 return board_api_level;
335 }
336
IsReleasedAndroidVersion()337 bool IsReleasedAndroidVersion() {
338 return android::base::GetProperty("ro.build.version.codename", "") == "REL";
339 }
340