sdcard.cpp revision fc592327a94dcfaac0f14b991ed7cab36c72551b
1c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// Copyright (C) 2016 The Android Open Source Project 2c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// 3c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// Licensed under the Apache License, Version 2.0 (the "License"); 4c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// you may not use this file except in compliance with the License. 5c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// You may obtain a copy of the License at 6c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// 7c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// http://www.apache.org/licenses/LICENSE-2.0 8c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// 9c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// Unless required by applicable law or agreed to in writing, software 10c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// distributed under the License is distributed on an "AS IS" BASIS, 11c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// See the License for the specific language governing permissions and 13c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes// limitations under the License. 14c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 15c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#define LOG_TAG "sdcard" 16c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 17c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <dirent.h> 18c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <errno.h> 19c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <fcntl.h> 20c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <linux/fuse.h> 21c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <pthread.h> 22c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <stdlib.h> 23c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <string.h> 24c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <sys/inotify.h> 25c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <sys/mount.h> 26c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <sys/resource.h> 27c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <sys/stat.h> 28c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <sys/types.h> 29c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <unistd.h> 30c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 319526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg#include <android-base/file.h> 32c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes#include <android-base/logging.h> 33bae15b4f46e2848b43b32a85f346ad2a3163240cJorge Lucangeli Obes#include <android-base/macros.h> 349526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg#include <android-base/stringprintf.h> 359526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg#include <android-base/strings.h> 36c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes 37c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <cutils/fs.h> 38c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <cutils/multiuser.h> 399526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg#include <cutils/properties.h> 409526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 41c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <packagelistparser/packagelistparser.h> 42c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 43c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes#include <libminijail.h> 44c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes#include <scoped_minijail.h> 45c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes 46c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include <private/android_filesystem_config.h> 47c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 48c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// README 49c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 50c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// What is this? 51c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 52c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// sdcard is a program that uses FUSE to emulate FAT-on-sdcard style 53c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// directory permissions (all files are given fixed owner, group, and 54c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// permissions at creation, owner, group, and permissions are not 55c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// changeable, symlinks and hardlinks are not createable, etc. 56c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 57c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// See usage() for command line options. 58c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 59c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// It must be run as root, but will drop to requested UID/GID as soon as it 60c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// mounts a filesystem. It will refuse to run if requested UID/GID are zero. 61c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 62c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// Things I believe to be true: 63c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 64c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK, 65c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// CREAT) must bump that node's refcount 66c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// - don't forget that FORGET can forget multiple references (req->nlookup) 67c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// - if an op that returns a fuse_entry fails writing the reply to the 68c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// kernel, you must rollback the refcount to reflect the reference the 69c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// kernel did not actually acquire 70c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 71c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// This daemon can also derive custom filesystem permissions based on directory 72c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// structure when requested. These custom permissions support several features: 73c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// 74c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// - Apps can access their own files in /Android/data/com.example/ without 75c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// requiring any additional GIDs. 76c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// - Separate permissions for protecting directories like Pictures and Music. 77c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes// - Multi-user separation on the same physical device. 78c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 79c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes#include "fuse.h" 80c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 819526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs" 829526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg#define PROP_SDCARDFS_USER "persist.sys.sdcardfs" 839526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 84c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes/* Supplementary groups to execute with. */ 85c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic const gid_t kGroups[1] = { AID_PACKAGE_INFO }; 86c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 87c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic bool package_parse_callback(pkg_info *info, void *userdata) { 88c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse_global *global = (struct fuse_global *)userdata; 89d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes bool res = global->package_to_appid->emplace(info->name, info->uid).second; 90c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes packagelist_free(info); 91d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes return res; 92c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 93c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 94c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic bool read_package_list(struct fuse_global* global) { 95c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes pthread_mutex_lock(&global->lock); 96c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 97d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes global->package_to_appid->clear(); 98c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes bool rc = packagelist_parse(package_parse_callback, global); 99e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes DLOG(INFO) << "read_package_list: found " << global->package_to_appid->size() << " packages"; 100c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 101d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes // Regenerate ownership details using newly loaded mapping. 102c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes derive_permissions_recursive_locked(global->fuse_default, &global->root); 103c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 104c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes pthread_mutex_unlock(&global->lock); 105c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 106c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return rc; 107c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 108c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 109c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic void watch_package_list(struct fuse_global* global) { 110c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct inotify_event *event; 111c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes char event_buf[512]; 112c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 113c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int nfd = inotify_init(); 114d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris if (nfd == -1) { 115c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(ERROR) << "inotify_init failed"; 116c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return; 117c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 118c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 119c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes bool active = false; 120c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes while (1) { 121c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (!active) { 122c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF); 123c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (res == -1) { 124c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (errno == ENOENT || errno == EACCES) { 125c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes /* Framework may not have created the file yet, sleep and retry. */ 126c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "missing \"" << PACKAGES_LIST_FILE << "\"; retrying..."; 127c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes sleep(3); 128c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes continue; 129c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } else { 130c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(ERROR) << "inotify_add_watch failed"; 131c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return; 132c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 133c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 134c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 135c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes /* Watch above will tell us about any future changes, so 136c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes * read the current state. */ 137c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (read_package_list(global) == false) { 138c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "read_package_list failed"; 139c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return; 140c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 141c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes active = true; 142c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 143c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 144c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int event_pos = 0; 145d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris ssize_t res = TEMP_FAILURE_RETRY(read(nfd, event_buf, sizeof(event_buf))); 146d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris if (res == -1) { 147c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(ERROR) << "failed to read inotify event"; 148c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return; 149d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris } else if (static_cast<size_t>(res) < sizeof(*event)) { 150d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris LOG(ERROR) << "failed to read inotify event: read " << res << " expected " 151d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris << sizeof(event_buf); 152d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris return; 153c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 154c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 155d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris while (res >= static_cast<ssize_t>(sizeof(*event))) { 156c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int event_size; 157d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos); 158c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 159e157b253d4e8708779d8bad2e21929fedbe0168cJorge Lucangeli Obes DLOG(INFO) << "inotify event: " << std::hex << event->mask << std::dec; 160c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if ((event->mask & IN_IGNORED) == IN_IGNORED) { 161c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes /* Previously watched file was deleted, probably due to move 162c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes * that swapped in new data; re-arm the watch and read. */ 163c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes active = false; 164c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 165c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 166c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes event_size = sizeof(*event) + event->len; 167c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes res -= event_size; 168c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes event_pos += event_size; 169c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 170c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 171c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 172c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 173c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) { 174c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes char opts[256]; 175c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 176d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris fuse->fd = TEMP_FAILURE_RETRY(open("/dev/fuse", O_RDWR | O_CLOEXEC)); 177c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (fuse->fd == -1) { 178c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(ERROR) << "failed to open fuse device"; 179c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return -1; 180c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 181c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 182c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes umount2(fuse->dest_path, MNT_DETACH); 183c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 184c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes snprintf(opts, sizeof(opts), 185c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", 186c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fuse->fd, fuse->global->uid, fuse->global->gid); 187d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, 188d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris opts) == -1) { 189c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(ERROR) << "failed to mount fuse filesystem"; 190c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return -1; 191c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 192c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 193c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fuse->gid = gid; 194c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fuse->mask = mask; 195c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 196c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return 0; 197c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 198c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 199c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obesstatic void drop_privs(uid_t uid, gid_t gid) { 200c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes ScopedMinijail j(minijail_new()); 201bae15b4f46e2848b43b32a85f346ad2a3163240cJorge Lucangeli Obes minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups); 202c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes minijail_change_gid(j.get(), gid); 203c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes minijail_change_uid(j.get(), uid); 204c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes /* minijail_enter() will abort if priv-dropping fails. */ 205c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes minijail_enter(j.get()); 206c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes} 207c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes 208c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic void* start_handler(void* data) { 209c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse_handler* handler = static_cast<fuse_handler*>(data); 210c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handle_fuse_requests(handler); 211c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return NULL; 212c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 213c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 214c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic void run(const char* source_path, const char* label, uid_t uid, 215c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes gid_t gid, userid_t userid, bool multi_user, bool full_write) { 216c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse_global global; 217c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse fuse_default; 218c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse fuse_read; 219c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse fuse_write; 220c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse_handler handler_default; 221c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse_handler handler_read; 222c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct fuse_handler handler_write; 223c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes pthread_t thread_default; 224c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes pthread_t thread_read; 225c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes pthread_t thread_write; 226c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 227c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&global, 0, sizeof(global)); 228c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&fuse_default, 0, sizeof(fuse_default)); 229c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&fuse_read, 0, sizeof(fuse_read)); 230c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&fuse_write, 0, sizeof(fuse_write)); 231c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&handler_default, 0, sizeof(handler_default)); 232c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&handler_read, 0, sizeof(handler_read)); 233c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&handler_write, 0, sizeof(handler_write)); 234c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 235c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes pthread_mutex_init(&global.lock, NULL); 236d6d8faa69068d92e0e4021fced181b448d4e8cbdJorge Lucangeli Obes global.package_to_appid = new AppIdMap; 237c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.uid = uid; 238c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.gid = gid; 239c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.multi_user = multi_user; 240c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.next_generation = 0; 241c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.inode_ctr = 1; 242c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 243c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes memset(&global.root, 0, sizeof(global.root)); 244c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.nid = FUSE_ROOT_ID; /* 1 */ 245c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.refcount = 2; 246c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.namelen = strlen(source_path); 247c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.name = strdup(source_path); 248c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.userid = userid; 249c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.uid = AID_ROOT; 250c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.under_android = false; 251c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 252c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes strcpy(global.source_path, source_path); 253c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 254c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (multi_user) { 255c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.perm = PERM_PRE_ROOT; 256c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path); 257c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } else { 258c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.root.perm = PERM_ROOT; 259c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path); 260c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 261c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 262c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fuse_default.global = &global; 263c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fuse_read.global = &global; 264c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fuse_write.global = &global; 265c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 266c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.fuse_default = &fuse_default; 267c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.fuse_read = &fuse_read; 268c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes global.fuse_write = &fuse_write; 269c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 270c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label); 271c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label); 272c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label); 273c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 274c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handler_default.fuse = &fuse_default; 275c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handler_read.fuse = &fuse_read; 276c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handler_write.fuse = &fuse_write; 277c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 278c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handler_default.token = 0; 279c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handler_read.token = 1; 280c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes handler_write.token = 2; 281c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 282c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes umask(0); 283c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 284c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (multi_user) { 285c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes /* Multi-user storage is fully isolated per user, so "other" 286c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes * permissions are completely masked off. */ 287c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006) 288c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes || fuse_setup(&fuse_read, AID_EVERYBODY, 0027) 289c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) { 290c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(FATAL) << "failed to fuse_setup"; 291c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 292c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } else { 293c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes /* Physical storage is readable by all users on device, but 294c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes * the Android directories are masked off to a single user 295c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes * deep inside attr_from_stat(). */ 296c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006) 297c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022) 298c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) { 299c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(FATAL) << "failed to fuse_setup"; 300c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 301c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 302c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 303c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes // Will abort if priv-dropping fails. 304c96f53e2fe7e67bd8a412575355e1b816f0aceafJorge Lucangeli Obes drop_privs(uid, gid); 305c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 306c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (multi_user) { 307c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes fs_prepare_dir(global.obb_path, 0775, uid, gid); 308c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 309c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 310c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (pthread_create(&thread_default, NULL, start_handler, &handler_default) 311c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes || pthread_create(&thread_read, NULL, start_handler, &handler_read) 312c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes || pthread_create(&thread_write, NULL, start_handler, &handler_write)) { 313c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(FATAL) << "failed to pthread_create"; 314c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 315c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 316c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes watch_package_list(&global); 317c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(FATAL) << "terminated prematurely"; 318c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 319c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 3209526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenbergstatic bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path, uid_t fsuid, 3219526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) { 3229526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg std::string opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d", 3239526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid); 3249526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3259526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs", 326d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) { 3279526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg PLOG(ERROR) << "failed to mount sdcardfs filesystem"; 3289526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return false; 3299526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 3309526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3319526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return true; 3329526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg} 3339526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 334fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenbergstatic bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path, 335fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg gid_t gid, mode_t mask) { 336fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid); 337fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg 338fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg if (mount(source_path.c_str(), dest_path.c_str(), nullptr, 339fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg MS_BIND, nullptr) != 0) { 340fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg PLOG(ERROR) << "failed to bind mount sdcardfs filesystem"; 341fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg return false; 342fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg } 343fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg 344fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg if (mount(source_path.c_str(), dest_path.c_str(), "none", 345fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) { 346fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg PLOG(ERROR) << "failed to mount sdcardfs filesystem"; 347fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg if (umount2(dest_path.c_str(), MNT_DETACH)) 348fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg PLOG(WARNING) << "Failed to unmount bind"; 349fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg return false; 350fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg } 351fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg 352fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg return true; 353fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg} 354fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg 3559526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenbergstatic void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid, 3569526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg gid_t gid, userid_t userid, bool multi_user, bool full_write) { 3579526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg std::string dest_path_default = "/mnt/runtime/default/" + label; 3589526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg std::string dest_path_read = "/mnt/runtime/read/" + label; 3599526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg std::string dest_path_write = "/mnt/runtime/write/" + label; 3609526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3619526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg umask(0); 3629526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (multi_user) { 3639526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // Multi-user storage is fully isolated per user, so "other" 3649526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // permissions are completely masked off. 3659526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, 3669526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg AID_SDCARD_RW, 0006) 367fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) 368fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, 3699526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg AID_EVERYBODY, full_write ? 0007 : 0027)) { 3709526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg LOG(FATAL) << "failed to sdcardfs_setup"; 3719526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 3729526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } else { 3739526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // Physical storage is readable by all users on device, but 3749526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // the Android directories are masked off to a single user 3759526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // deep inside attr_from_stat(). 3769526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid, 3779526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg AID_SDCARD_RW, 0006) 378fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, 3799526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg AID_EVERYBODY, full_write ? 0027 : 0022) 380fc592327a94dcfaac0f14b991ed7cab36c72551bDaniel Rosenberg || !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, 3819526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg AID_EVERYBODY, full_write ? 0007 : 0022)) { 3829526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg LOG(FATAL) << "failed to sdcardfs_setup"; 3839526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 3849526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 3859526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3869526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // Will abort if priv-dropping fails. 3879526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg drop_privs(uid, gid); 3889526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3899526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (multi_user) { 3909526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg std::string obb_path = source_path + "/obb"; 3919526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg fs_prepare_dir(obb_path.c_str(), 0775, uid, gid); 3929526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 3939526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3949526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg exit(0); 3959526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg} 3969526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 3979526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenbergstatic bool supports_sdcardfs(void) { 3989526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg std::string filesystems; 3999526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) { 4009526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg PLOG(ERROR) << "Could not read /proc/filesystems"; 4019526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return false; 4029526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 4039526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg for (const auto& fs : android::base::Split(filesystems, "\n")) { 4049526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (fs.find("sdcardfs") != std::string::npos) return true; 4059526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 4069526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return false; 4079526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg} 4089526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 4099526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenbergstatic bool should_use_sdcardfs(void) { 4109526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg char property[PROPERTY_VALUE_MAX]; 4119526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 4129526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // Allow user to have a strong opinion about state 4139526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg property_get(PROP_SDCARDFS_USER, property, ""); 4149526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (!strcmp(property, "force_on")) { 4159526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg LOG(WARNING) << "User explicitly enabled sdcardfs"; 4169526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return supports_sdcardfs(); 4179526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } else if (!strcmp(property, "force_off")) { 4189526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg LOG(WARNING) << "User explicitly disabled sdcardfs"; 4199526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return false; 4209526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 4219526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 4229526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg // Fall back to device opinion about state 4239526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) { 4249526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg LOG(WARNING) << "Device explicitly enabled sdcardfs"; 4259526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return supports_sdcardfs(); 4269526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } else { 4279526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg LOG(WARNING) << "Device explicitly disabled sdcardfs"; 4289526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg return false; 4299526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 4309526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg} 4319526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg 432c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesstatic int usage() { 433c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>" 434c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes << " -u: specify UID to run as" 435c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes << " -g: specify GID to run as" 436c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes << " -U: specify user ID that owns device" 437c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes << " -m: source_path is multi-user" 438c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes << " -w: runtime write mount has full write access"; 439c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return 1; 440c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 441c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 442c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obesint main(int argc, char **argv) { 443c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes const char *source_path = NULL; 444c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes const char *label = NULL; 445c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes uid_t uid = 0; 446c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes gid_t gid = 0; 447c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes userid_t userid = 0; 448c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes bool multi_user = false; 449c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes bool full_write = false; 450c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int i; 451c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes struct rlimit rlim; 452c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int fs_version; 453c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 454c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes int opt; 455c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) { 456c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes switch (opt) { 457c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes case 'u': 458c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes uid = strtoul(optarg, NULL, 10); 459c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes break; 460c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes case 'g': 461c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes gid = strtoul(optarg, NULL, 10); 462c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes break; 463c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes case 'U': 464c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes userid = strtoul(optarg, NULL, 10); 465c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes break; 466c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes case 'm': 467c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes multi_user = true; 468c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes break; 469c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes case 'w': 470c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes full_write = true; 471c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes break; 472c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes case '?': 473c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes default: 474c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return usage(); 475c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 476c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 477c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 478c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes for (i = optind; i < argc; i++) { 479c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes char* arg = argv[i]; 480c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (!source_path) { 481c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes source_path = arg; 482c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } else if (!label) { 483c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes label = arg; 484c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } else { 485c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "too many arguments"; 486c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return usage(); 487c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 488c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 489c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 490c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (!source_path) { 491c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "no source path specified"; 492c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return usage(); 493c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 494c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (!label) { 495c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "no label specified"; 496c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return usage(); 497c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 498c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes if (!uid || !gid) { 499c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "uid and gid must be nonzero"; 500c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return usage(); 501c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 502c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 503c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes rlim.rlim_cur = 8192; 504c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes rlim.rlim_max = 8192; 505d6b0d375490f9c31da0131582b7d77d1fdd79706Christopher Ferris if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { 506c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes PLOG(ERROR) << "setting RLIMIT_NOFILE failed"; 507c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 508c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 509c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) { 510c9e1710accb44dd95fc8e088f5139844e8d1268cJorge Lucangeli Obes LOG(ERROR) << "installd fs upgrade not yet complete; waiting..."; 511c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes sleep(1); 512c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes } 513c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes 5149526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg if (should_use_sdcardfs()) { 5159526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write); 5169526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } else { 5179526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg run(source_path, label, uid, gid, userid, multi_user, full_write); 5189526819c7068266c1d063c7c4db039a534c7afffDaniel Rosenberg } 519c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes return 1; 520c255f25ccb700880483c73d9ff823bf9540dd616Jorge Lucangeli Obes} 521