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

Commit e5088d92 authored by Ricky Wai's avatar Ricky Wai
Browse files

Bind mount obb directory in emulated storage.

- Create obb directories for packages when zygote starts.

- During zygote fork, bind all visible obb package directories
for an app.

- If app data isolation is not enabled for that process, bind
mount the whole obb directory instead.

Bug: 148049767
Bug: 137890172
Test: atest android.appsecurity.cts.AdoptableHostTest
Change-Id: I841e98c120d447b148c22cfd809d738427b04f2e
parent cd1ca07b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package android.os.storage;
import android.annotation.Nullable;
import android.os.IVold;

import java.util.Set;

/**
 * Mount service local interface.
 *
@@ -96,6 +98,12 @@ public abstract class StorageManagerInternal {
        void onReset(IVold vold);
    }

    /**
     * Check if fuse is running in target user, if it's running then setup its obb directories.
     * TODO: System server should store a list of active pids that obb is not mounted and use it.
     */
    public abstract void prepareObbDirs(int userId, Set<String> packageList, String processName);

    /**
     * Add a listener to listen to reset event in StorageManagerService.
     *
+102 −0
Original line number Diff line number Diff line
@@ -105,10 +105,12 @@ namespace {
using namespace std::placeholders;

using android::String8;
using android::base::ReadFileToString;
using android::base::StringAppendF;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
using android::base::GetBoolProperty;
using android::base::GetProperty;

#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
                              append(StringPrintf(__VA_ARGS__))
@@ -174,6 +176,12 @@ static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751;
static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
    "persist.zygote.app_data_isolation";

/**
 * Property to enable app data isolation for sdcard obb or data in vold.
 */
static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
    "persist.sys.vold_app_data_isolation_enabled";

static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;

@@ -603,6 +611,15 @@ static void EnableDebugger() {
  }
}

static bool IsFilesystemSupported(const std::string& fsType) {
    std::string supported;
    if (!ReadFileToString("/proc/filesystems", &supported)) {
        ALOGE("Failed to read supported filesystems");
        return false;
    }
    return supported.find(fsType + "\n") != std::string::npos;
}

static void PreApplicationInit() {
  // The child process sets this to indicate it's not the zygote.
  android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0);
@@ -782,6 +799,31 @@ static void MountAppDataTmpFs(const std::string& target_dir,
  }
}

static void BindMountObbPackage(std::string_view package_name, int userId, fail_fn_t fail_fn) {

  // TODO(148772775): Pass primary volume name from zygote argument to here
  std::string source;
  if (IsFilesystemSupported("sdcardfs")) {
    source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s",
        userId, package_name.data());
  } else {
    source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s",
        userId, userId, package_name.data());
  }
  std::string target(
      StringPrintf("/storage/emulated/%d/Android/obb/%s", userId, package_name.data()));

  if (access(source.c_str(), F_OK) != 0) {
    fail_fn(CREATE_ERROR("Cannot access source %s: %s", source.c_str(), strerror(errno)));
  }

  if (access(target.c_str(), F_OK) != 0) {
    fail_fn(CREATE_ERROR("Cannot access target %s: %s", target.c_str(), strerror(errno)));
  }

  BindMount(source, target, fail_fn);
}

// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static void MountEmulatedStorage(uid_t uid, jint mount_mode,
@@ -1504,6 +1546,60 @@ static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list,
  }
}

// Bind mount all obb directories that are visible to this app.
// If app data isolation is not enabled for this process, bind mount the whole obb
// directory instead.
static void BindMountAppObbDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
    uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) {

  auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
  const userid_t user_id = multiuser_get_user_id(uid);

  // If FUSE is not ready for this user, skip it
  // TODO(148772775): Pass primary volume name from zygote argument to here
  std::string tmp = GetProperty("vold.fuse_running_users", "");
  std::istringstream fuse_running_users(tmp);
  bool user_found = false;
  std::string s;
  std::string user_id_str = std::to_string(user_id);
  while (!user_found && std::getline(fuse_running_users, s, ',')) {
    if (user_id_str == s) {
      user_found = true;
    }
  }
  if (!user_found) {
    ALOGI("User %d is not running fuse yet, fuse_running_users=%s", user_id, tmp.c_str());
    return;
  }

  // Fuse is ready, so we can start using fuse path.
  int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;

  if (size == 0) {
    // App data isolation is not enabled for this process, so we bind mount to whole obb/ dir.
    std::string source;
    if (IsFilesystemSupported("sdcardfs")) {
      source = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", user_id);
    } else {
      source = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", user_id, user_id);
    }
    std::string target(StringPrintf("/storage/emulated/%d/Android/obb", user_id));

    if (access(source.c_str(), F_OK) != 0) {
      fail_fn(CREATE_ERROR("Error accessing %s: %s", source.c_str(), strerror(errno)));
    }
    BindMount(source, target, fail_fn);
    return;
  }

  // Bind mount each package obb directory
  for (int i = 0; i < size; i += 3) {
    jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
    std::string packageName = extract_fn(package_str).value();
    BindMountObbPackage(packageName, user_id, fail_fn);
  }
}

// Utility routine to specialize a zygote child process.
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
                             jint runtime_flags, jobjectArray rlimits,
@@ -1552,6 +1648,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
    isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
  }

  if ((mount_external != MOUNT_EXTERNAL_INSTALLER) &&
        GetBoolProperty(kPropFuse, false) &&
        GetBoolProperty(ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
    BindMountAppObbDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
  }

  // If this zygote isn't root, it won't be able to create a process group,
  // since the directory is owned by root.
  if (!is_system_server && getuid() == 0) {
+38 −2
Original line number Diff line number Diff line
@@ -2120,8 +2120,6 @@ class StorageManagerService extends IStorageManager.Stub

    private void unmount(VolumeInfo vol) {
        try {
            mVold.unmount(vol.id);
            mStorageSessionController.onVolumeUnmount(vol);
            try {
                if (vol.type == VolumeInfo.TYPE_PRIVATE) {
                    mInstaller.onPrivateVolumeRemoved(vol.getFsUuid());
@@ -2129,6 +2127,8 @@ class StorageManagerService extends IStorageManager.Stub
            } catch (Installer.InstallerException e) {
                Slog.e(TAG, "Failed unmount mirror data", e);
            }
            mVold.unmount(vol.id);
            mStorageSessionController.onVolumeUnmount(vol);
        } catch (Exception e) {
            Slog.wtf(TAG, e);
        }
@@ -4346,6 +4346,42 @@ class StorageManagerService extends IStorageManager.Stub
            mPolicies.add(policy);
        }

        /**
         * Check if fuse is running in target user, if it's running then setup its obb directories.
         * TODO: System server should store a list of active pids that obb is not mounted and use it.
         */
        @Override
        public void prepareObbDirs(int userId, Set<String> packageList, String processName) {
            String fuseRunningUsersList = SystemProperties.get("vold.fuse_running_users", "");
            String[] fuseRunningUsers = fuseRunningUsersList.split(",");
            boolean fuseReady = false;
            String targetUserId = String.valueOf(userId);
            for (String user : fuseRunningUsers) {
                if (targetUserId.equals(user)) {
                    fuseReady = true;
                }
            }
            if (fuseReady) {
                try {
                    final IVold vold = IVold.Stub.asInterface(
                            ServiceManager.getServiceOrThrow("vold"));
                    for (String pkg : packageList) {
                        final String obbDir =
                                String.format("/storage/emulated/%d/Android/obb", userId);
                        final String packageObbDir = String.format("%s/%s/", obbDir, pkg);

                        // Create package obb dir if it doesn't exist.
                        File file = new File(packageObbDir);
                        if (!file.exists()) {
                            vold.setupAppDir(packageObbDir, mPmInternal.getPackage(pkg).getUid());
                        }
                    }
                } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
                    Slog.e(TAG, "Unable to create obb directories for " + processName, e);
                }
            }
        }

        @Override
        public void onExternalStoragePolicyChanged(int uid, String packageName) {
            final int mountMode = getExternalStorageMountMode(uid, packageName);
+18 −1
Original line number Diff line number Diff line
@@ -80,11 +80,13 @@ import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.IVold;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -142,10 +144,14 @@ import java.util.Map;
public final class ProcessList {
    static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessList" : TAG_AM;

    // A device config to control the minimum target SDK to enable app data isolation
    // A system property to control if app data isolation is enabled.
    static final String ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
            "persist.zygote.app_data_isolation";

    // A system property to control if obb app data isolation is enabled in vold.
    static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
            "persist.sys.vold_app_data_isolation_enabled";

    // A device config to control the minimum target SDK to enable app data isolation
    static final String ANDROID_APP_DATA_ISOLATION_MIN_SDK = "android_app_data_isolation_min_sdk";

@@ -379,6 +385,8 @@ public final class ProcessList {

    private boolean mAppDataIsolationEnabled = false;

    private boolean mVoldAppDataIsolationEnabled = false;

    private ArrayList<String> mAppDataIsolationWhitelistedApps;

    /**
@@ -691,6 +699,8 @@ public final class ProcessList {
        // want some apps enabled while some apps disabled
        mAppDataIsolationEnabled =
                SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
        mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
                ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
        mAppDataIsolationWhitelistedApps = new ArrayList<>(
                SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());

@@ -2113,6 +2123,13 @@ public final class ProcessList {
                        app.info.packageName, app.userId);
                pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
                        ? new String[]{app.info.packageName} : sharedPackages, uid);

                if (mVoldAppDataIsolationEnabled) {
                    StorageManagerInternal storageManagerInternal = LocalServices.getService(
                                StorageManagerInternal.class);
                    storageManagerInternal.prepareObbDirs(UserHandle.getUserId(uid),
                            pkgDataInfoMap.keySet(), app.processName);
                }
            } else {
                pkgDataInfoMap = null;
            }