1 // Copyright (C) 2016 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #define LOG_TAG "sdcard" 16 17 #include <dirent.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <linux/fuse.h> 21 #include <pthread.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <sys/inotify.h> 25 #include <sys/mount.h> 26 #include <sys/resource.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <unistd.h> 30 31 #include <android-base/file.h> 32 #include <android-base/logging.h> 33 #include <android-base/macros.h> 34 #include <android-base/stringprintf.h> 35 #include <android-base/strings.h> 36 37 #include <cutils/fs.h> 38 #include <cutils/multiuser.h> 39 #include <cutils/properties.h> 40 41 #include <libminijail.h> 42 #include <scoped_minijail.h> 43 44 #include <private/android_filesystem_config.h> 45 46 #define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs" 47 #define PROP_SDCARDFS_USER "persist.sys.sdcardfs" 48 49 static bool supports_esdfs(void) { 50 std::string filesystems; 51 if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) { 52 PLOG(ERROR) << "Could not read /proc/filesystems"; 53 return false; 54 } 55 for (const auto& fs : android::base::Split(filesystems, "\n")) { 56 if (fs.find("esdfs") != std::string::npos) return true; 57 } 58 return false; 59 } 60 61 static bool should_use_sdcardfs(void) { 62 char property[PROPERTY_VALUE_MAX]; 63 64 // Allow user to have a strong opinion about state 65 property_get(PROP_SDCARDFS_USER, property, ""); 66 if (!strcmp(property, "force_on")) { 67 LOG(WARNING) << "User explicitly enabled sdcardfs"; 68 return true; 69 } else if (!strcmp(property, "force_off")) { 70 LOG(WARNING) << "User explicitly disabled sdcardfs"; 71 return !supports_esdfs(); 72 } 73 74 // Fall back to device opinion about state 75 if (property_get_bool(PROP_SDCARDFS_DEVICE, true)) { 76 LOG(WARNING) << "Device explicitly enabled sdcardfs"; 77 return true; 78 } else { 79 LOG(WARNING) << "Device explicitly disabled sdcardfs"; 80 return !supports_esdfs(); 81 } 82 } 83 84 // NOTE: This is a vestigial program that simply exists to mount the in-kernel 85 // sdcardfs filesystem. The older FUSE-based design that used to live here has 86 // been completely removed to avoid confusion. 87 88 /* Supplementary groups to execute with. */ 89 static const gid_t kGroups[1] = { AID_PACKAGE_INFO }; 90 91 static void drop_privs(uid_t uid, gid_t gid) { 92 ScopedMinijail j(minijail_new()); 93 minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups); 94 minijail_change_gid(j.get(), gid); 95 minijail_change_uid(j.get(), uid); 96 /* minijail_enter() will abort if priv-dropping fails. */ 97 minijail_enter(j.get()); 98 } 99 100 static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path, 101 uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, 102 mode_t mask, bool derive_gid, bool default_normal, bool use_esdfs) { 103 // Try several attempts, each time with one less option, to gracefully 104 // handle older kernels that aren't updated yet. 105 for (int i = 0; i < 4; i++) { 106 std::string new_opts; 107 if (multi_user && i < 3) new_opts += "multiuser,"; 108 if (derive_gid && i < 2) new_opts += "derive_gid,"; 109 if (default_normal && i < 1) new_opts += "default_normal,"; 110 111 auto opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d", 112 fsuid, fsgid, new_opts.c_str(), mask, userid, gid); 113 if (mount(source_path.c_str(), dest_path.c_str(), use_esdfs ? "esdfs" : "sdcardfs", 114 MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) { 115 PLOG(WARNING) << "Failed to mount sdcardfs with options " << opts; 116 } else { 117 return true; 118 } 119 } 120 121 return false; 122 } 123 124 static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path, 125 gid_t gid, mode_t mask) { 126 std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid); 127 128 if (mount(source_path.c_str(), dest_path.c_str(), nullptr, 129 MS_BIND, nullptr) != 0) { 130 PLOG(ERROR) << "failed to bind mount sdcardfs filesystem"; 131 return false; 132 } 133 134 if (mount(source_path.c_str(), dest_path.c_str(), "none", 135 MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) { 136 PLOG(ERROR) << "failed to mount sdcardfs filesystem"; 137 if (umount2(dest_path.c_str(), MNT_DETACH)) 138 PLOG(WARNING) << "Failed to unmount bind"; 139 return false; 140 } 141 142 return true; 143 } 144 145 static bool sdcardfs_setup_secondary(const std::string& default_path, const std::string& source_path, 146 const std::string& dest_path, uid_t fsuid, gid_t fsgid, 147 bool multi_user, userid_t userid, gid_t gid, mode_t mask, 148 bool derive_gid, bool default_normal, bool use_esdfs) { 149 if (use_esdfs) { 150 return sdcardfs_setup(source_path, dest_path, fsuid, fsgid, multi_user, userid, gid, mask, 151 derive_gid, default_normal, use_esdfs); 152 } else { 153 return sdcardfs_setup_bind_remount(default_path, dest_path, gid, mask); 154 } 155 } 156 157 static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid, 158 gid_t gid, userid_t userid, bool multi_user, bool full_write, 159 bool derive_gid, bool default_normal, bool use_esdfs) { 160 std::string dest_path_default = "/mnt/runtime/default/" + label; 161 std::string dest_path_read = "/mnt/runtime/read/" + label; 162 std::string dest_path_write = "/mnt/runtime/write/" + label; 163 164 umask(0); 165 if (multi_user) { 166 // Multi-user storage is fully isolated per user, so "other" 167 // permissions are completely masked off. 168 if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, 169 AID_SDCARD_RW, 0006, derive_gid, default_normal, use_esdfs) || 170 !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_read, uid, gid, 171 multi_user, userid, AID_EVERYBODY, 0027, derive_gid, 172 default_normal, use_esdfs) || 173 !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid, 174 multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0027, 175 derive_gid, default_normal, use_esdfs)) { 176 LOG(FATAL) << "failed to sdcardfs_setup"; 177 } 178 } else { 179 // Physical storage is readable by all users on device, but 180 // the Android directories are masked off to a single user 181 // deep inside attr_from_stat(). 182 if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, 183 AID_SDCARD_RW, 0006, derive_gid, default_normal, use_esdfs) || 184 !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_read, uid, gid, 185 multi_user, userid, AID_EVERYBODY, full_write ? 0027 : 0022, 186 derive_gid, default_normal, use_esdfs) || 187 !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid, 188 multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0022, 189 derive_gid, default_normal, use_esdfs)) { 190 LOG(FATAL) << "failed to sdcardfs_setup"; 191 } 192 } 193 194 // Will abort if priv-dropping fails. 195 drop_privs(uid, gid); 196 197 if (multi_user) { 198 std::string obb_path = source_path + "/obb"; 199 fs_prepare_dir(obb_path.c_str(), 0775, uid, gid); 200 } 201 202 exit(0); 203 } 204 205 static int usage() { 206 LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>" 207 << " -u: specify UID to run as" 208 << " -g: specify GID to run as" 209 << " -U: specify user ID that owns device" 210 << " -m: source_path is multi-user" 211 << " -w: runtime write mount has full write access" 212 << " -P preserve owners on the lower file system"; 213 return 1; 214 } 215 216 int main(int argc, char **argv) { 217 const char *source_path = NULL; 218 const char *label = NULL; 219 uid_t uid = 0; 220 gid_t gid = 0; 221 userid_t userid = 0; 222 bool multi_user = false; 223 bool full_write = false; 224 bool derive_gid = false; 225 bool default_normal = false; 226 int i; 227 struct rlimit rlim; 228 int fs_version; 229 230 setenv("ANDROID_LOG_TAGS", "*:v", 1); 231 android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); 232 233 int opt; 234 while ((opt = getopt(argc, argv, "u:g:U:mwGi")) != -1) { 235 switch (opt) { 236 case 'u': 237 uid = strtoul(optarg, NULL, 10); 238 break; 239 case 'g': 240 gid = strtoul(optarg, NULL, 10); 241 break; 242 case 'U': 243 userid = strtoul(optarg, NULL, 10); 244 break; 245 case 'm': 246 multi_user = true; 247 break; 248 case 'w': 249 full_write = true; 250 break; 251 case 'G': 252 derive_gid = true; 253 break; 254 case 'i': 255 default_normal = true; 256 break; 257 case '?': 258 default: 259 return usage(); 260 } 261 } 262 263 for (i = optind; i < argc; i++) { 264 char* arg = argv[i]; 265 if (!source_path) { 266 source_path = arg; 267 } else if (!label) { 268 label = arg; 269 } else { 270 LOG(ERROR) << "too many arguments"; 271 return usage(); 272 } 273 } 274 275 if (!source_path) { 276 LOG(ERROR) << "no source path specified"; 277 return usage(); 278 } 279 if (!label) { 280 LOG(ERROR) << "no label specified"; 281 return usage(); 282 } 283 if (!uid || !gid) { 284 LOG(ERROR) << "uid and gid must be nonzero"; 285 return usage(); 286 } 287 288 rlim.rlim_cur = 8192; 289 rlim.rlim_max = 8192; 290 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { 291 PLOG(ERROR) << "setting RLIMIT_NOFILE failed"; 292 } 293 294 while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) { 295 LOG(ERROR) << "installd fs upgrade not yet complete; waiting..."; 296 sleep(1); 297 } 298 299 run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write, derive_gid, 300 default_normal, !should_use_sdcardfs()); 301 return 1; 302 } 303