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
This commit is contained in:
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user