Merge changes I04ac8fba,Ia0a8548f am: db6628bb7d am: a534c95087
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1615382 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I06eb075d11b110ccbbd8dcaecb948e502d69f6bb
This commit is contained in:
@@ -333,7 +333,7 @@ public class ZygoteProcess {
|
|||||||
* started.
|
* started.
|
||||||
* @param pkgDataInfoMap Map from related package names to private data directory
|
* @param pkgDataInfoMap Map from related package names to private data directory
|
||||||
* volume UUID and inode number.
|
* volume UUID and inode number.
|
||||||
* @param whitelistedDataInfoMap Map from allowlisted package names to private data directory
|
* @param allowlistedDataInfoList Map from allowlisted package names to private data directory
|
||||||
* volume UUID and inode number.
|
* volume UUID and inode number.
|
||||||
* @param bindMountAppsData whether zygote needs to mount CE and DE data.
|
* @param bindMountAppsData whether zygote needs to mount CE and DE data.
|
||||||
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
|
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
|
||||||
@@ -359,7 +359,7 @@ public class ZygoteProcess {
|
|||||||
@Nullable Map<String, Pair<String, Long>>
|
@Nullable Map<String, Pair<String, Long>>
|
||||||
pkgDataInfoMap,
|
pkgDataInfoMap,
|
||||||
@Nullable Map<String, Pair<String, Long>>
|
@Nullable Map<String, Pair<String, Long>>
|
||||||
whitelistedDataInfoMap,
|
allowlistedDataInfoList,
|
||||||
boolean bindMountAppsData,
|
boolean bindMountAppsData,
|
||||||
boolean bindMountAppStorageDirs,
|
boolean bindMountAppStorageDirs,
|
||||||
@Nullable String[] zygoteArgs) {
|
@Nullable String[] zygoteArgs) {
|
||||||
@@ -373,7 +373,7 @@ public class ZygoteProcess {
|
|||||||
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
|
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
|
||||||
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
|
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
|
||||||
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
|
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
|
||||||
pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
|
pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
|
||||||
bindMountAppStorageDirs, zygoteArgs);
|
bindMountAppStorageDirs, zygoteArgs);
|
||||||
} catch (ZygoteStartFailedEx ex) {
|
} catch (ZygoteStartFailedEx ex) {
|
||||||
Log.e(LOG_TAG,
|
Log.e(LOG_TAG,
|
||||||
@@ -615,7 +615,7 @@ public class ZygoteProcess {
|
|||||||
* @param disabledCompatChanges a list of disabled compat changes for the process being started.
|
* @param disabledCompatChanges a list of disabled compat changes for the process being started.
|
||||||
* @param pkgDataInfoMap Map from related package names to private data directory volume UUID
|
* @param pkgDataInfoMap Map from related package names to private data directory volume UUID
|
||||||
* and inode number.
|
* and inode number.
|
||||||
* @param whitelistedDataInfoMap Map from allowlisted package names to private data directory
|
* @param allowlistedDataInfoList Map from allowlisted package names to private data directory
|
||||||
* volume UUID and inode number.
|
* volume UUID and inode number.
|
||||||
* @param bindMountAppsData whether zygote needs to mount CE and DE data.
|
* @param bindMountAppsData whether zygote needs to mount CE and DE data.
|
||||||
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
|
* @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
|
||||||
@@ -642,7 +642,7 @@ public class ZygoteProcess {
|
|||||||
@Nullable Map<String, Pair<String, Long>>
|
@Nullable Map<String, Pair<String, Long>>
|
||||||
pkgDataInfoMap,
|
pkgDataInfoMap,
|
||||||
@Nullable Map<String, Pair<String, Long>>
|
@Nullable Map<String, Pair<String, Long>>
|
||||||
whitelistedDataInfoMap,
|
allowlistedDataInfoList,
|
||||||
boolean bindMountAppsData,
|
boolean bindMountAppsData,
|
||||||
boolean bindMountAppStorageDirs,
|
boolean bindMountAppStorageDirs,
|
||||||
@Nullable String[] extraArgs)
|
@Nullable String[] extraArgs)
|
||||||
@@ -733,12 +733,12 @@ public class ZygoteProcess {
|
|||||||
}
|
}
|
||||||
argsForZygote.add(sb.toString());
|
argsForZygote.add(sb.toString());
|
||||||
}
|
}
|
||||||
if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) {
|
if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(Zygote.WHITELISTED_DATA_INFO_MAP);
|
sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP);
|
||||||
sb.append("=");
|
sb.append("=");
|
||||||
boolean started = false;
|
boolean started = false;
|
||||||
for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) {
|
for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) {
|
||||||
if (started) {
|
if (started) {
|
||||||
sb.append(',');
|
sb.append(',');
|
||||||
}
|
}
|
||||||
@@ -1318,7 +1318,7 @@ public class ZygoteProcess {
|
|||||||
true /* startChildZygote */, null /* packageName */,
|
true /* startChildZygote */, null /* packageName */,
|
||||||
ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
|
ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
|
||||||
null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
|
null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
|
||||||
null /* whitelistedDataInfoMap */, true /* bindMountAppsData*/,
|
null /* allowlistedDataInfoList */, true /* bindMountAppsData*/,
|
||||||
/* bindMountAppStorageDirs */ false, extraArgs);
|
/* bindMountAppStorageDirs */ false, extraArgs);
|
||||||
|
|
||||||
} catch (ZygoteStartFailedEx ex) {
|
} catch (ZygoteStartFailedEx ex) {
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public final class Zygote {
|
|||||||
public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
|
public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
|
||||||
|
|
||||||
/** List of allowlisted packages and its app data info: volume uuid and inode. */
|
/** List of allowlisted packages and its app data info: volume uuid and inode. */
|
||||||
public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map";
|
public static final String ALLOWLISTED_DATA_INFO_MAP = "--allowlisted-data-info-map";
|
||||||
|
|
||||||
/** Bind mount app storage dirs to lower fs not via fuse */
|
/** Bind mount app storage dirs to lower fs not via fuse */
|
||||||
public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
|
public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
|
||||||
@@ -324,7 +324,7 @@ public final class Zygote {
|
|||||||
* @param isTopApp true if the process is for top (high priority) application.
|
* @param isTopApp true if the process is for top (high priority) application.
|
||||||
* @param pkgDataInfoList A list that stores related packages and its app data
|
* @param pkgDataInfoList A list that stores related packages and its app data
|
||||||
* info: volume uuid and inode.
|
* info: volume uuid and inode.
|
||||||
* @param whitelistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
|
* @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
|
||||||
* @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
|
* @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
|
||||||
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
|
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
|
||||||
*
|
*
|
||||||
@@ -334,14 +334,14 @@ public final class Zygote {
|
|||||||
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
|
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
|
||||||
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
|
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
|
||||||
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
|
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
|
||||||
boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList,
|
boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList,
|
||||||
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
|
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
|
||||||
ZygoteHooks.preFork();
|
ZygoteHooks.preFork();
|
||||||
|
|
||||||
int pid = nativeForkAndSpecialize(
|
int pid = nativeForkAndSpecialize(
|
||||||
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
|
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
|
||||||
fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
|
fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
|
||||||
pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs,
|
pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs,
|
||||||
bindMountAppStorageDirs);
|
bindMountAppStorageDirs);
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// Note that this event ends at the end of handleChildProc,
|
// Note that this event ends at the end of handleChildProc,
|
||||||
@@ -364,7 +364,7 @@ public final class Zygote {
|
|||||||
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
|
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
|
||||||
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
|
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
|
||||||
String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
|
String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
|
||||||
String[] whitelistedDataInfoList, boolean bindMountAppDataDirs,
|
String[] allowlistedDataInfoList, boolean bindMountAppDataDirs,
|
||||||
boolean bindMountAppStorageDirs);
|
boolean bindMountAppStorageDirs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -392,18 +392,18 @@ public final class Zygote {
|
|||||||
* volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
|
* volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
|
||||||
* app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
|
* app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
|
||||||
* app_b_ce_inode, ...];
|
* app_b_ce_inode, ...];
|
||||||
* @param whitelistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
|
* @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
|
||||||
* @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
|
* @param bindMountAppDataDirs True if the zygote needs to mount data dirs.
|
||||||
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
|
* @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs.
|
||||||
*/
|
*/
|
||||||
private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
|
private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
|
||||||
int[][] rlimits, int mountExternal, String seInfo, String niceName,
|
int[][] rlimits, int mountExternal, String seInfo, String niceName,
|
||||||
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
|
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
|
||||||
String[] pkgDataInfoList, String[] whitelistedDataInfoList,
|
String[] pkgDataInfoList, String[] allowlistedDataInfoList,
|
||||||
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
|
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
|
||||||
nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
|
nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
|
||||||
niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
|
niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
|
||||||
pkgDataInfoList, whitelistedDataInfoList,
|
pkgDataInfoList, allowlistedDataInfoList,
|
||||||
bindMountAppDataDirs, bindMountAppStorageDirs);
|
bindMountAppDataDirs, bindMountAppStorageDirs);
|
||||||
|
|
||||||
// Note that this event ends at the end of handleChildProc.
|
// Note that this event ends at the end of handleChildProc.
|
||||||
@@ -428,7 +428,7 @@ public final class Zygote {
|
|||||||
private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
|
private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
|
||||||
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
|
int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
|
||||||
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
|
boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
|
||||||
String[] pkgDataInfoList, String[] whitelistedDataInfoList,
|
String[] pkgDataInfoList, String[] allowlistedDataInfoList,
|
||||||
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
|
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -807,7 +807,7 @@ public final class Zygote {
|
|||||||
args.mRuntimeFlags, rlimits, args.mMountExternal,
|
args.mRuntimeFlags, rlimits, args.mMountExternal,
|
||||||
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
|
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
|
||||||
args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
|
args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
|
||||||
args.mPkgDataInfoList, args.mWhitelistedDataInfoList,
|
args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
|
||||||
args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
|
args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ class ZygoteArguments {
|
|||||||
* A list that stores all allowlisted app data info: volume uuid and inode.
|
* A list that stores all allowlisted app data info: volume uuid and inode.
|
||||||
* Null if it does need to do app data isolation.
|
* Null if it does need to do app data isolation.
|
||||||
*/
|
*/
|
||||||
String[] mWhitelistedDataInfoList;
|
String[] mAllowlistedDataInfoList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
|
* @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
|
||||||
@@ -475,8 +475,8 @@ class ZygoteArguments {
|
|||||||
}
|
}
|
||||||
} else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
|
} else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
|
||||||
mPkgDataInfoList = getAssignmentList(arg);
|
mPkgDataInfoList = getAssignmentList(arg);
|
||||||
} else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) {
|
} else if (arg.startsWith(Zygote.ALLOWLISTED_DATA_INFO_MAP)) {
|
||||||
mWhitelistedDataInfoList = getAssignmentList(arg);
|
mAllowlistedDataInfoList = getAssignmentList(arg);
|
||||||
} else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
|
} else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
|
||||||
mBindMountAppStorageDirs = true;
|
mBindMountAppStorageDirs = true;
|
||||||
} else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
|
} else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ class ZygoteConnection {
|
|||||||
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
|
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
|
||||||
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
|
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
|
||||||
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
|
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
|
||||||
parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
|
parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
|
||||||
parsedArgs.mBindMountAppStorageDirs);
|
parsedArgs.mBindMountAppStorageDirs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1400,16 +1400,15 @@ static void insertPackagesToMergedList(JNIEnv* env,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
|
static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
|
||||||
jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
|
jobjectArray allowlisted_data_info_list, uid_t uid,
|
||||||
jstring managed_nice_name, fail_fn_t fail_fn) {
|
const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) {
|
||||||
|
std::vector<std::string> merged_data_info_list;
|
||||||
|
insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list, process_name,
|
||||||
|
managed_nice_name, fail_fn);
|
||||||
|
insertPackagesToMergedList(env, merged_data_info_list, allowlisted_data_info_list, process_name,
|
||||||
|
managed_nice_name, fail_fn);
|
||||||
|
|
||||||
std::vector<std::string> merged_data_info_list;
|
isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
|
||||||
insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
|
|
||||||
process_name, managed_nice_name, fail_fn);
|
|
||||||
insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list,
|
|
||||||
process_name, managed_nice_name, fail_fn);
|
|
||||||
|
|
||||||
isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1510,240 +1509,242 @@ static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Utility routine to specialize a zygote child process.
|
// Utility routine to specialize a zygote child process.
|
||||||
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
|
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
|
||||||
jint runtime_flags, jobjectArray rlimits,
|
jobjectArray rlimits, jlong permitted_capabilities,
|
||||||
jlong permitted_capabilities, jlong effective_capabilities,
|
jlong effective_capabilities, jint mount_external,
|
||||||
jint mount_external, jstring managed_se_info,
|
jstring managed_se_info, jstring managed_nice_name,
|
||||||
jstring managed_nice_name, bool is_system_server,
|
bool is_system_server, bool is_child_zygote,
|
||||||
bool is_child_zygote, jstring managed_instruction_set,
|
jstring managed_instruction_set, jstring managed_app_data_dir,
|
||||||
jstring managed_app_data_dir, bool is_top_app,
|
bool is_top_app, jobjectArray pkg_data_info_list,
|
||||||
jobjectArray pkg_data_info_list,
|
jobjectArray allowlisted_data_info_list, bool mount_data_dirs,
|
||||||
jobjectArray whitelisted_data_info_list,
|
bool mount_storage_dirs) {
|
||||||
bool mount_data_dirs, bool mount_storage_dirs) {
|
const char* process_name = is_system_server ? "system_server" : "zygote";
|
||||||
const char* process_name = is_system_server ? "system_server" : "zygote";
|
auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
|
||||||
auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
|
auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
|
||||||
auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
|
|
||||||
|
|
||||||
auto se_info = extract_fn(managed_se_info);
|
auto se_info = extract_fn(managed_se_info);
|
||||||
auto nice_name = extract_fn(managed_nice_name);
|
auto nice_name = extract_fn(managed_nice_name);
|
||||||
auto instruction_set = extract_fn(managed_instruction_set);
|
auto instruction_set = extract_fn(managed_instruction_set);
|
||||||
auto app_data_dir = extract_fn(managed_app_data_dir);
|
auto app_data_dir = extract_fn(managed_app_data_dir);
|
||||||
|
|
||||||
// Keep capabilities across UID change, unless we're staying root.
|
// Keep capabilities across UID change, unless we're staying root.
|
||||||
if (uid != 0) {
|
if (uid != 0) {
|
||||||
EnableKeepCapabilities(fail_fn);
|
EnableKeepCapabilities(fail_fn);
|
||||||
}
|
|
||||||
|
|
||||||
SetInheritable(permitted_capabilities, fail_fn);
|
|
||||||
|
|
||||||
DropCapabilitiesBoundingSet(fail_fn);
|
|
||||||
|
|
||||||
bool need_pre_initialize_native_bridge =
|
|
||||||
!is_system_server &&
|
|
||||||
instruction_set.has_value() &&
|
|
||||||
android::NativeBridgeAvailable() &&
|
|
||||||
// Native bridge may be already initialized if this
|
|
||||||
// is an app forked from app-zygote.
|
|
||||||
!android::NativeBridgeInitialized() &&
|
|
||||||
android::NeedsNativeBridge(instruction_set.value().c_str());
|
|
||||||
|
|
||||||
MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
|
|
||||||
|
|
||||||
// Make sure app is running in its own mount namespace before isolating its data directories.
|
|
||||||
ensureInAppMountNamespace(fail_fn);
|
|
||||||
|
|
||||||
// Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
|
|
||||||
// mount all related packages separately.
|
|
||||||
if (mount_data_dirs) {
|
|
||||||
isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
|
|
||||||
uid, process_name, managed_nice_name, fail_fn);
|
|
||||||
isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
|
|
||||||
}
|
|
||||||
// MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps
|
|
||||||
// will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()),
|
|
||||||
// and hence they won't bind mount storage dirs.
|
|
||||||
if (mount_storage_dirs) {
|
|
||||||
BindMountStorageDirs(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) {
|
|
||||||
const int rc = createProcessGroup(uid, getpid());
|
|
||||||
if (rc == -EROFS) {
|
|
||||||
ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
|
|
||||||
} else if (rc != 0) {
|
|
||||||
ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SetGids(env, gids, is_child_zygote, fail_fn);
|
SetInheritable(permitted_capabilities, fail_fn);
|
||||||
SetRLimits(env, rlimits, fail_fn);
|
|
||||||
|
|
||||||
if (need_pre_initialize_native_bridge) {
|
DropCapabilitiesBoundingSet(fail_fn);
|
||||||
// Due to the logic behind need_pre_initialize_native_bridge we know that
|
|
||||||
// instruction_set contains a value.
|
|
||||||
android::PreInitializeNativeBridge(
|
|
||||||
app_data_dir.has_value() ? app_data_dir.value().c_str() : nullptr,
|
|
||||||
instruction_set.value().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setresgid(gid, gid, gid) == -1) {
|
bool need_pre_initialize_native_bridge = !is_system_server && instruction_set.has_value() &&
|
||||||
fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
|
android::NativeBridgeAvailable() &&
|
||||||
}
|
// Native bridge may be already initialized if this
|
||||||
|
// is an app forked from app-zygote.
|
||||||
|
!android::NativeBridgeInitialized() &&
|
||||||
|
android::NeedsNativeBridge(instruction_set.value().c_str());
|
||||||
|
|
||||||
// Must be called when the new process still has CAP_SYS_ADMIN, in this case,
|
MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
|
||||||
// before changing uid from 0, which clears capabilities. The other
|
|
||||||
// alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
|
|
||||||
// breaks SELinux domain transition (see b/71859146). As the result,
|
|
||||||
// privileged syscalls used below still need to be accessible in app process.
|
|
||||||
SetUpSeccompFilter(uid, is_child_zygote);
|
|
||||||
|
|
||||||
// Must be called before losing the permission to set scheduler policy.
|
// Make sure app is running in its own mount namespace before isolating its data directories.
|
||||||
SetSchedulerPolicy(fail_fn, is_top_app);
|
ensureInAppMountNamespace(fail_fn);
|
||||||
|
|
||||||
if (setresuid(uid, uid, uid) == -1) {
|
// Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind
|
||||||
fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
|
// mount all related packages separately.
|
||||||
}
|
if (mount_data_dirs) {
|
||||||
|
isolateAppData(env, pkg_data_info_list, allowlisted_data_info_list, uid, process_name,
|
||||||
// The "dumpable" flag of a process, which controls core dump generation, is
|
managed_nice_name, fail_fn);
|
||||||
// overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
|
isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
|
||||||
// user or group ID changes. See proc(5) for possible values. In most cases,
|
|
||||||
// the value is 0, so core dumps are disabled for zygote children. However,
|
|
||||||
// when running in a Chrome OS container, the value is already set to 2,
|
|
||||||
// which allows the external crash reporter to collect all core dumps. Since
|
|
||||||
// only system crashes are interested, core dump is disabled for app
|
|
||||||
// processes. This also ensures compliance with CTS.
|
|
||||||
int dumpable = prctl(PR_GET_DUMPABLE);
|
|
||||||
if (dumpable == -1) {
|
|
||||||
ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
|
|
||||||
RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dumpable == 2 && uid >= AID_APP) {
|
|
||||||
if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
|
|
||||||
ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
|
|
||||||
RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
|
|
||||||
}
|
}
|
||||||
}
|
// MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps
|
||||||
|
// will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()),
|
||||||
// Set process properties to enable debugging if required.
|
// and hence they won't bind mount storage dirs.
|
||||||
if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) {
|
if (mount_storage_dirs) {
|
||||||
EnableDebugger();
|
BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name,
|
||||||
}
|
fail_fn);
|
||||||
if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
|
|
||||||
// simpleperf needs the process to be dumpable to profile it.
|
|
||||||
if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
|
|
||||||
ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno));
|
|
||||||
RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
HeapTaggingLevel heap_tagging_level;
|
// If this zygote isn't root, it won't be able to create a process group,
|
||||||
switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
|
// since the directory is owned by root.
|
||||||
case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
|
if (!is_system_server && getuid() == 0) {
|
||||||
heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
|
const int rc = createProcessGroup(uid, getpid());
|
||||||
break;
|
if (rc == -EROFS) {
|
||||||
case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC:
|
ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
|
||||||
heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
|
} else if (rc != 0) {
|
||||||
break;
|
ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc));
|
||||||
case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC:
|
}
|
||||||
heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
|
|
||||||
|
|
||||||
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
|
|
||||||
runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
|
|
||||||
|
|
||||||
// Avoid heap zero initialization for applications without MTE. Zero init may
|
|
||||||
// cause app compat problems, use more memory, or reduce performance. While it
|
|
||||||
// would be nice to have them for apps, we will have to wait until they are
|
|
||||||
// proven out, have more efficient hardware, and/or apply them only to new
|
|
||||||
// applications.
|
|
||||||
if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) {
|
|
||||||
mallopt(M_BIONIC_ZERO_INIT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
|
|
||||||
runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT;
|
|
||||||
|
|
||||||
bool forceEnableGwpAsan = false;
|
|
||||||
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
|
|
||||||
default:
|
|
||||||
case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
|
|
||||||
break;
|
|
||||||
case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
|
|
||||||
forceEnableGwpAsan = true;
|
|
||||||
[[fallthrough]];
|
|
||||||
case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
|
|
||||||
android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
|
|
||||||
}
|
|
||||||
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
|
|
||||||
runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
|
|
||||||
|
|
||||||
if (NeedsNoRandomizeWorkaround()) {
|
|
||||||
// Work around ARM kernel ASLR lossage (http://b/5817320).
|
|
||||||
int old_personality = personality(0xffffffff);
|
|
||||||
int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
|
|
||||||
if (new_personality == -1) {
|
|
||||||
ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn);
|
SetGids(env, gids, is_child_zygote, fail_fn);
|
||||||
|
SetRLimits(env, rlimits, fail_fn);
|
||||||
|
|
||||||
__android_log_close();
|
if (need_pre_initialize_native_bridge) {
|
||||||
AStatsSocket_close();
|
// Due to the logic behind need_pre_initialize_native_bridge we know that
|
||||||
|
// instruction_set contains a value.
|
||||||
|
android::PreInitializeNativeBridge(app_data_dir.has_value() ? app_data_dir.value().c_str()
|
||||||
|
: nullptr,
|
||||||
|
instruction_set.value().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
|
if (setresgid(gid, gid, gid) == -1) {
|
||||||
const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
|
fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
|
// Must be called when the new process still has CAP_SYS_ADMIN, in this case,
|
||||||
fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed",
|
// before changing uid from 0, which clears capabilities. The other
|
||||||
uid, is_system_server, se_info_ptr, nice_name_ptr));
|
// alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
|
||||||
}
|
// breaks SELinux domain transition (see b/71859146). As the result,
|
||||||
|
// privileged syscalls used below still need to be accessible in app process.
|
||||||
|
SetUpSeccompFilter(uid, is_child_zygote);
|
||||||
|
|
||||||
// Make it easier to debug audit logs by setting the main thread's name to the
|
// Must be called before losing the permission to set scheduler policy.
|
||||||
// nice name rather than "app_process".
|
SetSchedulerPolicy(fail_fn, is_top_app);
|
||||||
if (nice_name.has_value()) {
|
|
||||||
SetThreadName(nice_name.value());
|
|
||||||
} else if (is_system_server) {
|
|
||||||
SetThreadName("system_server");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
|
if (setresuid(uid, uid, uid) == -1) {
|
||||||
UnsetChldSignalHandler();
|
fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "dumpable" flag of a process, which controls core dump generation, is
|
||||||
|
// overwritten by the value in /proc/sys/fs/suid_dumpable when the effective
|
||||||
|
// user or group ID changes. See proc(5) for possible values. In most cases,
|
||||||
|
// the value is 0, so core dumps are disabled for zygote children. However,
|
||||||
|
// when running in a Chrome OS container, the value is already set to 2,
|
||||||
|
// which allows the external crash reporter to collect all core dumps. Since
|
||||||
|
// only system crashes are interested, core dump is disabled for app
|
||||||
|
// processes. This also ensures compliance with CTS.
|
||||||
|
int dumpable = prctl(PR_GET_DUMPABLE);
|
||||||
|
if (dumpable == -1) {
|
||||||
|
ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
|
||||||
|
RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dumpable == 2 && uid >= AID_APP) {
|
||||||
|
if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
|
||||||
|
ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
|
||||||
|
RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set process properties to enable debugging if required.
|
||||||
|
if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) {
|
||||||
|
EnableDebugger();
|
||||||
|
}
|
||||||
|
if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
|
||||||
|
// simpleperf needs the process to be dumpable to profile it.
|
||||||
|
if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
|
||||||
|
ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno));
|
||||||
|
RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapTaggingLevel heap_tagging_level;
|
||||||
|
switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) {
|
||||||
|
case RuntimeFlags::MEMORY_TAG_LEVEL_TBI:
|
||||||
|
heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
|
||||||
|
break;
|
||||||
|
case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC:
|
||||||
|
heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC;
|
||||||
|
break;
|
||||||
|
case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC:
|
||||||
|
heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level);
|
||||||
|
|
||||||
|
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
|
||||||
|
// runtime.
|
||||||
|
runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
|
||||||
|
|
||||||
|
// Avoid heap zero initialization for applications without MTE. Zero init may
|
||||||
|
// cause app compat problems, use more memory, or reduce performance. While it
|
||||||
|
// would be nice to have them for apps, we will have to wait until they are
|
||||||
|
// proven out, have more efficient hardware, and/or apply them only to new
|
||||||
|
// applications.
|
||||||
|
if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) {
|
||||||
|
mallopt(M_BIONIC_ZERO_INIT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
|
||||||
|
// runtime.
|
||||||
|
runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT;
|
||||||
|
|
||||||
|
bool forceEnableGwpAsan = false;
|
||||||
|
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
|
||||||
|
default:
|
||||||
|
case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
|
||||||
|
break;
|
||||||
|
case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
|
||||||
|
forceEnableGwpAsan = true;
|
||||||
|
[[fallthrough]];
|
||||||
|
case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
|
||||||
|
android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
|
||||||
|
}
|
||||||
|
// Now that we've used the flag, clear it so that we don't pass unknown flags to the ART
|
||||||
|
// runtime.
|
||||||
|
runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
|
||||||
|
|
||||||
|
if (NeedsNoRandomizeWorkaround()) {
|
||||||
|
// Work around ARM kernel ASLR lossage (http://b/5817320).
|
||||||
|
int old_personality = personality(0xffffffff);
|
||||||
|
int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
|
||||||
|
if (new_personality == -1) {
|
||||||
|
ALOGW("personality(%d) failed: %s", new_personality, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
|
||||||
|
fail_fn);
|
||||||
|
|
||||||
|
__android_log_close();
|
||||||
|
AStatsSocket_close();
|
||||||
|
|
||||||
|
const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
|
||||||
|
const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
|
||||||
|
|
||||||
|
if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
|
||||||
|
fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
|
||||||
|
is_system_server, se_info_ptr, nice_name_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make it easier to debug audit logs by setting the main thread's name to the
|
||||||
|
// nice name rather than "app_process".
|
||||||
|
if (nice_name.has_value()) {
|
||||||
|
SetThreadName(nice_name.value());
|
||||||
|
} else if (is_system_server) {
|
||||||
|
SetThreadName("system_server");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
|
||||||
|
UnsetChldSignalHandler();
|
||||||
|
|
||||||
|
if (is_system_server) {
|
||||||
|
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags);
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
fail_fn("Error calling post fork system server hooks.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(b/117874058): Remove hardcoded label here.
|
||||||
|
static const char* kSystemServerLabel = "u:r:system_server:s0";
|
||||||
|
if (selinux_android_setcon(kSystemServerLabel) != 0) {
|
||||||
|
fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_child_zygote) {
|
||||||
|
initUnsolSocketToSystemServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
|
||||||
|
is_system_server, is_child_zygote, managed_instruction_set);
|
||||||
|
|
||||||
|
// Reset the process priority to the default value.
|
||||||
|
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
|
||||||
|
|
||||||
if (is_system_server) {
|
|
||||||
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags);
|
|
||||||
if (env->ExceptionCheck()) {
|
if (env->ExceptionCheck()) {
|
||||||
fail_fn("Error calling post fork system server hooks.");
|
fail_fn("Error calling post fork hooks.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(oth): Remove hardcoded label here (b/117874058).
|
|
||||||
static const char* kSystemServerLabel = "u:r:system_server:s0";
|
|
||||||
if (selinux_android_setcon(kSystemServerLabel) != 0) {
|
|
||||||
fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_child_zygote) {
|
|
||||||
initUnsolSocketToSystemServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
|
|
||||||
is_system_server, is_child_zygote, managed_instruction_set);
|
|
||||||
|
|
||||||
// Reset the process priority to the default value.
|
|
||||||
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
|
|
||||||
|
|
||||||
if (env->ExceptionCheck()) {
|
|
||||||
fail_fn("Error calling post fork hooks.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
|
static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
|
||||||
@@ -2068,12 +2069,11 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl
|
|||||||
|
|
||||||
NO_PAC_FUNC
|
NO_PAC_FUNC
|
||||||
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
|
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
|
||||||
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
|
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||||
jint runtime_flags, jobjectArray rlimits,
|
jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
|
||||||
jint mount_external, jstring se_info, jstring nice_name,
|
|
||||||
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
|
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
|
||||||
jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
|
jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
|
||||||
jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
|
jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list,
|
||||||
jboolean mount_data_dirs, jboolean mount_storage_dirs) {
|
jboolean mount_data_dirs, jboolean mount_storage_dirs) {
|
||||||
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
|
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
|
||||||
|
|
||||||
@@ -2108,14 +2108,11 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
|
|||||||
pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
|
pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
|
||||||
capabilities, capabilities,
|
mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
|
||||||
mount_external, se_info, nice_name, false,
|
instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
|
||||||
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
|
allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
|
||||||
is_top_app == JNI_TRUE, pkg_data_info_list,
|
mount_storage_dirs == JNI_TRUE);
|
||||||
whitelisted_data_info_list,
|
|
||||||
mount_data_dirs == JNI_TRUE,
|
|
||||||
mount_storage_dirs == JNI_TRUE);
|
|
||||||
}
|
}
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
@@ -2147,12 +2144,11 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
|
|||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// System server prcoess does not need data isolation so no need to
|
// System server prcoess does not need data isolation so no need to
|
||||||
// know pkg_data_info_list.
|
// know pkg_data_info_list.
|
||||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
|
||||||
permitted_capabilities, effective_capabilities,
|
effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
|
||||||
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
|
|
||||||
false, nullptr, nullptr, /* is_top_app= */ false,
|
false, nullptr, nullptr, /* is_top_app= */ false,
|
||||||
/* pkg_data_info_list */ nullptr,
|
/* pkg_data_info_list */ nullptr,
|
||||||
/* whitelisted_data_info_list */ nullptr, false, false);
|
/* allowlisted_data_info_list */ nullptr, false, false);
|
||||||
} else if (pid > 0) {
|
} else if (pid > 0) {
|
||||||
// The zygote process checks whether the child process has died or not.
|
// The zygote process checks whether the child process has died or not.
|
||||||
ALOGI("System server process %d has been created", pid);
|
ALOGI("System server process %d has been created", pid);
|
||||||
@@ -2260,7 +2256,7 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
|
|||||||
if (!path_cstr) {
|
if (!path_cstr) {
|
||||||
RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
|
RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
|
||||||
}
|
}
|
||||||
FileDescriptorWhitelist::Get()->Allow(path_cstr);
|
FileDescriptorAllowlist::Get()->Allow(path_cstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
|
static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
|
||||||
@@ -2295,20 +2291,19 @@ static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
|
|||||||
* @param is_top_app If the process is for top (high priority) application
|
* @param is_top_app If the process is for top (high priority) application
|
||||||
*/
|
*/
|
||||||
static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
|
static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
|
||||||
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
|
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
|
||||||
jint runtime_flags, jobjectArray rlimits,
|
jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
|
||||||
jint mount_external, jstring se_info, jstring nice_name,
|
jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir,
|
||||||
jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
|
jboolean is_top_app, jobjectArray pkg_data_info_list,
|
||||||
jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
|
jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs,
|
||||||
jboolean mount_data_dirs, jboolean mount_storage_dirs) {
|
jboolean mount_storage_dirs) {
|
||||||
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
|
jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
|
||||||
|
|
||||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
|
||||||
capabilities, capabilities,
|
mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
|
||||||
mount_external, se_info, nice_name, false,
|
instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
|
||||||
is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
|
allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
|
||||||
is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list,
|
mount_storage_dirs == JNI_TRUE);
|
||||||
mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
#include <android-base/stringprintf.h>
|
#include <android-base/stringprintf.h>
|
||||||
#include <android-base/strings.h>
|
#include <android-base/strings.h>
|
||||||
|
|
||||||
// Static whitelist of open paths that the zygote is allowed to keep open.
|
// Static allowlist of open paths that the zygote is allowed to keep open.
|
||||||
static const char* kPathWhitelist[] = {
|
static const char* kPathAllowlist[] = {
|
||||||
"/dev/null",
|
"/dev/null",
|
||||||
"/dev/socket/zygote",
|
"/dev/socket/zygote",
|
||||||
"/dev/socket/zygote_secondary",
|
"/dev/socket/zygote_secondary",
|
||||||
@@ -51,118 +51,114 @@ static const char* kPathWhitelist[] = {
|
|||||||
static const char kFdPath[] = "/proc/self/fd";
|
static const char kFdPath[] = "/proc/self/fd";
|
||||||
|
|
||||||
// static
|
// static
|
||||||
FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
|
FileDescriptorAllowlist* FileDescriptorAllowlist::Get() {
|
||||||
if (instance_ == nullptr) {
|
if (instance_ == nullptr) {
|
||||||
instance_ = new FileDescriptorWhitelist();
|
instance_ = new FileDescriptorAllowlist();
|
||||||
}
|
}
|
||||||
return instance_;
|
return instance_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsArtMemfd(const std::string& path) {
|
static bool IsArtMemfd(const std::string& path) {
|
||||||
return android::base::StartsWith(path, "/memfd:/boot-image-methods.art");
|
return android::base::StartsWith(path, "/memfd:/boot-image-methods.art");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
|
bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const {
|
||||||
// Check the static whitelist path.
|
// Check the static allowlist path.
|
||||||
for (const auto& whitelist_path : kPathWhitelist) {
|
for (const auto& allowlist_path : kPathAllowlist) {
|
||||||
if (path == whitelist_path)
|
if (path == allowlist_path) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check any paths added to the dynamic whitelist.
|
|
||||||
for (const auto& whitelist_path : whitelist_) {
|
|
||||||
if (path == whitelist_path)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Framework jars are allowed.
|
|
||||||
static const char* kFrameworksPrefix[] = {
|
|
||||||
"/system/framework/",
|
|
||||||
"/system_ext/framework/",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* kJarSuffix = ".jar";
|
|
||||||
|
|
||||||
for (const auto& frameworks_prefix : kFrameworksPrefix) {
|
|
||||||
if (android::base::StartsWith(path, frameworks_prefix)
|
|
||||||
&& android::base::EndsWith(path, kJarSuffix)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
|
// Check any paths added to the dynamic allowlist.
|
||||||
static const char* kApexPrefix = "/apex/";
|
for (const auto& allowlist_path : allowlist_) {
|
||||||
static const char* kApexJavalibPathSuffix = "/javalib";
|
if (path == allowlist_path) return true;
|
||||||
if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
|
}
|
||||||
android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the in-memory file created by ART through memfd_create is allowed.
|
// Framework jars are allowed.
|
||||||
if (IsArtMemfd(path)) {
|
static const char* kFrameworksPrefix[] = {
|
||||||
return true;
|
"/system/framework/",
|
||||||
}
|
"/system_ext/framework/",
|
||||||
|
};
|
||||||
|
|
||||||
// Whitelist files needed for Runtime Resource Overlay, like these:
|
static const char* kJarSuffix = ".jar";
|
||||||
// /system/vendor/overlay/framework-res.apk
|
|
||||||
// /system/vendor/overlay-subdir/pg/framework-res.apk
|
|
||||||
// /vendor/overlay/framework-res.apk
|
|
||||||
// /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
|
|
||||||
// /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
|
|
||||||
// /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
|
|
||||||
// See AssetManager.cpp for more details on overlay-subdir.
|
|
||||||
static const char* kOverlayDir = "/system/vendor/overlay/";
|
|
||||||
static const char* kVendorOverlayDir = "/vendor/overlay";
|
|
||||||
static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
|
|
||||||
static const char* kSystemProductOverlayDir = "/system/product/overlay/";
|
|
||||||
static const char* kProductOverlayDir = "/product/overlay";
|
|
||||||
static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
|
|
||||||
static const char* kSystemExtOverlayDir = "/system_ext/overlay";
|
|
||||||
static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
|
|
||||||
static const char* kOdmOverlayDir = "/odm/overlay";
|
|
||||||
static const char* kSystemOemOverlayDir = "/system/oem/overlay";
|
|
||||||
static const char* kOemOverlayDir = "/oem/overlay";
|
|
||||||
static const char* kApkSuffix = ".apk";
|
|
||||||
|
|
||||||
if ((android::base::StartsWith(path, kOverlayDir)
|
for (const auto& frameworks_prefix : kFrameworksPrefix) {
|
||||||
|| android::base::StartsWith(path, kVendorOverlaySubdir)
|
if (android::base::StartsWith(path, frameworks_prefix) &&
|
||||||
|| android::base::StartsWith(path, kVendorOverlayDir)
|
android::base::EndsWith(path, kJarSuffix)) {
|
||||||
|| android::base::StartsWith(path, kSystemProductOverlayDir)
|
return true;
|
||||||
|| android::base::StartsWith(path, kProductOverlayDir)
|
}
|
||||||
|| android::base::StartsWith(path, kSystemSystemExtOverlayDir)
|
}
|
||||||
|| android::base::StartsWith(path, kSystemExtOverlayDir)
|
|
||||||
|| android::base::StartsWith(path, kSystemOdmOverlayDir)
|
|
||||||
|| android::base::StartsWith(path, kOdmOverlayDir)
|
|
||||||
|| android::base::StartsWith(path, kSystemOemOverlayDir)
|
|
||||||
|| android::base::StartsWith(path, kOemOverlayDir))
|
|
||||||
&& android::base::EndsWith(path, kApkSuffix)
|
|
||||||
&& path.find("/../") == std::string::npos) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
|
// Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
|
||||||
static const char* kOverlayIdmapSuffix = ".apk@idmap";
|
static const char* kApexPrefix = "/apex/";
|
||||||
if (android::base::StartsWith(path, kOverlayIdmapPrefix)
|
static const char* kApexJavalibPathSuffix = "/javalib";
|
||||||
&& android::base::EndsWith(path, kOverlayIdmapSuffix)
|
if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
|
||||||
&& path.find("/../") == std::string::npos) {
|
android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All regular files that are placed under this path are whitelisted automatically.
|
// the in-memory file created by ART through memfd_create is allowed.
|
||||||
static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
|
if (IsArtMemfd(path)) {
|
||||||
if (android::base::StartsWith(path, kZygoteWhitelistPath)
|
return true;
|
||||||
&& path.find("/../") == std::string::npos) {
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
// Allowlist files needed for Runtime Resource Overlay, like these:
|
||||||
|
// /system/vendor/overlay/framework-res.apk
|
||||||
|
// /system/vendor/overlay-subdir/pg/framework-res.apk
|
||||||
|
// /vendor/overlay/framework-res.apk
|
||||||
|
// /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
|
||||||
|
// /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
|
||||||
|
// /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
|
||||||
|
// See AssetManager.cpp for more details on overlay-subdir.
|
||||||
|
static const char* kOverlayDir = "/system/vendor/overlay/";
|
||||||
|
static const char* kVendorOverlayDir = "/vendor/overlay";
|
||||||
|
static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
|
||||||
|
static const char* kSystemProductOverlayDir = "/system/product/overlay/";
|
||||||
|
static const char* kProductOverlayDir = "/product/overlay";
|
||||||
|
static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
|
||||||
|
static const char* kSystemExtOverlayDir = "/system_ext/overlay";
|
||||||
|
static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
|
||||||
|
static const char* kOdmOverlayDir = "/odm/overlay";
|
||||||
|
static const char* kSystemOemOverlayDir = "/system/oem/overlay";
|
||||||
|
static const char* kOemOverlayDir = "/oem/overlay";
|
||||||
|
static const char* kApkSuffix = ".apk";
|
||||||
|
|
||||||
|
if ((android::base::StartsWith(path, kOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kVendorOverlaySubdir) ||
|
||||||
|
android::base::StartsWith(path, kVendorOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kSystemProductOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kProductOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kSystemSystemExtOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kSystemExtOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kSystemOdmOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kOdmOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kSystemOemOverlayDir) ||
|
||||||
|
android::base::StartsWith(path, kOemOverlayDir)) &&
|
||||||
|
android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
|
||||||
|
static const char* kOverlayIdmapSuffix = ".apk@idmap";
|
||||||
|
if (android::base::StartsWith(path, kOverlayIdmapPrefix) &&
|
||||||
|
android::base::EndsWith(path, kOverlayIdmapSuffix) &&
|
||||||
|
path.find("/../") == std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All regular files that are placed under this path are allowlisted
|
||||||
|
// automatically. The directory name is maintained for compatibility.
|
||||||
|
static const char* kZygoteAllowlistPath = "/vendor/zygote_whitelist/";
|
||||||
|
if (android::base::StartsWith(path, kZygoteAllowlistPath) &&
|
||||||
|
path.find("/../") == std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptorWhitelist::FileDescriptorWhitelist()
|
FileDescriptorAllowlist::FileDescriptorAllowlist() : allowlist_() {}
|
||||||
: whitelist_() {
|
|
||||||
}
|
|
||||||
|
|
||||||
FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
|
FileDescriptorAllowlist* FileDescriptorAllowlist::instance_ = nullptr;
|
||||||
|
|
||||||
// Keeps track of all relevant information (flags, offset etc.) of an
|
// Keeps track of all relevant information (flags, offset etc.) of an
|
||||||
// open zygote file descriptor.
|
// open zygote file descriptor.
|
||||||
@@ -215,7 +211,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn)
|
|||||||
fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
|
fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
|
const FileDescriptorAllowlist* allowlist = FileDescriptorAllowlist::Get();
|
||||||
|
|
||||||
if (S_ISSOCK(f_stat.st_mode)) {
|
if (S_ISSOCK(f_stat.st_mode)) {
|
||||||
std::string socket_name;
|
std::string socket_name;
|
||||||
@@ -223,16 +219,15 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn)
|
|||||||
fail_fn("Unable to get socket name");
|
fail_fn("Unable to get socket name");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!whitelist->IsAllowed(socket_name)) {
|
if (!allowlist->IsAllowed(socket_name)) {
|
||||||
fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
|
fail_fn(android::base::StringPrintf("Socket name not allowlisted : %s (fd=%d)",
|
||||||
socket_name.c_str(),
|
socket_name.c_str(), fd));
|
||||||
fd));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FileDescriptorInfo(fd);
|
return new FileDescriptorInfo(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only handle whitelisted regular files and character devices. Whitelisted
|
// We only handle allowlisted regular files and character devices. Allowlisted
|
||||||
// character devices must provide a guarantee of sensible behaviour when
|
// character devices must provide a guarantee of sensible behaviour when
|
||||||
// reopened.
|
// reopened.
|
||||||
//
|
//
|
||||||
@@ -266,8 +261,8 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn)
|
|||||||
strerror(errno)));
|
strerror(errno)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!whitelist->IsAllowed(file_path)) {
|
if (!allowlist->IsAllowed(file_path)) {
|
||||||
fail_fn(android::base::StringPrintf("Not whitelisted (%d): %s", fd, file_path.c_str()));
|
fail_fn(android::base::StringPrintf("Not allowlisted (%d): %s", fd, file_path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// File descriptor flags : currently on FD_CLOEXEC. We can set these
|
// File descriptor flags : currently on FD_CLOEXEC. We can set these
|
||||||
|
|||||||
@@ -33,42 +33,40 @@ class FileDescriptorInfo;
|
|||||||
// This type is duplicated in com_android_internal_os_Zygote.cpp
|
// This type is duplicated in com_android_internal_os_Zygote.cpp
|
||||||
typedef const std::function<void(std::string)>& fail_fn_t;
|
typedef const std::function<void(std::string)>& fail_fn_t;
|
||||||
|
|
||||||
// Whitelist of open paths that the zygote is allowed to keep open.
|
// Allowlist of open paths that the zygote is allowed to keep open.
|
||||||
//
|
//
|
||||||
// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
|
// In addition to the paths listed in kPathAllowlist in file_utils.cpp, and
|
||||||
// paths dynamically added with Allow(), all files ending with ".jar"
|
// paths dynamically added with Allow(), all files ending with ".jar"
|
||||||
// under /system/framework" are whitelisted. See IsAllowed() for the canonical
|
// under /system/framework" are allowlisted. See IsAllowed() for the canonical
|
||||||
// definition.
|
// definition.
|
||||||
//
|
//
|
||||||
// If the whitelisted path is associated with a regular file or a
|
// If the allowlisted path is associated with a regular file or a
|
||||||
// character device, the file is reopened after a fork with the same
|
// character device, the file is reopened after a fork with the same
|
||||||
// offset and mode. If the whilelisted path is associated with a
|
// offset and mode. If the allowlisted path is associated with a
|
||||||
// AF_UNIX socket, the socket will refer to /dev/null after each
|
// AF_UNIX socket, the socket will refer to /dev/null after each
|
||||||
// fork, and all operations on it will fail.
|
// fork, and all operations on it will fail.
|
||||||
class FileDescriptorWhitelist {
|
class FileDescriptorAllowlist {
|
||||||
public:
|
public:
|
||||||
// Lazily creates the global whitelist.
|
// Lazily creates the global allowlist.
|
||||||
static FileDescriptorWhitelist* Get();
|
static FileDescriptorAllowlist* Get();
|
||||||
|
|
||||||
// Adds a path to the whitelist.
|
// Adds a path to the allowlist.
|
||||||
void Allow(const std::string& path) {
|
void Allow(const std::string& path) { allowlist_.push_back(path); }
|
||||||
whitelist_.push_back(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true iff. a given path is whitelisted. A path is whitelisted
|
// Returns true iff. a given path is allowlisted. A path is allowlisted
|
||||||
// if it belongs to the whitelist (see kPathWhitelist) or if it's a path
|
// if it belongs to the allowlist (see kPathAllowlist) or if it's a path
|
||||||
// under /system/framework that ends with ".jar" or if it is a system
|
// under /system/framework that ends with ".jar" or if it is a system
|
||||||
// framework overlay.
|
// framework overlay.
|
||||||
bool IsAllowed(const std::string& path) const;
|
bool IsAllowed(const std::string& path) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileDescriptorWhitelist();
|
FileDescriptorAllowlist();
|
||||||
|
|
||||||
static FileDescriptorWhitelist* instance_;
|
static FileDescriptorAllowlist* instance_;
|
||||||
|
|
||||||
std::vector<std::string> whitelist_;
|
std::vector<std::string> allowlist_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist);
|
DISALLOW_COPY_AND_ASSIGN(FileDescriptorAllowlist);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A FileDescriptorTable is a collection of FileDescriptorInfo objects
|
// A FileDescriptorTable is a collection of FileDescriptorInfo objects
|
||||||
|
|||||||
Reference in New Issue
Block a user