Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 496ac000 authored by Martijn Coenen's avatar Martijn Coenen
Browse files

Only allow Download authority/MTP/installers to write in Android/.

Previously when FUSE was enabled, we gave all apps requesting
WRITE_MEDIA_STORAGE or install permissions a direct view
to the lower filesystem. This was way too broad for a few reasons:
1) WRITE_MEDIA_STORAGE will be deprecated; holding that permission by
itself shouldn't grant you any special privileges.
2) Installers should only be able to write OBBs

The only other exceptions that are allowed to bypass scoped storage are
the process hosting the DownloadProvider and the process implementing
the MTP server; both of these have legit reasons for writing in
Android/. The way this is currently implemented is by giving these apps
the SDCARD_RW gid, which has write access in the default Android/
sdcardfs view.

Installers will be further scoped down to be only able to access OBB
in a follow-up CL.

Bug: 134706060
Bug: 146490513
Test: DownloadProvider can download
      Play + OBBs work
      Writing in Android/ through MTP works

Change-Id: Iff8681732d0c1124e24e5347f7dcb64b781c1e8c
parent 7c1df2d1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -88,6 +88,12 @@ public class Process {
    @UnsupportedAppUsage
    public static final int DRM_UID = 1019;

    /**
     * Defines the GID for the group that allows write access to the internal media storage.
     * @hide
     */
    public static final int SDCARD_RW_GID = 1015;

    /**
     * Defines the UID/GID for the group that controls VPN services.
     * @hide
+2 −0
Original line number Diff line number Diff line
@@ -594,6 +594,8 @@ public class ZygoteProcess {
            argsForZygote.add("--mount-external-legacy");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
            argsForZygote.add("--mount-external-pass-through");
        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
            argsForZygote.add("--mount-external-android-writable");
        }

        argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
+5 −0
Original line number Diff line number Diff line
@@ -145,6 +145,11 @@ public final class Zygote {
    /** The lower file system should be bind mounted directly on external storage */
    public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;

    /** Use the regular scoped storage filesystem, but Android/ should be writable.
     * Used to support the applications hosting DownloadManager and the MTP server.
     */
    public static final int MOUNT_EXTERNAL_ANDROID_WRITABLE = IVold.REMOUNT_MODE_ANDROID_WRITABLE;

    /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
    static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8;

+2 −0
Original line number Diff line number Diff line
@@ -376,6 +376,8 @@ class ZygoteArguments {
                mMountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
            } else if (arg.equals("--mount-external-pass-through")) {
                mMountExternal = Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
            } else if (arg.equals("--mount-external-android-writable")) {
                mMountExternal = Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
            } else if (arg.equals("--query-abi-list")) {
                mAbiListQuery = true;
            } else if (arg.equals("--get-pid")) {
+5 −7
Original line number Diff line number Diff line
@@ -319,7 +319,8 @@ enum MountExternalKind {
  MOUNT_EXTERNAL_INSTALLER = 5,
  MOUNT_EXTERNAL_FULL = 6,
  MOUNT_EXTERNAL_PASS_THROUGH = 7,
  MOUNT_EXTERNAL_COUNT = 8
  MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
  MOUNT_EXTERNAL_COUNT = 9
};

// The order of entries here must be kept in sync with MountExternalKind enum values.
@@ -331,6 +332,8 @@ static const std::array<const std::string, MOUNT_EXTERNAL_COUNT> ExternalStorage
  "/mnt/runtime/write",   // MOUNT_EXTERNAL_LEGACY
  "/mnt/runtime/write",   // MOUNT_EXTERNAL_INSTALLER
  "/mnt/runtime/full",    // MOUNT_EXTERNAL_FULL
  "/mnt/runtime/full",    // MOUNT_EXTERNAL_PASS_THROUGH (only used w/ FUSE)
  "/mnt/runtime/full",    // MOUNT_EXTERNAL_ANDROID_WRITABLE (only used w/ FUSE)
};

// Must match values in com.android.internal.os.Zygote.
@@ -749,12 +752,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
  PrepareDir(user_source, DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT, fail_fn);

  if (isFuse) {
    if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH || mount_mode ==
        MOUNT_EXTERNAL_INSTALLER || mount_mode == MOUNT_EXTERNAL_FULL) {
      // For now, MediaProvider, installers and "full" get the pass_through mount
      // view, which is currently identical to the sdcardfs write view.
      //
      // TODO(b/146189163): scope down MOUNT_EXTERNAL_INSTALLER
    if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
      BindMount(pass_through_source, "/storage", fail_fn);
    } else {
      BindMount(user_source, "/storage", fail_fn);
Loading