summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2015-06-24 15:24:48 -0700
committerJeff Sharkey <jsharkey@android.com>2015-06-25 22:25:48 -0700
commit9527b223a9d4a4d149bb005afc77148dbeeff785 (patch)
tree5e3839f65f6dad7f402c280ef5de091238648159 /core/jni
parent9206d6a0e69ef0f60e20464796d4a2da6f7c42f4 (diff)
downloadframeworks_base-9527b223a9d4a4d149bb005afc77148dbeeff785.zip
frameworks_base-9527b223a9d4a4d149bb005afc77148dbeeff785.tar.gz
frameworks_base-9527b223a9d4a4d149bb005afc77148dbeeff785.tar.bz2
Let's reinvent storage, yet again!
Now that we're treating storage as a runtime permission, we need to grant read/write access without killing the app. This is really tricky, since we had been using GIDs for access control, and they're set in stone once Zygote drops privileges. The only thing left that can change dynamically is the filesystem itself, so let's do that. This means changing the FUSE daemon to present itself as three different views: /mnt/runtime_default/foo - view for apps with no access /mnt/runtime_read/foo - view for apps with read access /mnt/runtime_write/foo - view for apps with write access There is still a single location for all the backing files, and filesystem permissions are derived the same way for each view, but the file modes are masked off differently for each mountpoint. During Zygote fork, it wires up the appropriate storage access into an isolated mount namespace based on the current app permissions. When the app is granted permissions dynamically at runtime, the system asks vold to jump into the existing mount namespace and bind mount the newly granted access model into place. Bug: 21858077 Change-Id: I62fb25d126dd815aea699b33d580e3afb90f8fd2
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp71
1 files changed, 42 insertions, 29 deletions
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 76db5d3..f7cfe0e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -66,6 +66,8 @@ static jmethodID gCallPostForkChildHooks;
enum MountExternalKind {
MOUNT_EXTERNAL_NONE = 0,
MOUNT_EXTERNAL_DEFAULT = 1,
+ MOUNT_EXTERNAL_READ = 2,
+ MOUNT_EXTERNAL_WRITE = 3,
};
static void RuntimeAbort(JNIEnv* env) {
@@ -249,38 +251,49 @@ static void SetSchedulerPolicy(JNIEnv* env) {
// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
-static bool MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace) {
- if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
- return true;
- }
-
- // Create a second private mount namespace for our process
- if (unshare(CLONE_NEWNS) == -1) {
- ALOGW("Failed to unshare(): %s", strerror(errno));
- return false;
- }
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
+ bool force_mount_namespace) {
+ // See storage config details at http://source.android.com/tech/storage/
- if (mount_mode == MOUNT_EXTERNAL_NONE) {
- return true;
- }
-
- // See storage config details at http://source.android.com/tech/storage/
- userid_t user_id = multiuser_get_user_id(uid);
-
- // Bind mount user-specific storage into place
- const String8 source(String8::format("/mnt/user/%d", user_id));
- const String8 target(String8::format("/storage/self"));
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ ALOGW("Failed to unshare(): %s", strerror(errno));
+ return false;
+ }
- if (fs_prepare_dir(source.string(), 0755, 0, 0) == -1) {
- return false;
- }
+ // Unmount storage provided by root namespace and mount requested view
+ umount2("/storage", MNT_FORCE);
+
+ String8 storageSource;
+ if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
+ storageSource = "/mnt/runtime_default";
+ } else if (mount_mode == MOUNT_EXTERNAL_READ) {
+ storageSource = "/mnt/runtime_read";
+ } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
+ storageSource = "/mnt/runtime_write";
+ } else {
+ // Sane default of no storage visible
+ return true;
+ }
+ if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
+ NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+ ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
+ return false;
+ }
- if (TEMP_FAILURE_RETRY(mount(source.string(), target.string(), NULL, MS_BIND, NULL)) == -1) {
- ALOGW("Failed to mount %s to %s: %s", source.string(), target.string(), strerror(errno));
- return false;
- }
+ // Mount user-specific symlink helpers into place
+ userid_t user_id = multiuser_get_user_id(uid);
+ const String8 userSource(String8::format("/mnt/user/%d", user_id));
+ if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+ return false;
+ }
+ if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
+ NULL, MS_BIND, NULL)) == -1) {
+ ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
+ return false;
+ }
- return true;
+ return true;
}
static bool NeedsNoRandomizeWorkaround() {
@@ -543,7 +556,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
debug_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
- MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
+ MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
NULL, NULL);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.