diff options
-rw-r--r-- | libcutils/fs_config.cpp | 49 | ||||
-rw-r--r-- | libcutils/tests/fs_config.cpp | 173 |
2 files changed, 181 insertions, 41 deletions
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index ea99595f4..40d3476ae 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp | |||
@@ -139,14 +139,8 @@ static const struct fs_path_config android_files[] = { | |||
139 | { 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" }, | 139 | { 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" }, |
140 | { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_dir + 1 }, | 140 | { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_dir + 1 }, |
141 | { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_file + 1 }, | 141 | { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_file + 1 }, |
142 | { 00600, AID_ROOT, AID_ROOT, 0, "system/odm/build.prop" }, | ||
143 | { 00600, AID_ROOT, AID_ROOT, 0, "system/odm/default.prop" }, | ||
144 | { 00444, AID_ROOT, AID_ROOT, 0, "system/odm/etc/fs_config_dirs" }, | ||
145 | { 00444, AID_ROOT, AID_ROOT, 0, "system/odm/etc/fs_config_files" }, | ||
146 | { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_dir + 1 }, | 142 | { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_dir + 1 }, |
147 | { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_file + 1 }, | 143 | { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_file + 1 }, |
148 | { 00444, AID_ROOT, AID_ROOT, 0, "system/oem/etc/fs_config_dirs" }, | ||
149 | { 00444, AID_ROOT, AID_ROOT, 0, "system/oem/etc/fs_config_files" }, | ||
150 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, | 144 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, |
151 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" }, | 145 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" }, |
152 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" }, | 146 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" }, |
@@ -163,10 +157,6 @@ static const struct fs_path_config android_files[] = { | |||
163 | { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, | 157 | { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, |
164 | { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, | 158 | { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, |
165 | { 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" }, | 159 | { 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" }, |
166 | { 00600, AID_ROOT, AID_ROOT, 0, "system/vendor/build.prop" }, | ||
167 | { 00600, AID_ROOT, AID_ROOT, 0, "system/vendor/default.prop" }, | ||
168 | { 00444, AID_ROOT, AID_ROOT, 0, "system/vendor/etc/fs_config_dirs" }, | ||
169 | { 00444, AID_ROOT, AID_ROOT, 0, "system/vendor/etc/fs_config_files" }, | ||
170 | { 00600, AID_ROOT, AID_ROOT, 0, "vendor/build.prop" }, | 160 | { 00600, AID_ROOT, AID_ROOT, 0, "vendor/build.prop" }, |
171 | { 00600, AID_ROOT, AID_ROOT, 0, "vendor/default.prop" }, | 161 | { 00600, AID_ROOT, AID_ROOT, 0, "vendor/default.prop" }, |
172 | { 00444, AID_ROOT, AID_ROOT, 0, ven_conf_dir + 1 }, | 162 | { 00444, AID_ROOT, AID_ROOT, 0, ven_conf_dir + 1 }, |
@@ -205,9 +195,6 @@ static const struct fs_path_config android_files[] = { | |||
205 | // Support RT scheduling in Bluetooth | 195 | // Support RT scheduling in Bluetooth |
206 | { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN) | | 196 | { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN) | |
207 | CAP_MASK_LONG(CAP_SYS_NICE), | 197 | CAP_MASK_LONG(CAP_SYS_NICE), |
208 | "system/vendor/bin/hw/android.hardware.bluetooth@1.0-service" }, | ||
209 | { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN) | | ||
210 | CAP_MASK_LONG(CAP_SYS_NICE), | ||
211 | "vendor/bin/hw/android.hardware.bluetooth@1.0-service" }, | 198 | "vendor/bin/hw/android.hardware.bluetooth@1.0-service" }, |
212 | 199 | ||
213 | // Support wifi_hal_legacy administering a network interface. | 200 | // Support wifi_hal_legacy administering a network interface. |
@@ -233,8 +220,6 @@ static const struct fs_path_config android_files[] = { | |||
233 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, | 220 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, |
234 | { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, | 221 | { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, |
235 | { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, | 222 | { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, |
236 | { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" }, | ||
237 | { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/xbin/*" }, | ||
238 | { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, | 223 | { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, |
239 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, | 224 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, |
240 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" }, | 225 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" }, |
@@ -273,6 +258,36 @@ static int fs_config_open(int dir, int which, const char* target_out_path) { | |||
273 | return fd; | 258 | return fd; |
274 | } | 259 | } |
275 | 260 | ||
261 | // if path is "vendor/<stuff>", "oem/<stuff>" or "odm/<stuff>" | ||
262 | static bool is_partition(const char* path, size_t len) { | ||
263 | static const char* partitions[] = {"vendor/", "oem/", "odm/"}; | ||
264 | for (size_t i = 0; i < (sizeof(partitions) / sizeof(partitions[0])); ++i) { | ||
265 | size_t plen = strlen(partitions[i]); | ||
266 | if (len <= plen) continue; | ||
267 | if (!strncmp(path, partitions[i], plen)) return true; | ||
268 | } | ||
269 | return false; | ||
270 | } | ||
271 | |||
272 | // alias prefixes of "<partition>/<stuff>" to "system/<partition>/<stuff>" or | ||
273 | // "system/<partition>/<stuff>" to "<partition>/<stuff>" | ||
274 | static bool prefix_cmp(const char* prefix, const char* path, size_t len) { | ||
275 | if (!strncmp(prefix, path, len)) return true; | ||
276 | |||
277 | static const char system[] = "system/"; | ||
278 | if (!strncmp(path, system, strlen(system))) { | ||
279 | path += strlen(system); | ||
280 | } else if (len <= strlen(system)) { | ||
281 | return false; | ||
282 | } else if (strncmp(prefix, system, strlen(system))) { | ||
283 | return false; | ||
284 | } else { | ||
285 | prefix += strlen(system); | ||
286 | len -= strlen(system); | ||
287 | } | ||
288 | return is_partition(prefix, len) && !strncmp(prefix, path, len); | ||
289 | } | ||
290 | |||
276 | static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* path, size_t plen) { | 291 | static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* path, size_t plen) { |
277 | if (dir) { | 292 | if (dir) { |
278 | if (plen < len) { | 293 | if (plen < len) { |
@@ -281,13 +296,13 @@ static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* | |||
281 | } else { | 296 | } else { |
282 | // If name ends in * then allow partial matches. | 297 | // If name ends in * then allow partial matches. |
283 | if (prefix[len - 1] == '*') { | 298 | if (prefix[len - 1] == '*') { |
284 | return !strncmp(prefix, path, len - 1); | 299 | return prefix_cmp(prefix, path, len - 1); |
285 | } | 300 | } |
286 | if (plen != len) { | 301 | if (plen != len) { |
287 | return false; | 302 | return false; |
288 | } | 303 | } |
289 | } | 304 | } |
290 | return !strncmp(prefix, path, len); | 305 | return prefix_cmp(prefix, path, len); |
291 | } | 306 | } |
292 | 307 | ||
293 | void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, | 308 | void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, |
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp index 3917a0b2e..a62cd51a2 100644 --- a/libcutils/tests/fs_config.cpp +++ b/libcutils/tests/fs_config.cpp | |||
@@ -14,63 +14,188 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <inttypes.h> | ||
18 | |||
17 | #include <string> | 19 | #include <string> |
18 | 20 | ||
19 | #include <gtest/gtest.h> | 21 | #include <gtest/gtest.h> |
20 | 22 | ||
23 | #include <android-base/file.h> | ||
24 | #include <android-base/stringprintf.h> | ||
21 | #include <android-base/strings.h> | 25 | #include <android-base/strings.h> |
22 | 26 | ||
23 | #include <private/android_filesystem_config.h> | 27 | #include <private/android_filesystem_config.h> |
28 | #include <private/fs_config.h> | ||
24 | 29 | ||
25 | extern const struct fs_path_config* __for_testing_only__android_dirs; | 30 | extern const fs_path_config* __for_testing_only__android_dirs; |
26 | extern const struct fs_path_config* __for_testing_only__android_files; | 31 | extern const fs_path_config* __for_testing_only__android_files; |
27 | 32 | ||
28 | static void check_one(const struct fs_path_config* paths, const std::string& prefix, | 33 | // Maximum entries in system/core/libcutils/fs_config.cpp:android_* before we |
29 | const std::string& alternate) { | 34 | // hit a nullptr termination, before we declare the list is just too big or |
30 | for (size_t idx = 0; paths[idx].prefix; ++idx) { | 35 | // could be missing the nullptr. |
31 | std::string path(paths[idx].prefix); | 36 | static constexpr size_t max_idx = 4096; |
37 | |||
38 | static bool check_unique(std::vector<const char*>& paths, const std::string& config_name, | ||
39 | const std::string& prefix) { | ||
40 | bool retval = false; | ||
41 | |||
42 | std::string alternate = "system/" + prefix; | ||
43 | |||
44 | for (size_t idx = 0; idx < paths.size(); ++idx) { | ||
45 | size_t second; | ||
46 | std::string path(paths[idx]); | ||
47 | // check if there are multiple identical paths | ||
48 | for (second = idx + 1; second < paths.size(); ++second) { | ||
49 | if (path == paths[second]) { | ||
50 | GTEST_LOG_(ERROR) << "duplicate paths in " << config_name << ": " << paths[idx]; | ||
51 | retval = true; | ||
52 | break; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | // check if path is <partition>/ | ||
32 | if (android::base::StartsWith(path, prefix.c_str())) { | 57 | if (android::base::StartsWith(path, prefix.c_str())) { |
33 | path = alternate + path.substr(prefix.length()); | 58 | // rebuild path to be system/<partition>/... to check for alias |
34 | size_t second; | 59 | path = alternate + path.substr(prefix.size()); |
35 | for (second = 0; paths[second].prefix; ++second) { | 60 | for (second = 0; second < paths.size(); ++second) { |
36 | if (path == paths[second].prefix) break; | 61 | if (path == paths[second]) { |
62 | GTEST_LOG_(ERROR) << "duplicate alias paths in " << config_name << ": " | ||
63 | << paths[idx] << " and " << paths[second] | ||
64 | << " (remove latter)"; | ||
65 | retval = true; | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | continue; | ||
70 | } | ||
71 | |||
72 | // check if path is system/<partition>/ | ||
73 | if (android::base::StartsWith(path, alternate.c_str())) { | ||
74 | // rebuild path to be <partition>/... to check for alias | ||
75 | path = prefix + path.substr(alternate.size()); | ||
76 | for (second = 0; second < paths.size(); ++second) { | ||
77 | if (path == paths[second]) break; | ||
37 | } | 78 | } |
38 | if (!paths[second].prefix) { | 79 | if (second >= paths.size()) { |
39 | // guaranteed to fail expectations, trigger test failure with | 80 | GTEST_LOG_(ERROR) << "replace path in " << config_name << ": " << paths[idx] |
40 | // a message that reports the violation as an inequality. | 81 | << " with " << path; |
41 | EXPECT_STREQ((prefix + path.substr(alternate.length())).c_str(), path.c_str()); | 82 | retval = true; |
42 | } | 83 | } |
43 | } | 84 | } |
44 | } | 85 | } |
86 | return retval; | ||
87 | } | ||
88 | |||
89 | static bool check_unique(const fs_path_config* paths, const char* type_name, | ||
90 | const std::string& prefix) { | ||
91 | std::string config("system/core/libcutils/fs_config.cpp:android_"); | ||
92 | config += type_name; | ||
93 | config += "[]"; | ||
94 | |||
95 | bool retval = false; | ||
96 | std::vector<const char*> paths_tmp; | ||
97 | for (size_t idx = 0; paths[idx].prefix; ++idx) { | ||
98 | if (idx > max_idx) { | ||
99 | GTEST_LOG_(WARNING) << config << ": has no end (missing null prefix)"; | ||
100 | retval = true; | ||
101 | break; | ||
102 | } | ||
103 | paths_tmp.push_back(paths[idx].prefix); | ||
104 | } | ||
105 | |||
106 | return check_unique(paths_tmp, config, prefix) || retval; | ||
45 | } | 107 | } |
46 | 108 | ||
47 | static void check_two(const struct fs_path_config* paths, const std::string& prefix) { | 109 | #define endof(pointer, field) (offsetof(typeof(*(pointer)), field) + sizeof((pointer)->field)) |
110 | |||
111 | static bool check_unique(const std::string& config, const std::string& prefix) { | ||
112 | int retval = false; | ||
113 | |||
114 | std::string data; | ||
115 | if (!android::base::ReadFileToString(config, &data)) return retval; | ||
116 | |||
117 | const fs_path_config_from_file* pc = | ||
118 | reinterpret_cast<const fs_path_config_from_file*>(data.c_str()); | ||
119 | size_t len = data.size(); | ||
120 | |||
121 | std::vector<const char*> paths_tmp; | ||
122 | size_t entry_number = 0; | ||
123 | while (len > 0) { | ||
124 | uint16_t host_len = (len >= endof(pc, len)) ? pc->len : INT16_MAX; | ||
125 | if (host_len > len) { | ||
126 | GTEST_LOG_(WARNING) << config << ": truncated at entry " << entry_number << " (" | ||
127 | << host_len << " > " << len << ")"; | ||
128 | const std::string unknown("?"); | ||
129 | GTEST_LOG_(WARNING) | ||
130 | << config << ": entry[" << entry_number << "]={ " | ||
131 | << "len=" << ((len >= endof(pc, len)) | ||
132 | ? android::base::StringPrintf("%" PRIu16, pc->len) | ||
133 | : unknown) | ||
134 | << ", mode=" << ((len >= endof(pc, mode)) | ||
135 | ? android::base::StringPrintf("0%" PRIo16, pc->mode) | ||
136 | : unknown) | ||
137 | << ", uid=" << ((len >= endof(pc, uid)) | ||
138 | ? android::base::StringPrintf("%" PRIu16, pc->uid) | ||
139 | : unknown) | ||
140 | << ", gid=" << ((len >= endof(pc, gid)) | ||
141 | ? android::base::StringPrintf("%" PRIu16, pc->gid) | ||
142 | : unknown) | ||
143 | << ", capabilities=" | ||
144 | << ((len >= endof(pc, capabilities)) | ||
145 | ? android::base::StringPrintf("0x%" PRIx64, pc->capabilities) | ||
146 | : unknown) | ||
147 | << ", prefix=" | ||
148 | << ((len >= offsetof(fs_path_config_from_file, prefix)) | ||
149 | ? android::base::StringPrintf( | ||
150 | "\"%.*s...", (int)(len - offsetof(fs_path_config_from_file, prefix)), | ||
151 | pc->prefix) | ||
152 | : unknown) | ||
153 | << " }"; | ||
154 | retval = true; | ||
155 | break; | ||
156 | } | ||
157 | paths_tmp.push_back(pc->prefix); | ||
158 | |||
159 | pc = reinterpret_cast<const fs_path_config_from_file*>(reinterpret_cast<const char*>(pc) + | ||
160 | host_len); | ||
161 | len -= host_len; | ||
162 | ++entry_number; | ||
163 | } | ||
164 | |||
165 | return check_unique(paths_tmp, config, prefix) || retval; | ||
166 | } | ||
167 | |||
168 | void check_two(const fs_path_config* paths, const char* type_name, const char* prefix) { | ||
48 | ASSERT_FALSE(paths == nullptr); | 169 | ASSERT_FALSE(paths == nullptr); |
49 | std::string alternate = "system/" + prefix; | 170 | ASSERT_FALSE(type_name == nullptr); |
50 | check_one(paths, prefix, alternate); | 171 | ASSERT_FALSE(prefix == nullptr); |
51 | check_one(paths, alternate, prefix); | 172 | bool check_internal = check_unique(paths, type_name, prefix); |
173 | EXPECT_FALSE(check_internal); | ||
174 | bool check_overrides = | ||
175 | check_unique(std::string("/") + prefix + "etc/fs_config_" + type_name, prefix); | ||
176 | EXPECT_FALSE(check_overrides); | ||
52 | } | 177 | } |
53 | 178 | ||
54 | TEST(fs_config, vendor_dirs_alias) { | 179 | TEST(fs_config, vendor_dirs_alias) { |
55 | check_two(__for_testing_only__android_dirs, "vendor/"); | 180 | check_two(__for_testing_only__android_dirs, "dirs", "vendor/"); |
56 | } | 181 | } |
57 | 182 | ||
58 | TEST(fs_config, vendor_files_alias) { | 183 | TEST(fs_config, vendor_files_alias) { |
59 | check_two(__for_testing_only__android_files, "vendor/"); | 184 | check_two(__for_testing_only__android_files, "files", "vendor/"); |
60 | } | 185 | } |
61 | 186 | ||
62 | TEST(fs_config, oem_dirs_alias) { | 187 | TEST(fs_config, oem_dirs_alias) { |
63 | check_two(__for_testing_only__android_dirs, "oem/"); | 188 | check_two(__for_testing_only__android_dirs, "dirs", "oem/"); |
64 | } | 189 | } |
65 | 190 | ||
66 | TEST(fs_config, oem_files_alias) { | 191 | TEST(fs_config, oem_files_alias) { |
67 | check_two(__for_testing_only__android_files, "oem/"); | 192 | check_two(__for_testing_only__android_files, "files", "oem/"); |
68 | } | 193 | } |
69 | 194 | ||
70 | TEST(fs_config, odm_dirs_alias) { | 195 | TEST(fs_config, odm_dirs_alias) { |
71 | check_two(__for_testing_only__android_dirs, "odm/"); | 196 | check_two(__for_testing_only__android_dirs, "dirs", "odm/"); |
72 | } | 197 | } |
73 | 198 | ||
74 | TEST(fs_config, odm_files_alias) { | 199 | TEST(fs_config, odm_files_alias) { |
75 | check_two(__for_testing_only__android_files, "odm/"); | 200 | check_two(__for_testing_only__android_files, "files", "odm/"); |
76 | } | 201 | } |