1 /* 2 * Copyright (C) 2007 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 <private/fs_config.h> 18 19 // This file is used to define the properties of the filesystem 20 // images generated by build tools (mkbootfs and mkyaffs2image) and 21 // by the device side of adb. 22 23 #define LOG_TAG "fs_config" 24 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <stdint.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <sys/stat.h> 32 #include <sys/types.h> 33 34 #include <log/log.h> 35 #include <private/android_filesystem_config.h> 36 #include <utils/Compat.h> 37 38 #ifndef O_BINARY 39 #define O_BINARY 0 40 #endif 41 42 // My kingdom for <endian.h> 43 static inline uint16_t get2LE(const uint8_t* src) { 44 return src[0] | (src[1] << 8); 45 } 46 47 static inline uint64_t get8LE(const uint8_t* src) { 48 uint32_t low, high; 49 50 low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); 51 high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24); 52 return ((uint64_t)high << 32) | (uint64_t)low; 53 } 54 55 #define ALIGN(x, alignment) (((x) + ((alignment)-1)) & ~((alignment)-1)) 56 57 // Rules for directories. 58 // These rules are applied based on "first match", so they 59 // should start with the most specific path and work their 60 // way up to the root. 61 62 static const struct fs_path_config android_dirs[] = { 63 // clang-format off 64 { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, 65 { 00555, AID_ROOT, AID_ROOT, 0, "config" }, 66 { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, 67 { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, 68 { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" }, 69 { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, 70 { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" }, 71 { 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" }, 72 { 00771, AID_SHELL, AID_SHELL, 0, "data/local" }, 73 { 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" }, 74 { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, 75 { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, 76 { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, 77 { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, 78 { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest" }, 79 { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64" }, 80 { 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" }, 81 { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, 82 { 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" }, 83 { 00755, AID_ROOT, AID_SHELL, 0, "product/bin" }, 84 { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, 85 { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, 86 { 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" }, 87 { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, 88 { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, 89 { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, 90 { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, 91 { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, 92 { 00755, AID_ROOT, AID_ROOT, 0, 0 }, 93 // clang-format on 94 }; 95 #ifndef __ANDROID_VNDK__ 96 auto __for_testing_only__android_dirs = android_dirs; 97 #endif 98 99 // Rules for files. 100 // These rules are applied based on "first match", so they 101 // should start with the most specific path and work their 102 // way up to the root. Prefixes ending in * denotes wildcard 103 // and will allow partial matches. 104 static const char sys_conf_dir[] = "/system/etc/fs_config_dirs"; 105 static const char sys_conf_file[] = "/system/etc/fs_config_files"; 106 // No restrictions are placed on the vendor and oem file-system config files, 107 // although the developer is advised to restrict the scope to the /vendor or 108 // oem/ file-system since the intent is to provide support for customized 109 // portions of a separate vendor.img or oem.img. Has to remain open so that 110 // customization can also land on /system/vendor, /system/oem or /system/odm. 111 // We expect build-time checking or filtering when constructing the associated 112 // fs_config_* files (see build/tools/fs_config/fs_config_generate.c) 113 static const char ven_conf_dir[] = "/vendor/etc/fs_config_dirs"; 114 static const char ven_conf_file[] = "/vendor/etc/fs_config_files"; 115 static const char oem_conf_dir[] = "/oem/etc/fs_config_dirs"; 116 static const char oem_conf_file[] = "/oem/etc/fs_config_files"; 117 static const char odm_conf_dir[] = "/odm/etc/fs_config_dirs"; 118 static const char odm_conf_file[] = "/odm/etc/fs_config_files"; 119 static const char* conf[][2] = { 120 {sys_conf_file, sys_conf_dir}, 121 {ven_conf_file, ven_conf_dir}, 122 {oem_conf_file, oem_conf_dir}, 123 {odm_conf_file, odm_conf_dir}, 124 }; 125 126 // Do not use android_files to grant Linux capabilities. Use ambient capabilities in their 127 // associated init.rc file instead. See https://source.android.com/devices/tech/config/ambient. 128 129 // Do not place any new vendor/, data/vendor/, etc entries in android_files. 130 // Vendor entries should be done via a vendor or device specific config.fs. 131 // See https://source.android.com/devices/tech/config/filesystem#using-file-system-capabilities 132 static const struct fs_path_config android_files[] = { 133 // clang-format off 134 { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, 135 { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral/*" }, 136 { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, 137 { 00644, AID_APP, AID_APP, 0, "data/data/*" }, 138 { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, 139 { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest/tests.txt" }, 140 { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" }, 141 { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" }, 142 { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" }, 143 { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" }, // legacy 144 { 00600, AID_ROOT, AID_ROOT, 0, "system/etc/prop.default" }, 145 { 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" }, 146 { 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" }, 147 { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_dir + 1 }, 148 { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_file + 1 }, 149 { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_dir + 1 }, 150 { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_file + 1 }, 151 { 00600, AID_ROOT, AID_ROOT, 0, "product/build.prop" }, 152 { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, 153 { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" }, 154 { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" }, 155 { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" }, 156 { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, 157 { 00700, AID_ROOT, AID_ROOT, 0, "system/bin/secilc" }, 158 { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, 159 { 00600, AID_ROOT, AID_ROOT, 0, "system/build.prop" }, 160 { 00444, AID_ROOT, AID_ROOT, 0, sys_conf_dir + 1 }, 161 { 00444, AID_ROOT, AID_ROOT, 0, sys_conf_file + 1 }, 162 { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" }, 163 { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" }, 164 { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" }, 165 { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, 166 { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, 167 { 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" }, 168 { 00600, AID_ROOT, AID_ROOT, 0, "vendor/build.prop" }, 169 { 00600, AID_ROOT, AID_ROOT, 0, "vendor/default.prop" }, 170 { 00444, AID_ROOT, AID_ROOT, 0, ven_conf_dir + 1 }, 171 { 00444, AID_ROOT, AID_ROOT, 0, ven_conf_file + 1 }, 172 173 // the following two files are INTENTIONALLY set-uid, but they 174 // are NOT included on user builds. 175 { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, 176 { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, 177 178 // the following files have enhanced capabilities and ARE included 179 // in user builds. 180 { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), 181 "system/bin/inputflinger" }, 182 { 00550, AID_LOGD, AID_LOGD, CAP_MASK_LONG(CAP_SYSLOG) | 183 CAP_MASK_LONG(CAP_AUDIT_CONTROL) | 184 CAP_MASK_LONG(CAP_SETGID), 185 "system/bin/logd" }, 186 { 00550, AID_SYSTEM, AID_LOG, CAP_MASK_LONG(CAP_SYSLOG), 187 "system/bin/bootstat" }, 188 { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | 189 CAP_MASK_LONG(CAP_SETGID), 190 "system/bin/run-as" }, 191 192 // Support FIFO scheduling mode in SurfaceFlinger. 193 { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE), 194 "system/bin/surfaceflinger" }, 195 // generic defaults 196 { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, 197 { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, 198 { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, 199 { 00755, AID_ROOT, AID_SHELL, 0, "product/bin/*" }, 200 { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, 201 { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, 202 { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, 203 { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, 204 { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, 205 { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, 206 { 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" }, 207 { 00644, AID_ROOT, AID_ROOT, 0, 0 }, 208 // clang-format on 209 }; 210 #ifndef __ANDROID_VNDK__ 211 auto __for_testing_only__android_files = android_files; 212 #endif 213 214 static size_t strip(const char* path, size_t len, const char suffix[]) { 215 if (len < strlen(suffix)) return len; 216 if (strncmp(path + len - strlen(suffix), suffix, strlen(suffix))) return len; 217 return len - strlen(suffix); 218 } 219 220 static int fs_config_open(int dir, int which, const char* target_out_path) { 221 int fd = -1; 222 223 if (target_out_path && *target_out_path) { 224 // target_out_path is the path to the directory holding content of 225 // system partition but as we cannot guarantee it ends with '/system' 226 // or with or without a trailing slash, need to strip them carefully. 227 char* name = NULL; 228 size_t len = strlen(target_out_path); 229 len = strip(target_out_path, len, "/"); 230 len = strip(target_out_path, len, "/system"); 231 if (asprintf(&name, "%.*s%s", (int)len, target_out_path, conf[which][dir]) != -1) { 232 fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY)); 233 free(name); 234 } 235 } 236 if (fd < 0) { 237 fd = TEMP_FAILURE_RETRY(open(conf[which][dir], O_RDONLY | O_BINARY)); 238 } 239 return fd; 240 } 241 242 // if path is "odm/<stuff>", "oem/<stuff>", "product/<stuff>" or 243 // "vendor/<stuff>" 244 static bool is_partition(const char* path, size_t len) { 245 static const char* partitions[] = {"odm/", "oem/", "product/", "vendor/"}; 246 for (size_t i = 0; i < (sizeof(partitions) / sizeof(partitions[0])); ++i) { 247 size_t plen = strlen(partitions[i]); 248 if (len <= plen) continue; 249 if (!strncmp(path, partitions[i], plen)) return true; 250 } 251 return false; 252 } 253 254 static inline bool prefix_cmp(bool partial, const char* prefix, size_t len, const char* path, 255 size_t plen) { 256 return ((partial && plen >= len) || (plen == len)) && !strncmp(prefix, path, len); 257 } 258 259 // alias prefixes of "<partition>/<stuff>" to "system/<partition>/<stuff>" or 260 // "system/<partition>/<stuff>" to "<partition>/<stuff>" 261 static bool fs_config_cmp(bool partial, const char* prefix, size_t len, const char* path, 262 size_t plen) { 263 // If name ends in * then allow partial matches. 264 if (!partial && prefix[len - 1] == '*') { 265 len--; 266 partial = true; 267 } 268 269 if (prefix_cmp(partial, prefix, len, path, plen)) return true; 270 271 static const char system[] = "system/"; 272 if (!strncmp(path, system, strlen(system))) { 273 path += strlen(system); 274 plen -= strlen(system); 275 } else if (len <= strlen(system)) { 276 return false; 277 } else if (strncmp(prefix, system, strlen(system))) { 278 return false; 279 } else { 280 prefix += strlen(system); 281 len -= strlen(system); 282 } 283 return is_partition(prefix, len) && prefix_cmp(partial, prefix, len, path, plen); 284 } 285 #ifndef __ANDROID_VNDK__ 286 auto __for_testing_only__fs_config_cmp = fs_config_cmp; 287 #endif 288 289 void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, 290 unsigned* mode, uint64_t* capabilities) { 291 const struct fs_path_config* pc; 292 size_t which, plen; 293 294 if (path[0] == '/') { 295 path++; 296 } 297 298 plen = strlen(path); 299 300 for (which = 0; which < (sizeof(conf) / sizeof(conf[0])); ++which) { 301 struct fs_path_config_from_file header; 302 303 int fd = fs_config_open(dir, which, target_out_path); 304 if (fd < 0) continue; 305 306 while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) { 307 char* prefix; 308 uint16_t host_len = get2LE((const uint8_t*)&header.len); 309 ssize_t len, remainder = host_len - sizeof(header); 310 if (remainder <= 0) { 311 ALOGE("%s len is corrupted", conf[which][dir]); 312 break; 313 } 314 prefix = static_cast<char*>(calloc(1, remainder)); 315 if (!prefix) { 316 ALOGE("%s out of memory", conf[which][dir]); 317 break; 318 } 319 if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) { 320 free(prefix); 321 ALOGE("%s prefix is truncated", conf[which][dir]); 322 break; 323 } 324 len = strnlen(prefix, remainder); 325 if (len >= remainder) { // missing a terminating null 326 free(prefix); 327 ALOGE("%s is corrupted", conf[which][dir]); 328 break; 329 } 330 if (fs_config_cmp(dir, prefix, len, path, plen)) { 331 free(prefix); 332 close(fd); 333 *uid = get2LE((const uint8_t*)&(header.uid)); 334 *gid = get2LE((const uint8_t*)&(header.gid)); 335 *mode = (*mode & (~07777)) | get2LE((const uint8_t*)&(header.mode)); 336 *capabilities = get8LE((const uint8_t*)&(header.capabilities)); 337 return; 338 } 339 free(prefix); 340 } 341 close(fd); 342 } 343 344 for (pc = dir ? android_dirs : android_files; pc->prefix; pc++) { 345 if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) { 346 break; 347 } 348 } 349 *uid = pc->uid; 350 *gid = pc->gid; 351 *mode = (*mode & (~07777)) | pc->mode; 352 *capabilities = pc->capabilities; 353 } 354 355 ssize_t fs_config_generate(char* buffer, size_t length, const struct fs_path_config* pc) { 356 struct fs_path_config_from_file* p = (struct fs_path_config_from_file*)buffer; 357 size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t)); 358 359 if ((length < len) || (len > UINT16_MAX)) { 360 return -ENOSPC; 361 } 362 memset(p, 0, len); 363 uint16_t host_len = len; 364 p->len = get2LE((const uint8_t*)&host_len); 365 p->mode = get2LE((const uint8_t*)&(pc->mode)); 366 p->uid = get2LE((const uint8_t*)&(pc->uid)); 367 p->gid = get2LE((const uint8_t*)&(pc->gid)); 368 p->capabilities = get8LE((const uint8_t*)&(pc->capabilities)); 369 strcpy(p->prefix, pc->prefix); 370 return len; 371 } 372