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 <inttypes.h>
18
19 #include <string>
20
21 #include <gtest/gtest.h>
22
23 #include <android-base/file.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/strings.h>
26
27 #include <private/android_filesystem_config.h>
28 #include <private/fs_config.h>
29
30 extern const fs_path_config* __for_testing_only__android_dirs;
31 extern const fs_path_config* __for_testing_only__android_files;
32 extern bool (*__for_testing_only__fs_config_cmp)(bool, const char*, size_t, const char*, size_t);
33
34 // Maximum entries in system/core/libcutils/fs_config.cpp:android_* before we
35 // hit a nullptr termination, before we declare the list is just too big or
36 // could be missing the nullptr.
37 static constexpr size_t max_idx = 4096;
38
39 static const struct fs_config_cmp_test {
40 bool dir;
41 const char* prefix;
42 const char* path;
43 bool match;
44 } fs_config_cmp_tests[] = {
45 // clang-format off
46 { true, "system/lib", "system/lib/hw", true },
47 { true, "vendor/lib", "system/vendor/lib/hw", true },
48 { true, "system/vendor/lib", "vendor/lib/hw", true },
49 { true, "system/vendor/lib", "system/vendor/lib/hw", true },
50 { false, "vendor/bin/wifi", "system/vendor/bin/w", false },
51 { false, "vendor/bin/wifi", "system/vendor/bin/wifi", true },
52 { false, "vendor/bin/wifi", "system/vendor/bin/wifi2", false },
53 { false, "system/vendor/bin/wifi", "system/vendor/bin/wifi", true, },
54 { false, "odm/bin/wifi", "system/odm/bin/wifi", true },
55 { false, "oem/bin/wifi", "system/oem/bin/wifi", true },
56 { false, "data/bin/wifi", "system/data/bin/wifi", false },
57 { false, "system/bin/*", "system/bin/wifi", true },
58 { false, "vendor/bin/*", "system/vendor/bin/wifi", true },
59 { false, "system/bin/*", "system/bin", false },
60 { false, "system/vendor/bin/*", "vendor/bin/wifi", true },
61 { false, NULL, NULL, false },
62 // clang-format on
63 };
64
check_unique(std::vector<const char * > & paths,const std::string & config_name,const std::string & prefix)65 static bool check_unique(std::vector<const char*>& paths, const std::string& config_name,
66 const std::string& prefix) {
67 bool retval = false;
68
69 std::string alternate = "system/" + prefix;
70
71 for (size_t idx = 0; idx < paths.size(); ++idx) {
72 size_t second;
73 std::string path(paths[idx]);
74 // check if there are multiple identical paths
75 for (second = idx + 1; second < paths.size(); ++second) {
76 if (path == paths[second]) {
77 GTEST_LOG_(ERROR) << "duplicate paths in " << config_name << ": " << paths[idx];
78 retval = true;
79 break;
80 }
81 }
82
83 // check if path is <partition>/
84 if (android::base::StartsWith(path, prefix)) {
85 // rebuild path to be system/<partition>/... to check for alias
86 path = alternate + path.substr(prefix.size());
87 for (second = 0; second < paths.size(); ++second) {
88 if (path == paths[second]) {
89 GTEST_LOG_(ERROR) << "duplicate alias paths in " << config_name << ": "
90 << paths[idx] << " and " << paths[second]
91 << " (remove latter)";
92 retval = true;
93 break;
94 }
95 }
96 continue;
97 }
98
99 // check if path is system/<partition>/
100 if (android::base::StartsWith(path, alternate)) {
101 // rebuild path to be <partition>/... to check for alias
102 path = prefix + path.substr(alternate.size());
103 for (second = 0; second < paths.size(); ++second) {
104 if (path == paths[second]) break;
105 }
106 if (second >= paths.size()) {
107 GTEST_LOG_(ERROR) << "replace path in " << config_name << ": " << paths[idx]
108 << " with " << path;
109 retval = true;
110 }
111 }
112 }
113 return retval;
114 }
115
check_unique(const fs_path_config * paths,const char * type_name,const std::string & prefix)116 static bool check_unique(const fs_path_config* paths, const char* type_name,
117 const std::string& prefix) {
118 std::string config("system/core/libcutils/fs_config.cpp:android_");
119 config += type_name;
120 config += "[]";
121
122 bool retval = false;
123 std::vector<const char*> paths_tmp;
124 for (size_t idx = 0; paths[idx].prefix; ++idx) {
125 if (idx > max_idx) {
126 GTEST_LOG_(WARNING) << config << ": has no end (missing null prefix)";
127 retval = true;
128 break;
129 }
130 paths_tmp.push_back(paths[idx].prefix);
131 }
132
133 return check_unique(paths_tmp, config, prefix) || retval;
134 }
135
check_fs_config_cmp(const fs_config_cmp_test * tests)136 static bool check_fs_config_cmp(const fs_config_cmp_test* tests) {
137 bool match, retval = false;
138 for (size_t idx = 0; tests[idx].prefix; ++idx) {
139 match = __for_testing_only__fs_config_cmp(tests[idx].dir, tests[idx].prefix,
140 strlen(tests[idx].prefix), tests[idx].path,
141 strlen(tests[idx].path));
142 if (match != tests[idx].match) {
143 GTEST_LOG_(ERROR) << tests[idx].path << (match ? " matched " : " didn't match ")
144 << tests[idx].prefix;
145 retval = true;
146 break;
147 }
148 }
149 return retval;
150 }
151
152 #define endof(pointer, field) (offsetof(typeof(*(pointer)), field) + sizeof((pointer)->field))
153
check_unique(const std::string & config,const std::string & prefix)154 static bool check_unique(const std::string& config, const std::string& prefix) {
155 int retval = false;
156
157 std::string data;
158 if (!android::base::ReadFileToString(config, &data)) return retval;
159
160 const fs_path_config_from_file* pc =
161 reinterpret_cast<const fs_path_config_from_file*>(data.c_str());
162 size_t len = data.size();
163
164 std::vector<const char*> paths_tmp;
165 size_t entry_number = 0;
166 while (len > 0) {
167 uint16_t host_len = (len >= endof(pc, len)) ? pc->len : INT16_MAX;
168 if (host_len > len) {
169 GTEST_LOG_(WARNING) << config << ": truncated at entry " << entry_number << " ("
170 << host_len << " > " << len << ")";
171 const std::string unknown("?");
172 GTEST_LOG_(WARNING)
173 << config << ": entry[" << entry_number << "]={ "
174 << "len=" << ((len >= endof(pc, len))
175 ? android::base::StringPrintf("%" PRIu16, pc->len)
176 : unknown)
177 << ", mode=" << ((len >= endof(pc, mode))
178 ? android::base::StringPrintf("0%" PRIo16, pc->mode)
179 : unknown)
180 << ", uid=" << ((len >= endof(pc, uid))
181 ? android::base::StringPrintf("%" PRIu16, pc->uid)
182 : unknown)
183 << ", gid=" << ((len >= endof(pc, gid))
184 ? android::base::StringPrintf("%" PRIu16, pc->gid)
185 : unknown)
186 << ", capabilities="
187 << ((len >= endof(pc, capabilities))
188 ? android::base::StringPrintf("0x%" PRIx64, pc->capabilities)
189 : unknown)
190 << ", prefix="
191 << ((len >= offsetof(fs_path_config_from_file, prefix))
192 ? android::base::StringPrintf(
193 "\"%.*s...", (int)(len - offsetof(fs_path_config_from_file, prefix)),
194 pc->prefix)
195 : unknown)
196 << " }";
197 retval = true;
198 break;
199 }
200 paths_tmp.push_back(pc->prefix);
201
202 pc = reinterpret_cast<const fs_path_config_from_file*>(reinterpret_cast<const char*>(pc) +
203 host_len);
204 len -= host_len;
205 ++entry_number;
206 }
207
208 return check_unique(paths_tmp, config, prefix) || retval;
209 }
210
check_two(const fs_path_config * paths,const char * type_name,const char * prefix)211 void check_two(const fs_path_config* paths, const char* type_name, const char* prefix) {
212 ASSERT_FALSE(paths == nullptr);
213 ASSERT_FALSE(type_name == nullptr);
214 ASSERT_FALSE(prefix == nullptr);
215 bool check_internal = check_unique(paths, type_name, prefix);
216 EXPECT_FALSE(check_internal);
217 bool check_overrides =
218 check_unique(std::string("/") + prefix + "etc/fs_config_" + type_name, prefix);
219 EXPECT_FALSE(check_overrides);
220 }
221
TEST(fs_config,vendor_dirs_alias)222 TEST(fs_config, vendor_dirs_alias) {
223 check_two(__for_testing_only__android_dirs, "dirs", "vendor/");
224 }
225
TEST(fs_config,vendor_files_alias)226 TEST(fs_config, vendor_files_alias) {
227 check_two(__for_testing_only__android_files, "files", "vendor/");
228 }
229
TEST(fs_config,oem_dirs_alias)230 TEST(fs_config, oem_dirs_alias) {
231 check_two(__for_testing_only__android_dirs, "dirs", "oem/");
232 }
233
TEST(fs_config,oem_files_alias)234 TEST(fs_config, oem_files_alias) {
235 check_two(__for_testing_only__android_files, "files", "oem/");
236 }
237
TEST(fs_config,odm_dirs_alias)238 TEST(fs_config, odm_dirs_alias) {
239 check_two(__for_testing_only__android_dirs, "dirs", "odm/");
240 }
241
TEST(fs_config,odm_files_alias)242 TEST(fs_config, odm_files_alias) {
243 check_two(__for_testing_only__android_files, "files", "odm/");
244 }
245
TEST(fs_config,system_alias)246 TEST(fs_config, system_alias) {
247 EXPECT_FALSE(check_fs_config_cmp(fs_config_cmp_tests));
248 }
249