Home | History | Annotate | Download | only in sdcard
      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 <packagelistparser/packagelistparser.h>
     42 
     43 #include <libminijail.h>
     44 #include <scoped_minijail.h>
     45 
     46 #include <private/android_filesystem_config.h>
     47 
     48 // README
     49 //
     50 // What is this?
     51 //
     52 // sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
     53 // directory permissions (all files are given fixed owner, group, and
     54 // permissions at creation, owner, group, and permissions are not
     55 // changeable, symlinks and hardlinks are not createable, etc.
     56 //
     57 // See usage() for command line options.
     58 //
     59 // It must be run as root, but will drop to requested UID/GID as soon as it
     60 // mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
     61 //
     62 // Things I believe to be true:
     63 //
     64 // - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
     65 // CREAT) must bump that node's refcount
     66 // - don't forget that FORGET can forget multiple references (req->nlookup)
     67 // - if an op that returns a fuse_entry fails writing the reply to the
     68 // kernel, you must rollback the refcount to reflect the reference the
     69 // kernel did not actually acquire
     70 //
     71 // This daemon can also derive custom filesystem permissions based on directory
     72 // structure when requested. These custom permissions support several features:
     73 //
     74 // - Apps can access their own files in /Android/data/com.example/ without
     75 // requiring any additional GIDs.
     76 // - Separate permissions for protecting directories like Pictures and Music.
     77 // - Multi-user separation on the same physical device.
     78 
     79 #include "fuse.h"
     80 
     81 #define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
     82 #define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
     83 
     84 /* Supplementary groups to execute with. */
     85 static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
     86 
     87 static bool package_parse_callback(pkg_info *info, void *userdata) {
     88     struct fuse_global *global = (struct fuse_global *)userdata;
     89     bool res = global->package_to_appid->emplace(info->name, info->uid).second;
     90     packagelist_free(info);
     91     return res;
     92 }
     93 
     94 static bool read_package_list(struct fuse_global* global) {
     95     pthread_mutex_lock(&global->lock);
     96 
     97     global->package_to_appid->clear();
     98     bool rc = packagelist_parse(package_parse_callback, global);
     99     DLOG(INFO) << "read_package_list: found " << global->package_to_appid->size() << " packages";
    100 
    101     // Regenerate ownership details using newly loaded mapping.
    102     derive_permissions_recursive_locked(global->fuse_default, &global->root);
    103 
    104     pthread_mutex_unlock(&global->lock);
    105 
    106     return rc;
    107 }
    108 
    109 static void watch_package_list(struct fuse_global* global) {
    110     struct inotify_event *event;
    111     char event_buf[512];
    112 
    113     int nfd = inotify_init();
    114     if (nfd == -1) {
    115         PLOG(ERROR) << "inotify_init failed";
    116         return;
    117     }
    118 
    119     bool active = false;
    120     while (1) {
    121         if (!active) {
    122             int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
    123             if (res == -1) {
    124                 if (errno == ENOENT || errno == EACCES) {
    125                     /* Framework may not have created the file yet, sleep and retry. */
    126                     LOG(ERROR) << "missing \"" << PACKAGES_LIST_FILE << "\"; retrying...";
    127                     sleep(3);
    128                     continue;
    129                 } else {
    130                     PLOG(ERROR) << "inotify_add_watch failed";
    131                     return;
    132                 }
    133             }
    134 
    135             /* Watch above will tell us about any future changes, so
    136              * read the current state. */
    137             if (read_package_list(global) == false) {
    138                 LOG(ERROR) << "read_package_list failed";
    139                 return;
    140             }
    141             active = true;
    142         }
    143 
    144         int event_pos = 0;
    145         ssize_t res = TEMP_FAILURE_RETRY(read(nfd, event_buf, sizeof(event_buf)));
    146         if (res == -1) {
    147             PLOG(ERROR) << "failed to read inotify event";
    148             return;
    149         } else if (static_cast<size_t>(res) < sizeof(*event)) {
    150             LOG(ERROR) << "failed to read inotify event: read " << res << " expected "
    151                        << sizeof(event_buf);
    152             return;
    153         }
    154 
    155         while (res >= static_cast<ssize_t>(sizeof(*event))) {
    156             int event_size;
    157             event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
    158 
    159             DLOG(INFO) << "inotify event: " << std::hex << event->mask << std::dec;
    160             if ((event->mask & IN_IGNORED) == IN_IGNORED) {
    161                 /* Previously watched file was deleted, probably due to move
    162                  * that swapped in new data; re-arm the watch and read. */
    163                 active = false;
    164             }
    165 
    166             event_size = sizeof(*event) + event->len;
    167             res -= event_size;
    168             event_pos += event_size;
    169         }
    170     }
    171 }
    172 
    173 static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
    174     char opts[256];
    175 
    176     fuse->fd = TEMP_FAILURE_RETRY(open("/dev/fuse", O_RDWR | O_CLOEXEC));
    177     if (fuse->fd == -1) {
    178         PLOG(ERROR) << "failed to open fuse device";
    179         return -1;
    180     }
    181 
    182     umount2(fuse->dest_path, MNT_DETACH);
    183 
    184     snprintf(opts, sizeof(opts),
    185             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
    186             fuse->fd, fuse->global->uid, fuse->global->gid);
    187     if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME,
    188               opts) == -1) {
    189         PLOG(ERROR) << "failed to mount fuse filesystem";
    190         return -1;
    191     }
    192 
    193     fuse->gid = gid;
    194     fuse->mask = mask;
    195 
    196     return 0;
    197 }
    198 
    199 static void drop_privs(uid_t uid, gid_t gid) {
    200     ScopedMinijail j(minijail_new());
    201     minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups);
    202     minijail_change_gid(j.get(), gid);
    203     minijail_change_uid(j.get(), uid);
    204     /* minijail_enter() will abort if priv-dropping fails. */
    205     minijail_enter(j.get());
    206 }
    207 
    208 static void* start_handler(void* data) {
    209     struct fuse_handler* handler = static_cast<fuse_handler*>(data);
    210     handle_fuse_requests(handler);
    211     return NULL;
    212 }
    213 
    214 static void run(const char* source_path, const char* label, uid_t uid,
    215         gid_t gid, userid_t userid, bool multi_user, bool full_write) {
    216     struct fuse_global global;
    217     struct fuse fuse_default;
    218     struct fuse fuse_read;
    219     struct fuse fuse_write;
    220     struct fuse_handler handler_default;
    221     struct fuse_handler handler_read;
    222     struct fuse_handler handler_write;
    223     pthread_t thread_default;
    224     pthread_t thread_read;
    225     pthread_t thread_write;
    226 
    227     memset(&global, 0, sizeof(global));
    228     memset(&fuse_default, 0, sizeof(fuse_default));
    229     memset(&fuse_read, 0, sizeof(fuse_read));
    230     memset(&fuse_write, 0, sizeof(fuse_write));
    231     memset(&handler_default, 0, sizeof(handler_default));
    232     memset(&handler_read, 0, sizeof(handler_read));
    233     memset(&handler_write, 0, sizeof(handler_write));
    234 
    235     pthread_mutex_init(&global.lock, NULL);
    236     global.package_to_appid = new AppIdMap;
    237     global.uid = uid;
    238     global.gid = gid;
    239     global.multi_user = multi_user;
    240     global.next_generation = 0;
    241     global.inode_ctr = 1;
    242 
    243     memset(&global.root, 0, sizeof(global.root));
    244     global.root.nid = FUSE_ROOT_ID; /* 1 */
    245     global.root.refcount = 2;
    246     global.root.namelen = strlen(source_path);
    247     global.root.name = strdup(source_path);
    248     global.root.userid = userid;
    249     global.root.uid = AID_ROOT;
    250     global.root.under_android = false;
    251 
    252     strcpy(global.source_path, source_path);
    253 
    254     if (multi_user) {
    255         global.root.perm = PERM_PRE_ROOT;
    256         snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
    257     } else {
    258         global.root.perm = PERM_ROOT;
    259         snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
    260     }
    261 
    262     fuse_default.global = &global;
    263     fuse_read.global = &global;
    264     fuse_write.global = &global;
    265 
    266     global.fuse_default = &fuse_default;
    267     global.fuse_read = &fuse_read;
    268     global.fuse_write = &fuse_write;
    269 
    270     snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
    271     snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
    272     snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
    273 
    274     handler_default.fuse = &fuse_default;
    275     handler_read.fuse = &fuse_read;
    276     handler_write.fuse = &fuse_write;
    277 
    278     handler_default.token = 0;
    279     handler_read.token = 1;
    280     handler_write.token = 2;
    281 
    282     umask(0);
    283 
    284     if (multi_user) {
    285         /* Multi-user storage is fully isolated per user, so "other"
    286          * permissions are completely masked off. */
    287         if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
    288                 || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
    289                 || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
    290             PLOG(FATAL) << "failed to fuse_setup";
    291         }
    292     } else {
    293         /* Physical storage is readable by all users on device, but
    294          * the Android directories are masked off to a single user
    295          * deep inside attr_from_stat(). */
    296         if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
    297                 || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
    298                 || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
    299             PLOG(FATAL) << "failed to fuse_setup";
    300         }
    301     }
    302 
    303     // Will abort if priv-dropping fails.
    304     drop_privs(uid, gid);
    305 
    306     if (multi_user) {
    307         fs_prepare_dir(global.obb_path, 0775, uid, gid);
    308     }
    309 
    310     if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
    311             || pthread_create(&thread_read, NULL, start_handler, &handler_read)
    312             || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
    313         LOG(FATAL) << "failed to pthread_create";
    314     }
    315 
    316     watch_package_list(&global);
    317     LOG(FATAL) << "terminated prematurely";
    318 }
    319 
    320 static bool sdcardfs_setup(const std::string& source_path, const std::string& dest_path,
    321                            uid_t fsuid, gid_t fsgid, bool multi_user, userid_t userid, gid_t gid,
    322                            mode_t mask, bool derive_gid) {
    323     std::string opts = android::base::StringPrintf(
    324         "fsuid=%d,fsgid=%d,%s%smask=%d,userid=%d,gid=%d", fsuid, fsgid,
    325         multi_user ? "multiuser," : "", derive_gid ? "derive_gid," : "", mask, userid, gid);
    326 
    327     if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
    328               MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
    329         if (derive_gid) {
    330             PLOG(ERROR) << "trying to mount sdcardfs filesystem without derive_gid";
    331             /* Maybe this isn't supported on this kernel. Try without. */
    332             opts = android::base::StringPrintf("fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
    333                                                fsuid, fsgid, multi_user ? "multiuser," : "", mask,
    334                                                userid, gid);
    335             if (mount(source_path.c_str(), dest_path.c_str(), "sdcardfs",
    336                       MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) == -1) {
    337                 PLOG(ERROR) << "failed to mount sdcardfs filesystem";
    338                 return false;
    339             }
    340         } else {
    341             PLOG(ERROR) << "failed to mount sdcardfs filesystem";
    342             return false;
    343         }
    344     }
    345     return true;
    346 }
    347 
    348 static bool sdcardfs_setup_bind_remount(const std::string& source_path, const std::string& dest_path,
    349                                         gid_t gid, mode_t mask) {
    350     std::string opts = android::base::StringPrintf("mask=%d,gid=%d", mask, gid);
    351 
    352     if (mount(source_path.c_str(), dest_path.c_str(), nullptr,
    353             MS_BIND, nullptr) != 0) {
    354         PLOG(ERROR) << "failed to bind mount sdcardfs filesystem";
    355         return false;
    356     }
    357 
    358     if (mount(source_path.c_str(), dest_path.c_str(), "none",
    359             MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()) != 0) {
    360         PLOG(ERROR) << "failed to mount sdcardfs filesystem";
    361         if (umount2(dest_path.c_str(), MNT_DETACH))
    362             PLOG(WARNING) << "Failed to unmount bind";
    363         return false;
    364     }
    365 
    366     return true;
    367 }
    368 
    369 static void run_sdcardfs(const std::string& source_path, const std::string& label, uid_t uid,
    370                          gid_t gid, userid_t userid, bool multi_user, bool full_write,
    371                          bool derive_gid) {
    372     std::string dest_path_default = "/mnt/runtime/default/" + label;
    373     std::string dest_path_read = "/mnt/runtime/read/" + label;
    374     std::string dest_path_write = "/mnt/runtime/write/" + label;
    375 
    376     umask(0);
    377     if (multi_user) {
    378         // Multi-user storage is fully isolated per user, so "other"
    379         // permissions are completely masked off.
    380         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
    381                             AID_SDCARD_RW, 0006, derive_gid) ||
    382             !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY, 0027) ||
    383             !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
    384                                          full_write ? 0007 : 0027)) {
    385             LOG(FATAL) << "failed to sdcardfs_setup";
    386         }
    387     } else {
    388         // Physical storage is readable by all users on device, but
    389         // the Android directories are masked off to a single user
    390         // deep inside attr_from_stat().
    391         if (!sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
    392                             AID_SDCARD_RW, 0006, derive_gid) ||
    393             !sdcardfs_setup_bind_remount(dest_path_default, dest_path_read, AID_EVERYBODY,
    394                                          full_write ? 0027 : 0022) ||
    395             !sdcardfs_setup_bind_remount(dest_path_default, dest_path_write, AID_EVERYBODY,
    396                                          full_write ? 0007 : 0022)) {
    397             LOG(FATAL) << "failed to sdcardfs_setup";
    398         }
    399     }
    400 
    401     // Will abort if priv-dropping fails.
    402     drop_privs(uid, gid);
    403 
    404     if (multi_user) {
    405         std::string obb_path = source_path + "/obb";
    406         fs_prepare_dir(obb_path.c_str(), 0775, uid, gid);
    407     }
    408 
    409     exit(0);
    410 }
    411 
    412 static bool supports_sdcardfs(void) {
    413     std::string filesystems;
    414     if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) {
    415         PLOG(ERROR) << "Could not read /proc/filesystems";
    416         return false;
    417     }
    418     for (const auto& fs : android::base::Split(filesystems, "\n")) {
    419         if (fs.find("sdcardfs") != std::string::npos) return true;
    420     }
    421     return false;
    422 }
    423 
    424 static bool should_use_sdcardfs(void) {
    425     char property[PROPERTY_VALUE_MAX];
    426 
    427     // Allow user to have a strong opinion about state
    428     property_get(PROP_SDCARDFS_USER, property, "");
    429     if (!strcmp(property, "force_on")) {
    430         LOG(WARNING) << "User explicitly enabled sdcardfs";
    431         return supports_sdcardfs();
    432     } else if (!strcmp(property, "force_off")) {
    433         LOG(WARNING) << "User explicitly disabled sdcardfs";
    434         return false;
    435     }
    436 
    437     // Fall back to device opinion about state
    438     if (property_get_bool(PROP_SDCARDFS_DEVICE, true)) {
    439         LOG(WARNING) << "Device explicitly enabled sdcardfs";
    440         return supports_sdcardfs();
    441     } else {
    442         LOG(WARNING) << "Device explicitly disabled sdcardfs";
    443         return false;
    444     }
    445 }
    446 
    447 static int usage() {
    448     LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>"
    449                << "    -u: specify UID to run as"
    450                << "    -g: specify GID to run as"
    451                << "    -U: specify user ID that owns device"
    452                << "    -m: source_path is multi-user"
    453                << "    -w: runtime write mount has full write access"
    454                << "    -P  preserve owners on the lower file system";
    455     return 1;
    456 }
    457 
    458 int main(int argc, char **argv) {
    459     const char *source_path = NULL;
    460     const char *label = NULL;
    461     uid_t uid = 0;
    462     gid_t gid = 0;
    463     userid_t userid = 0;
    464     bool multi_user = false;
    465     bool full_write = false;
    466     bool derive_gid = false;
    467     int i;
    468     struct rlimit rlim;
    469     int fs_version;
    470 
    471     int opt;
    472     while ((opt = getopt(argc, argv, "u:g:U:mwG")) != -1) {
    473         switch (opt) {
    474             case 'u':
    475                 uid = strtoul(optarg, NULL, 10);
    476                 break;
    477             case 'g':
    478                 gid = strtoul(optarg, NULL, 10);
    479                 break;
    480             case 'U':
    481                 userid = strtoul(optarg, NULL, 10);
    482                 break;
    483             case 'm':
    484                 multi_user = true;
    485                 break;
    486             case 'w':
    487                 full_write = true;
    488                 break;
    489             case 'G':
    490                 derive_gid = true;
    491                 break;
    492             case '?':
    493             default:
    494                 return usage();
    495         }
    496     }
    497 
    498     for (i = optind; i < argc; i++) {
    499         char* arg = argv[i];
    500         if (!source_path) {
    501             source_path = arg;
    502         } else if (!label) {
    503             label = arg;
    504         } else {
    505             LOG(ERROR) << "too many arguments";
    506             return usage();
    507         }
    508     }
    509 
    510     if (!source_path) {
    511         LOG(ERROR) << "no source path specified";
    512         return usage();
    513     }
    514     if (!label) {
    515         LOG(ERROR) << "no label specified";
    516         return usage();
    517     }
    518     if (!uid || !gid) {
    519         LOG(ERROR) << "uid and gid must be nonzero";
    520         return usage();
    521     }
    522 
    523     rlim.rlim_cur = 8192;
    524     rlim.rlim_max = 8192;
    525     if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
    526         PLOG(ERROR) << "setting RLIMIT_NOFILE failed";
    527     }
    528 
    529     while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
    530         LOG(ERROR) << "installd fs upgrade not yet complete; waiting...";
    531         sleep(1);
    532     }
    533 
    534     if (should_use_sdcardfs()) {
    535         run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write, derive_gid);
    536     } else {
    537         run(source_path, label, uid, gid, userid, multi_user, full_write);
    538     }
    539     return 1;
    540 }
    541