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