summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chris Wailes <chriswailes@google.com> 2018-10-26 12:41:54 -0700
committer Chris Wailes <chriswailes@google.com> 2018-11-07 16:10:34 -0800
commitefc65b28857bce95626d84ff786c9969768648a5 (patch)
tree106218e9f6b25ab7ee7a1aec73e14c0fb29e969e
parentd605b5ab3dc329d36a391a6088d9464dbbb5c546 (diff)
Refactor native Zygote code.
This patch refactors the native Zygote code in anticipation of future changes. Notibly, this allows forking without application specific information, replaces a lambda that was defined twice with a function, and cleans up some of the jstring extraction logic. Bug: 68253328 Test: Built image, flashed phone, and booted Change-Id: I694994b2062b2839bf0cdf7d4bef366d98fc6eed Merged-In: I694994b2062b2839bf0cdf7d4bef366d98fc6eed
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp489
1 files changed, 257 insertions, 232 deletions
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 6f400c42bcbe..b96b8ecfb5e7 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -20,7 +20,9 @@
#include <sys/mount.h>
#include <linux/fs.h>
+#include <functional>
#include <list>
+#include <optional>
#include <sstream>
#include <string>
@@ -70,6 +72,8 @@
namespace {
+using namespace std::placeholders;
+
using android::String8;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -522,12 +526,12 @@ void SetThreadName(const char* thread_name) {
static FileDescriptorTable* gOpenFdTable = NULL;
static bool FillFileDescriptorVector(JNIEnv* env,
- jintArray java_fds,
+ jintArray managed_fds,
std::vector<int>* fds,
std::string* error_msg) {
CHECK(fds != nullptr);
- if (java_fds != nullptr) {
- ScopedIntArrayRO ar(env, java_fds);
+ if (managed_fds != nullptr) {
+ ScopedIntArrayRO ar(env, managed_fds);
if (ar.get() == nullptr) {
*error_msg = "Bad fd array";
return false;
@@ -540,32 +544,138 @@ static bool FillFileDescriptorVector(JNIEnv* env,
return true;
}
-// Utility routine to specialize a zygote child process.
-static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
- jint runtime_flags, jobjectArray javaRlimits,
- jlong permittedCapabilities, jlong effectiveCapabilities,
- jint mount_external, jstring java_se_info, jstring java_se_name,
- bool is_system_server, bool is_child_zygote, jstring instructionSet,
- jstring dataDir) {
+[[noreturn]]
+static void ZygoteFailure(JNIEnv* env,
+ const char* process_name,
+ jstring managed_process_name,
+ const std::string& msg) {
+ std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr;
+ if (managed_process_name != nullptr) {
+ 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();
+ }
+ }
+
+ const std::string& error_msg =
+ (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str());
+
+ env->FatalError(error_msg.c_str());
+ __builtin_unreachable();
+}
+
+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.");
+ }
+ }
+}
+
+// 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);
+ }
- 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 (gOpenFdTable == nullptr) {
+ gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
+ if (gOpenFdTable == nullptr) {
+ fail_fn(error_msg);
}
- if (se_name_c_str == nullptr && is_system_server) {
- se_name_c_str = "system_server";
+ } 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, managed_fds_to_close, &error_msg)) {
+ fail_fn(error_msg);
}
- 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();
- };
+
+ // 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.
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);
}
+
if (!DropCapabilitiesBoundingSet(&error_msg)) {
fail_fn(error_msg);
}
- bool use_native_bridge = !is_system_server && (instructionSet != NULL)
- && android::NativeBridgeAvailable();
- if (use_native_bridge) {
- ScopedUtfChars isa_string(env, instructionSet);
- use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
- }
- if (use_native_bridge && dataDir == NULL) {
- // dataDir should never be null if we need to use a native bridge.
- // In general, dataDir will never be null for normal applications. It can only happen in
- // special cases (for isolated processes which are not associated with any app). These are
- // launched by the framework and should not be emulated anyway.
+ bool use_native_bridge = !is_system_server &&
+ instruction_set.has_value() &&
+ android::NativeBridgeAvailable() &&
+ android::NeedsNativeBridge(instruction_set.value().c_str());
+
+ if (use_native_bridge && !app_data_dir.has_value()) {
+ // The app_data_dir variable should never be empty if we need to use a
+ // native bridge. In general, app_data_dir will never be empty for normal
+ // applications. It can only happen in special cases (for isolated
+ // processes which are not associated with any app). These are launched by
+ // the framework and should not be emulated anyway.
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)) {
@@ -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);
}
- if (!SetRLimits(env, javaRlimits, &error_msg)) {
+ if (!SetRLimits(env, rlimits, &error_msg)) {
fail_fn(error_msg);
}
if (use_native_bridge) {
- ScopedUtfChars isa_string(env, instructionSet);
- ScopedUtfChars data_dir(env, dataDir);
- android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
+ // Due to the logic behind use_native_bridge we know that both app_data_dir
+ // and instruction_set contain values.
+ android::PreInitializeNativeBridge(app_data_dir.value().c_str(),
+ instruction_set.value().c_str());
}
- int rc = setresgid(gid, gid, gid);
- if (rc == -1) {
+ if (setresgid(gid, gid, gid) == -1) {
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
- // 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.
+ // Must be called when the new process still has CAP_SYS_ADMIN, in this case,
+ // 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);
- rc = setresuid(uid, uid, uid);
- if (rc == -1) {
+ if (setresuid(uid, uid, uid) == -1) {
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));
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));
@@ -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)) {
fail_fn(error_msg);
}
@@ -691,42 +802,22 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
fail_fn(error_msg);
}
- const char* se_info_c_str = NULL;
- ScopedUtfChars* se_info = NULL;
- if (java_se_info != NULL) {
- se_info = new ScopedUtfChars(env, java_se_info);
- se_info_c_str = se_info->c_str();
- if (se_info_c_str == NULL) {
- 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));
+ 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 (se_name_c_str == NULL && is_system_server) {
- se_name_c_str = "system_server";
- }
- if (se_name_c_str != NULL) {
- SetThreadName(se_name_c_str);
+ if (nice_name.has_value()) {
+ SetThreadName(nice_name.value().c_str());
+ } else if (is_system_server) {
+ SetThreadName("system_server");
}
- delete se_info;
- delete se_name;
-
// Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers).
UnsetChldSignalHandler();
@@ -743,124 +834,101 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGi
}
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()) {
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);
+static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
- 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";
+ __user_cap_data_struct capdata[2];
+ if (capget(&capheader, &capdata[0]) == -1) {
+ ALOGE("capget failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "capget failed");
}
- 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;
+ return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32);
+}
- // 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);
+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);
}
- android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
+ /*
+ * Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
+ */
- pid_t pid = fork();
+ 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 (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);
+ if (native_gid_proxy.get() == nullptr) {
+ RuntimeAbort(env, __LINE__, "Bad gids array");
}
- // 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);
+ for (int gid_index = gids_num; --gids_num >= 0;) {
+ if (native_gid_proxy[gid_index] == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ break;
+ }
}
-
- // 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)));
+ if (gid_wakelock_found) {
+ capabilities |= (1LL << CAP_BLOCK_SUSPEND);
}
- return pid;
-}
-static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
- __user_cap_header_struct capheader;
- memset(&capheader, 0, sizeof(capheader));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- capheader.pid = 0;
+ /*
+ * 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);
+ }
- __user_cap_data_struct capdata[2];
- if (capget(&capheader, &capdata[0]) == -1) {
- ALOGE("capget failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "capget failed");
- }
+ /*
+ * Containers run without some capabilities, so drop any caps that are not
+ * available.
+ */
- return capdata[0].effective |
- (static_cast<uint64_t>(capdata[1].effective) << 32);
+ return capabilities & GetEffectiveCapabilityMask(env);
}
} // anonymous namespace
namespace android {
static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) {
- // security_getenforce is not allowed on app process. Initialize and cache the value before
- // zygote forks.
+ // security_getenforce is not allowed on app process. Initialize and cache
+ // the value before zygote forks.
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(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
- jint mount_external, jstring se_info, jstring se_name,
- jintArray fdsToClose, jintArray fdsToIgnore, jboolean is_child_zygote,
- jstring instructionSet, jstring appDataDir) {
- jlong capabilities = 0;
-
- // Grant CAP_WAKE_ALARM to the Bluetooth process.
- // 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);
+ jint mount_external, jstring se_info, jstring nice_name,
+ jintArray fds_to_close, jintArray fds_to_ignore, jboolean is_child_zygote,
+ jstring instruction_set, jstring app_data_dir) {
+ jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
- pid_t pid = ForkCommon(env, se_name, false, fdsToClose, fdsToIgnore);
+ pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
capabilities, capabilities,
- mount_external, se_info, se_name, false,
- is_child_zygote == JNI_TRUE, instructionSet, appDataDir);
+ mount_external, se_info, nice_name, false,
+ is_child_zygote == JNI_TRUE, instruction_set, app_data_dir);
}
return pid;
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
- jint runtime_flags, jobjectArray rlimits, jlong permittedCapabilities,
- jlong effectiveCapabilities) {
- pid_t pid = ForkCommon(env, NULL, true, NULL, NULL);
+ jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
+ jlong effective_capabilities) {
+ pid_t pid = ForkCommon(env, true,
+ /* managed_fds_to_close= */ nullptr,
+ /* managed_fds_to_ignore= */ nullptr);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
- permittedCapabilities, effectiveCapabilities,
- MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
- false, NULL, NULL);
+ permitted_capabilities, effective_capabilities,
+ MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
+ false, nullptr, nullptr);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
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);
const char* path_cstr = path_native.c_str();
if (!path_cstr) {
- RuntimeAbort(env, __LINE__, "path_cstr == NULL");
+ RuntimeAbort(env, __LINE__, "path_cstr == nullptr");
}
FileDescriptorWhitelist::Get()->Allow(path_cstr);
}