summaryrefslogtreecommitdiff
path: root/services/java/com/android/server/MountService.java
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-09-17 17:30:33 -0700
committerJeff Sharkey <jsharkey@android.com>2013-09-20 14:34:02 -0700
commit2d8b4e801332e02d6aad615b85cc9dd056ef805c (patch)
tree8100d77b8cef8d1b11ed366006b1035706640400 /services/java/com/android/server/MountService.java
parent6df7d4a574ffd85c82cad402552e3854df3a3f85 (diff)
Delegate mkdirs() to vold when lacking perms.
Apps without sdcard_r or sdcard_rw are still able to write to their package-specific directory, but someone needs to first make that directory on their behalf. This change will delegate the mkdirs() call through to vold when an app fails to create directly. MountService validates that the path belongs to the calling user, and that it's actually on external storage, before passing to vold. Update Environment to make app-vs-vold paths clearer. Bug: 10577808 Change-Id: I43b4a77fd6d2b9af2a0d899790da8d9d89386776
Diffstat (limited to 'services/java/com/android/server/MountService.java')
-rw-r--r--services/java/com/android/server/MountService.java82
1 files changed, 81 insertions, 1 deletions
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 1facb8093625..6ab86f5a3c4e 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -19,6 +19,7 @@ package com.android.server;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
+import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -2128,6 +2129,85 @@ class MountService extends IMountService.Stub
}
@Override
+ public int mkdirs(String callingPkg, String appPath) {
+ final int userId = UserHandle.getUserId(Binder.getCallingUid());
+ final UserEnvironment userEnv = new UserEnvironment(userId);
+
+ // Validate that reported package name belongs to caller
+ final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
+ Context.APP_OPS_SERVICE);
+ appOps.checkPackage(Binder.getCallingUid(), callingPkg);
+
+ try {
+ appPath = new File(appPath).getCanonicalPath();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
+ return -1;
+ }
+
+ // Try translating the app path into a vold path, but require that it
+ // belong to the calling package.
+ String voldPath = maybeTranslatePathForVold(appPath,
+ userEnv.buildExternalStorageAppDataDirs(callingPkg),
+ userEnv.buildExternalStorageAppDataDirsForVold(callingPkg));
+ if (voldPath != null) {
+ try {
+ mConnector.execute("volume", "mkdirs", voldPath);
+ return 0;
+ } catch (NativeDaemonConnectorException e) {
+ return e.getCode();
+ }
+ }
+
+ voldPath = maybeTranslatePathForVold(appPath,
+ userEnv.buildExternalStorageAppObbDirs(callingPkg),
+ userEnv.buildExternalStorageAppObbDirsForVold(callingPkg));
+ if (voldPath != null) {
+ try {
+ mConnector.execute("volume", "mkdirs", voldPath);
+ return 0;
+ } catch (NativeDaemonConnectorException e) {
+ return e.getCode();
+ }
+ }
+
+ throw new SecurityException("Invalid mkdirs path: " + appPath);
+ }
+
+ /**
+ * Translate the given path from an app-visible path to a vold-visible path,
+ * but only if it's under the given whitelisted paths.
+ *
+ * @param path a canonicalized app-visible path.
+ * @param appPaths list of app-visible paths that are allowed.
+ * @param voldPaths list of vold-visible paths directly corresponding to the
+ * allowed app-visible paths argument.
+ * @return a vold-visible path representing the original path, or
+ * {@code null} if the given path didn't have an app-to-vold
+ * mapping.
+ */
+ @VisibleForTesting
+ public static String maybeTranslatePathForVold(
+ String path, File[] appPaths, File[] voldPaths) {
+ if (appPaths.length != voldPaths.length) {
+ throw new IllegalStateException("Paths must be 1:1 mapping");
+ }
+
+ for (int i = 0; i < appPaths.length; i++) {
+ final String appPath = appPaths[i].getAbsolutePath();
+ if (path.startsWith(appPath)) {
+ path = new File(voldPaths[i], path.substring(appPath.length() + 1))
+ .getAbsolutePath();
+ if (!path.endsWith("/")) {
+ path = path + "/";
+ }
+ return path;
+ }
+ }
+ return null;
+ }
+
+ @Override
public StorageVolume[] getVolumeList() {
final int callingUserId = UserHandle.getCallingUserId();
final boolean accessAll = (mContext.checkPermission(
@@ -2651,7 +2731,7 @@ class MountService extends IMountService.Stub
if (forVold) {
return new File(Environment.getEmulatedStorageSource(userId), path).getAbsolutePath();
} else {
- return new File(userEnv.getExternalDirs()[0], path).getAbsolutePath();
+ return new File(userEnv.getExternalDirsForApp()[0], path).getAbsolutePath();
}
}