Merge "Refactor native Zygote code."

This commit is contained in:
Christian Wailes
2018-11-08 01:08:32 +00:00
committed by Gerrit Code Review

View File

@@ -20,7 +20,9 @@
#include <sys/mount.h> #include <sys/mount.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <functional>
#include <list> #include <list>
#include <optional>
#include <sstream> #include <sstream>
#include <string> #include <string>
@@ -70,6 +72,8 @@
namespace { namespace {
using namespace std::placeholders;
using android::String8; using android::String8;
using android::base::StringPrintf; using android::base::StringPrintf;
using android::base::WriteStringToFile; using android::base::WriteStringToFile;
@@ -522,12 +526,12 @@ void SetThreadName(const char* thread_name) {
static FileDescriptorTable* gOpenFdTable = NULL; static FileDescriptorTable* gOpenFdTable = NULL;
static bool FillFileDescriptorVector(JNIEnv* env, static bool FillFileDescriptorVector(JNIEnv* env,
jintArray java_fds, jintArray managed_fds,
std::vector<int>* fds, std::vector<int>* fds,
std::string* error_msg) { std::string* error_msg) {
CHECK(fds != nullptr); CHECK(fds != nullptr);
if (java_fds != nullptr) { if (managed_fds != nullptr) {
ScopedIntArrayRO ar(env, java_fds); ScopedIntArrayRO ar(env, managed_fds);
if (ar.get() == nullptr) { if (ar.get() == nullptr) {
*error_msg = "Bad fd array"; *error_msg = "Bad fd array";
return false; return false;
@@ -540,32 +544,138 @@ static bool FillFileDescriptorVector(JNIEnv* env,
return true; return true;
} }
// Utility routine to specialize a zygote child process. [[noreturn]]
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, static void ZygoteFailure(JNIEnv* env,
jint runtime_flags, jobjectArray javaRlimits, const char* process_name,
jlong permittedCapabilities, jlong effectiveCapabilities, jstring managed_process_name,
jint mount_external, jstring java_se_info, jstring java_se_name, const std::string& msg) {
bool is_system_server, bool is_child_zygote, jstring instructionSet, std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
jstring dataDir) { if (managed_process_name != nullptr) {
std::string error_msg; scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name));
if (scoped_managed_process_name_ptr->c_str() != nullptr) {
process_name = scoped_managed_process_name_ptr->c_str();
}
}
auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg) const std::string& error_msg =
__attribute__ ((noreturn)) { (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str());
const char* se_name_c_str = nullptr;
std::unique_ptr<ScopedUtfChars> se_name; env->FatalError(error_msg.c_str());
if (java_se_name != nullptr) { __builtin_unreachable();
se_name.reset(new ScopedUtfChars(env, java_se_name)); }
se_name_c_str = se_name->c_str();
static std::optional<std::string> ExtractJString(JNIEnv* env,
const char* process_name,
jstring managed_process_name,
jstring managed_string) {
if (managed_string == nullptr) {
return std::optional<std::string>();
} else {
ScopedUtfChars scoped_string_chars(env, managed_string);
if (scoped_string_chars.c_str() != nullptr) {
return std::optional<std::string>(scoped_string_chars.c_str());
} else {
ZygoteFailure(env, process_name, managed_process_name, "Failed to extract JString.");
} }
if (se_name_c_str == nullptr && is_system_server) { }
se_name_c_str = "system_server"; }
// Utility routine to fork a zygote.
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
jintArray managed_fds_to_close, jintArray managed_fds_to_ignore) {
SetSignalHandlers();
// Block SIGCHLD prior to fork.
sigset_t sigchld;
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
// Curry a failure function.
auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
nullptr, _1);
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
// This would cause failures because the FDs are not whitelisted.
//
// Note that the zygote process is single threaded at this point.
if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
// Close any logging related FDs before we start evaluating the list of
// file descriptors.
__android_log_close();
stats_log_close();
// If this is the first fork for this zygote, create the open FD table. If
// it isn't, we just need to check whether the list of open files has changed
// (and it shouldn't in the normal case).
std::string error_msg;
std::vector<int> fds_to_ignore;
if (!FillFileDescriptorVector(env, managed_fds_to_ignore, &fds_to_ignore, &error_msg)) {
fail_fn(error_msg);
}
if (gOpenFdTable == nullptr) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
if (gOpenFdTable == nullptr) {
fail_fn(error_msg);
} }
const std::string& error_msg = (se_name_c_str == nullptr) } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
? msg fail_fn(error_msg);
: StringPrintf("(%s) %s", se_name_c_str, msg.c_str()); }
env->FatalError(error_msg.c_str());
__builtin_unreachable(); android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
};
pid_t pid = fork();
if (pid == 0) {
// The child process.
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
if (!DetachDescriptors(env, managed_fds_to_close, &error_msg)) {
fail_fn(error_msg);
}
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
fail_fn(error_msg);
}
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
}
// We blocked SIGCHLD prior to a fork, we unblock it here.
if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
return pid;
}
// 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,
jlong permitted_capabilities, jlong effective_capabilities,
jint mount_external, jstring managed_se_info,
jstring managed_nice_name, bool is_system_server,
bool is_child_zygote, jstring managed_instruction_set,
jstring managed_app_data_dir) {
auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote",
managed_nice_name, _1);
auto extract_fn = std::bind(ExtractJString, env, is_system_server ? "system_server" : "zygote",
managed_nice_name, _1);
auto se_info = extract_fn(managed_se_info);
auto nice_name = extract_fn(managed_nice_name);
auto instruction_set = extract_fn(managed_instruction_set);
auto app_data_dir = extract_fn(managed_app_data_dir);
std::string error_msg;
// 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) {
@@ -574,26 +684,27 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
} }
} }
if (!SetInheritable(permittedCapabilities, &error_msg)) { if (!SetInheritable(permitted_capabilities, &error_msg)) {
fail_fn(error_msg); fail_fn(error_msg);
} }
if (!DropCapabilitiesBoundingSet(&error_msg)) { if (!DropCapabilitiesBoundingSet(&error_msg)) {
fail_fn(error_msg); fail_fn(error_msg);
} }
bool use_native_bridge = !is_system_server && (instructionSet != NULL) bool use_native_bridge = !is_system_server &&
&& android::NativeBridgeAvailable(); instruction_set.has_value() &&
if (use_native_bridge) { android::NativeBridgeAvailable() &&
ScopedUtfChars isa_string(env, instructionSet); android::NeedsNativeBridge(instruction_set.value().c_str());
use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
} if (use_native_bridge && !app_data_dir.has_value()) {
if (use_native_bridge && dataDir == NULL) { // The app_data_dir variable should never be empty if we need to use a
// dataDir should never be null if we need to use a native bridge. // native bridge. In general, app_data_dir will never be empty for normal
// In general, dataDir will never be null for normal applications. It can only happen in // applications. It can only happen in special cases (for isolated
// special cases (for isolated processes which are not associated with any app). These are // processes which are not associated with any app). These are launched by
// launched by the framework and should not be emulated anyway. // the framework and should not be emulated anyway.
use_native_bridge = false; use_native_bridge = false;
ALOGW("Native bridge will not be used because dataDir == NULL."); ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr.");
} }
if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) { if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
@@ -622,34 +733,33 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
} }
} }
if (!SetGids(env, javaGids, &error_msg)) { if (!SetGids(env, gids, &error_msg)) {
fail_fn(error_msg); fail_fn(error_msg);
} }
if (!SetRLimits(env, javaRlimits, &error_msg)) { if (!SetRLimits(env, rlimits, &error_msg)) {
fail_fn(error_msg); fail_fn(error_msg);
} }
if (use_native_bridge) { if (use_native_bridge) {
ScopedUtfChars isa_string(env, instructionSet); // Due to the logic behind use_native_bridge we know that both app_data_dir
ScopedUtfChars data_dir(env, dataDir); // and instruction_set contain values.
android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str()); android::PreInitializeNativeBridge(app_data_dir.value().c_str(),
instruction_set.value().c_str());
} }
int rc = setresgid(gid, gid, gid); if (setresgid(gid, gid, gid) == -1) {
if (rc == -1) {
fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
} }
// Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing // Must be called when the new process still has CAP_SYS_ADMIN, in this case,
// uid from 0, which clears capabilities. The other alternative is to call // before changing uid from 0, which clears capabilities. The other
// prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that
// b/71859146). As the result, privileged syscalls used below still need to be accessible in // breaks SELinux domain transition (see b/71859146). As the result,
// app process. // privileged syscalls used below still need to be accessible in app process.
SetUpSeccompFilter(uid); SetUpSeccompFilter(uid);
rc = setresuid(uid, uid, uid); if (setresuid(uid, uid, uid) == -1) {
if (rc == -1) {
fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
} }
@@ -666,6 +776,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno));
RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed");
} }
if (dumpable == 2 && uid >= AID_APP) { if (dumpable == 2 && uid >= AID_APP) {
if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) { if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno)); ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno));
@@ -682,7 +793,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
} }
} }
if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities, if (!SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities,
&error_msg)) { &error_msg)) {
fail_fn(error_msg); fail_fn(error_msg);
} }
@@ -691,41 +802,21 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
fail_fn(error_msg); fail_fn(error_msg);
} }
const char* se_info_c_str = NULL; const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr;
ScopedUtfChars* se_info = NULL; const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
if (java_se_info != NULL) {
se_info = new ScopedUtfChars(env, java_se_info); if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
se_info_c_str = se_info->c_str(); fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed",
if (se_info_c_str == NULL) { uid, is_system_server, se_info_ptr, nice_name_ptr));
fail_fn("se_info_c_str == NULL");
}
}
const char* se_name_c_str = NULL;
ScopedUtfChars* se_name = NULL;
if (java_se_name != NULL) {
se_name = new ScopedUtfChars(env, java_se_name);
se_name_c_str = se_name->c_str();
if (se_name_c_str == NULL) {
fail_fn("se_name_c_str == NULL");
}
}
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
if (rc == -1) {
fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
is_system_server, se_info_c_str, se_name_c_str));
} }
// Make it easier to debug audit logs by setting the main thread's name to the // Make it easier to debug audit logs by setting the main thread's name to the
// nice name rather than "app_process". // nice name rather than "app_process".
if (se_name_c_str == NULL && is_system_server) { if (nice_name.has_value()) {
se_name_c_str = "system_server"; SetThreadName(nice_name.value().c_str());
} else if (is_system_server) {
SetThreadName("system_server");
} }
if (se_name_c_str != NULL) {
SetThreadName(se_name_c_str);
}
delete se_info;
delete se_name;
// Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers). // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
UnsetChldSignalHandler(); UnsetChldSignalHandler();
@@ -743,102 +834,13 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
} }
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
is_system_server, is_child_zygote, instructionSet); is_system_server, is_child_zygote, managed_instruction_set);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
fail_fn("Error calling post fork hooks."); fail_fn("Error calling post fork hooks.");
} }
} }
// Utility routine to fork zygote and specialize the child process.
static pid_t ForkCommon(JNIEnv* env, jstring java_se_name, bool is_system_server,
jintArray fdsToClose, jintArray fdsToIgnore) {
SetSignalHandlers();
// Block SIGCHLD prior to fork.
sigset_t sigchld;
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
__attribute__ ((noreturn)) {
const char* se_name_c_str = nullptr;
std::unique_ptr<ScopedUtfChars> se_name;
if (java_se_name != nullptr) {
se_name.reset(new ScopedUtfChars(env, java_se_name));
se_name_c_str = se_name->c_str();
}
if (se_name_c_str == nullptr && is_system_server) {
se_name_c_str = "system_server";
}
const std::string& error_msg = (se_name_c_str == nullptr)
? msg
: StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
env->FatalError(error_msg.c_str());
__builtin_unreachable();
};
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
// This would cause failures because the FDs are not whitelisted.
//
// Note that the zygote process is single threaded at this point.
if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
// Close any logging related FDs before we start evaluating the list of
// file descriptors.
__android_log_close();
stats_log_close();
std::string error_msg;
// If this is the first fork for this zygote, create the open FD table.
// If it isn't, we just need to check whether the list of open files has
// changed (and it shouldn't in the normal case).
std::vector<int> fds_to_ignore;
if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
fail_fn(error_msg);
}
if (gOpenFdTable == NULL) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
if (gOpenFdTable == NULL) {
fail_fn(error_msg);
}
} else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
fail_fn(error_msg);
}
android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
pid_t pid = fork();
if (pid == 0) {
// The child process.
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
fail_fn(error_msg);
}
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
fail_fn(error_msg);
}
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
}
// We blocked SIGCHLD prior to a fork, we unblock it here.
if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
return pid;
}
static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
__user_cap_header_struct capheader; __user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader)); memset(&capheader, 0, sizeof(capheader));
@@ -851,16 +853,82 @@ static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
RuntimeAbort(env, __LINE__, "capget failed"); RuntimeAbort(env, __LINE__, "capget failed");
} }
return capdata[0].effective | return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32);
(static_cast<uint64_t>(capdata[1].effective) << 32); }
static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids,
bool is_child_zygote) {
jlong capabilities = 0;
/*
* Grant the following capabilities to the Bluetooth user:
* - CAP_WAKE_ALARM
* - CAP_NET_RAW
* - CAP_NET_BIND_SERVICE (for DHCP client functionality)
* - CAP_SYS_NICE (for setting RT priority for audio-related threads)
*/
if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
capabilities |= (1LL << CAP_NET_RAW);
capabilities |= (1LL << CAP_NET_BIND_SERVICE);
capabilities |= (1LL << CAP_SYS_NICE);
}
/*
* Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
*/
bool gid_wakelock_found = false;
if (gid == AID_WAKELOCK) {
gid_wakelock_found = true;
} else if (gids != nullptr) {
jsize gids_num = env->GetArrayLength(gids);
ScopedIntArrayRO native_gid_proxy(env, gids);
if (native_gid_proxy.get() == nullptr) {
RuntimeAbort(env, __LINE__, "Bad gids array");
}
for (int gid_index = gids_num; --gids_num >= 0;) {
if (native_gid_proxy[gid_index] == AID_WAKELOCK) {
gid_wakelock_found = true;
break;
}
}
}
if (gid_wakelock_found) {
capabilities |= (1LL << CAP_BLOCK_SUSPEND);
}
/*
* Grant child Zygote processes the following capabilities:
* - CAP_SETUID (change UID of child processes)
* - CAP_SETGID (change GID of child processes)
* - CAP_SETPCAP (change capabilities of child processes)
*/
if (is_child_zygote) {
capabilities |= (1LL << CAP_SETUID);
capabilities |= (1LL << CAP_SETGID);
capabilities |= (1LL << CAP_SETPCAP);
}
/*
* Containers run without some capabilities, so drop any caps that are not
* available.
*/
return capabilities & GetEffectiveCapabilityMask(env);
} }
} // anonymous namespace } // anonymous namespace
namespace android { namespace android {
static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) { static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) {
// security_getenforce is not allowed on app process. Initialize and cache the value before // security_getenforce is not allowed on app process. Initialize and cache
// zygote forks. // the value before zygote forks.
g_is_security_enforced = security_getenforce(); g_is_security_enforced = security_getenforce();
} }
@@ -871,76 +939,33 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl
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, jobjectArray rlimits, jint runtime_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name, jint mount_external, jstring se_info, jstring nice_name,
jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote, jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote,
jstring instructionSet, jstring appDataDir) { jstring instruction_set, jstring app_data_dir) {
jlong capabilities = 0; jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
// Grant CAP_WAKE_ALARM to the Bluetooth process. pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore);
// Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
// Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
// audio-related threads.
// TODO: consider making such functionality an RPC to netd.
if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
capabilities |= (1LL << CAP_NET_RAW);
capabilities |= (1LL << CAP_NET_BIND_SERVICE);
capabilities |= (1LL << CAP_SYS_NICE);
}
// Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
bool gid_wakelock_found = false;
if (gid == AID_WAKELOCK) {
gid_wakelock_found = true;
} else if (gids != NULL) {
jsize gids_num = env->GetArrayLength(gids);
ScopedIntArrayRO ar(env, gids);
if (ar.get() == NULL) {
RuntimeAbort(env, __LINE__, "Bad gids array");
}
for (int i = 0; i < gids_num; i++) {
if (ar[i] == AID_WAKELOCK) {
gid_wakelock_found = true;
break;
}
}
}
if (gid_wakelock_found) {
capabilities |= (1LL << CAP_BLOCK_SUSPEND);
}
// If forking a child zygote process, that zygote will need to be able to change
// the UID and GID of processes it forks, as well as drop those capabilities.
if (is_child_zygote) {
capabilities |= (1LL << CAP_SETUID);
capabilities |= (1LL << CAP_SETGID);
capabilities |= (1LL << CAP_SETPCAP);
}
// Containers run without some capabilities, so drop any caps that are not
// available.
capabilities &= GetEffectiveCapabilityMask(env);
pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
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, se_name, false, mount_external, se_info, nice_name, false,
is_child_zygote == JNI_TRUE, instructionSet, appDataDir); is_child_zygote == JNI_TRUE, instruction_set, app_data_dir);
} }
return pid; return pid;
} }
static jint com_android_internal_os_Zygote_nativeForkSystemServer( static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids, JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
jlong effectiveCapabilities) { jlong effective_capabilities) {
pid_t pid = ForkCommon(env, NULL, true, NULL, NULL); pid_t pid = ForkCommon(env, true,
/* managed_fds_to_close= */ nullptr,
/* managed_fds_to_ignore= */ nullptr);
if (pid == 0) { if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permittedCapabilities, effectiveCapabilities, permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, NULL, NULL); false, nullptr, nullptr);
} 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);
@@ -974,7 +999,7 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
ScopedUtfChars path_native(env, path); ScopedUtfChars path_native(env, path);
const char* path_cstr = path_native.c_str(); const char* path_cstr = path_native.c_str();
if (!path_cstr) { if (!path_cstr) {
RuntimeAbort(env, __LINE__, "path_cstr == NULL"); RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
} }
FileDescriptorWhitelist::Get()->Allow(path_cstr); FileDescriptorWhitelist::Get()->Allow(path_cstr);
} }