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 <android-base/file.h>
18 #include <android-base/properties.h>
19 #include <android-base/strings.h>
20 #include <fs_mgr.h>
21 #include <fstab/fstab.h>
22 #include <gtest/gtest.h>
23
24 #include <string>
25 #include <thread>
26
27 #include "utils.h"
28
29 using namespace std::chrono_literals;
30
isExemptFromAVBTests()31 static bool isExemptFromAVBTests() {
32 int first_api_level = getFirstApiLevel();
33 int vendor_api_level = getVendorApiLevel();
34 GTEST_LOG_(INFO) << "First API level is " << first_api_level;
35 GTEST_LOG_(INFO) << "Vendor API level is " << vendor_api_level;
36 if (first_api_level < __ANDROID_API_S__) {
37 GTEST_LOG_(INFO) << "Exempt from avb test due to old starting API level";
38 return true;
39 }
40
41 // This feature name check only applies to devices that first shipped with
42 // SC or later.
43 int min_api_level = (first_api_level < vendor_api_level) ? first_api_level : vendor_api_level;
44 if (min_api_level >= __ANDROID_API_S__ &&
45 !deviceSupportsFeature("android.hardware.security.model.compatible")) {
46 GTEST_LOG_(INFO) << "Skipping test: FEATURE_SECURITY_MODEL_COMPATIBLE missing.";
47 return true;
48 }
49 return false;
50 }
51
getVerityMountPoints()52 static std::set<std::string> getVerityMountPoints() {
53 std::set<std::string> verity_partitions;
54
55 android::fs_mgr::Fstab mounted_fstab;
56 if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
57 ADD_FAILURE() << "Failed to read the mounted fstab";
58 return verity_partitions;
59 }
60
61 // Build a list of mount points that are either mounted or known to have
62 // importance.
63 std::set<std::string> mount_points = {"/", "/system"};
64 for (const auto& entry : mounted_fstab) {
65 mount_points.insert(entry.mount_point);
66 }
67 android::fs_mgr::Fstab fstab;
68 if (!ReadDefaultFstab(&fstab)) {
69 ADD_FAILURE() << "Failed to read default fstab";
70 return verity_partitions;
71 }
72
73 for (const auto& entry : fstab) {
74 if (!entry.fs_mgr_flags.avb) {
75 continue;
76 }
77
78 if (mount_points.find(entry.mount_point) == mount_points.end()) {
79 GTEST_LOG_(INFO) << entry.mount_point << " isn't mounted, skipping";
80 continue;
81 }
82
83 if (mount_points.find(entry.mount_point) == mount_points.end()) {
84 GTEST_LOG_(INFO) << entry.mount_point << " isn't mounted, skipping";
85 continue;
86 }
87
88 if (android::base::EqualsIgnoreCase(entry.fs_type, "emmc")) {
89 GTEST_LOG_(INFO) << entry.mount_point << " has emmc fs_type, skipping";
90 continue;
91 }
92
93 GTEST_LOG_(INFO) << "partition enabled verity " << entry.mount_point;
94 verity_partitions.insert(android::base::Basename(entry.mount_point));
95 }
96 return verity_partitions;
97 }
98
99 // The properties for this test are set in init. There is a race condition that
100 // causes this test to be evaluated before these properties are readable. Avoid
101 // this by waiting for the properties to be available.
waitForProperty(const std::string & property)102 void waitForProperty(const std::string &property) {
103 int retries = 40;
104 std::string value = android::base::GetProperty(property, "unset");
105 while (android::base::EqualsIgnoreCase(property, "unset") && retries--) {
106 value = android::base::GetProperty(property, "unset");
107 std::this_thread::sleep_for(100ms);
108 }
109 if (android::base::EqualsIgnoreCase(property, "unset"))
110 ADD_FAILURE() << "Property was never set: " << property;
111 }
112
113 // As required by CDD, verified boot MUST use verification algorithms as strong
114 // as current recommendations from NIST for hashing algorithms (SHA-256).
115 // @CddTest = 9.10/C-1-5
TEST(VerifiedBootTest,avbHashtreeNotUsingSha1)116 TEST(VerifiedBootTest, avbHashtreeNotUsingSha1) {
117 if (isExemptFromAVBTests()) {
118 GTEST_SKIP();
119 }
120
121 auto verity_mount_points = getVerityMountPoints();
122 for (const auto& mount_point : verity_mount_points) {
123 // The verity sysprop use "system" as the partition name in the system as
124 // root case.
125 std::string partition = mount_point == "/" ? "system" : mount_point;
126 std::string alg_prop_name = "partition." + partition + ".verified.hash_alg";
127 waitForProperty(alg_prop_name);
128 std::string hash_alg = android::base::GetProperty(alg_prop_name, "");
129
130 if (hash_alg.empty())
131 ADD_FAILURE() << "Could not find hash algorithm for " << partition;
132 if (android::base::StartsWithIgnoreCase(hash_alg, "sha1"))
133 ADD_FAILURE() << "SHA1 is insecure, but is being used for " << partition;
134 }
135 }
136
137 // Ensure that protected partitions are being verified every time they are read
138 // from, rather than once per boot.
139 // @CddTest = 9.10/C-1-7
TEST(VerifiedBootTest,avbNotUsingCheckAtMostOnce)140 TEST(VerifiedBootTest, avbNotUsingCheckAtMostOnce) {
141 if (isExemptFromAVBTests()) {
142 GTEST_SKIP();
143 }
144 if (getFirstApiLevel() < __ANDROID_API_U__) {
145 GTEST_SKIP() << "Skipping test: Exempt due to old API level";
146 }
147
148 // Any device with sufficient RAM or a 64-bit CPU is not allowed to use
149 // check_at_most_once.
150 //
151 // Sufficiently performance limited devices are allowed to use it out of necessity.
152 if (android::base::GetBoolProperty("ro.config.low_ram", false) &&
153 android::base::GetProperty("ro.product.cpu.abilist64", "").empty())
154 GTEST_SKIP()
155 << "Skipping test: Device is performance constrained (low ram or 32-bit)";
156
157 auto verity_mount_points = getVerityMountPoints();
158 for (const auto& mount_point : verity_mount_points) {
159 // The verity sysprop use "system" as the partition name in the system as
160 // root case.
161 std::string partition = mount_point == "/" ? "system" : mount_point;
162 std::string prop_name = "partition." + partition + ".verified.check_at_most_once";
163 waitForProperty(prop_name);
164 if (android::base::GetBoolProperty(prop_name, false))
165 ADD_FAILURE() << "check_at_most_once is set on " << partition;
166 }
167 }
168