xref: /aosp_15_r20/cts/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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