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
423cd591813871902e27677d755160123b2a2454807Daniel Rosenberg    if (property_get_bool(PROP_SDCARDFS_DEVICE, true)) {
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