diff options
| -rw-r--r-- | core/jni/com_android_internal_os_Zygote.cpp | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 9c40a28dfd81..63a6f4c42798 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -665,8 +665,9 @@ static void EnableKeepCapabilities(fail_fn_t fail_fn) { } } -static void DropCapabilitiesBoundingSet(fail_fn_t fail_fn) { +static void DropCapabilitiesBoundingSet(fail_fn_t fail_fn, jlong bounding_capabilities) { for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {; + if ((1LL << i) & bounding_capabilities) continue; if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) { if (errno == EINVAL) { ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify " @@ -678,6 +679,27 @@ static void DropCapabilitiesBoundingSet(fail_fn_t fail_fn) { } } +static bool MatchGid(JNIEnv* env, jintArray gids, jint gid, jint gid_to_find) { + if (gid == gid_to_find) return true; + + if (gids == nullptr) return false; + + 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 gids_index = 0; gids_index < gids_num; ++gids_index) { + if (native_gid_proxy[gids_index] == gid_to_find) { + return true; + } + } + + return false; +} + static void SetInheritable(uint64_t inheritable, fail_fn_t fail_fn) { __user_cap_header_struct capheader; memset(&capheader, 0, sizeof(capheader)); @@ -1742,9 +1764,9 @@ static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list, // 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, + jlong effective_capabilities, jlong bounding_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, bool is_top_app, jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, bool mount_data_dirs, @@ -1758,6 +1780,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, auto instruction_set = extract_fn(managed_instruction_set); auto app_data_dir = extract_fn(managed_app_data_dir); + // Permit bounding capabilities + permitted_capabilities |= bounding_capabilities; + // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { EnableKeepCapabilities(fail_fn); @@ -1765,7 +1790,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, SetInheritable(permitted_capabilities, fail_fn); - DropCapabilitiesBoundingSet(fail_fn); + DropCapabilitiesBoundingSet(fail_fn, bounding_capabilities); bool need_pre_initialize_native_bridge = !is_system_server && instruction_set.has_value() && android::NativeBridgeAvailable() && @@ -2028,6 +2053,23 @@ static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { return capdata[0].effective | (static_cast<uint64_t>(capdata[1].effective) << 32); } +static jlong CalculateBoundingCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids) { + jlong capabilities = 0; + + /* + * Grant CAP_SYS_NICE to CapInh/CapPrm/CapBnd for processes that can spawn + * VMs. This enables processes to execve on binaries with elevated + * capabilities if its file capability bits are set. This does not grant + * capability to the parent process(that spawns the VM) as the effective + * bits are not set. + */ + if (MatchGid(env, gids, gid, AID_VIRTUALMACHINE)) { + capabilities |= (1LL << CAP_SYS_NICE); + } + + return capabilities; +} + static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gids, bool is_child_zygote) { jlong capabilities = 0; @@ -2061,26 +2103,7 @@ static jlong CalculateCapabilities(JNIEnv* env, jint uid, jint gid, jintArray gi * 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 gids_index = 0; gids_index < gids_num; ++gids_index) { - if (native_gid_proxy[gids_index] == AID_WAKELOCK) { - gid_wakelock_found = true; - break; - } - } - } - - if (gid_wakelock_found) { + if (MatchGid(env, gids, gid, AID_WAKELOCK)) { capabilities |= (1LL << CAP_BLOCK_SUSPEND); } @@ -2357,6 +2380,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); + jlong bounding_capabilities = CalculateBoundingCapabilities(env, uid, gid, gids); if (UNLIKELY(managed_fds_to_close == nullptr)) { zygote::ZygoteFailure(env, "zygote", nice_name, @@ -2395,10 +2419,10 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, - mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, - instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, - allowlisted_data_info_list, mount_data_dirs == JNI_TRUE, - mount_storage_dirs == JNI_TRUE); + bounding_capabilities, mount_external, se_info, nice_name, false, + is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, + is_top_app == JNI_TRUE, pkg_data_info_list, allowlisted_data_info_list, + mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE); } return pid; } @@ -2431,7 +2455,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( // System server prcoess does not need data isolation so no need to // know pkg_data_info_list. SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, - effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, + effective_capabilities, 0, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, nullptr, nullptr, /* is_top_app= */ false, /* pkg_data_info_list */ nullptr, /* allowlisted_data_info_list */ nullptr, false, false); @@ -2588,12 +2612,13 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess( jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); + jlong bounding_capabilities = CalculateBoundingCapabilities(env, uid, gid, gids); SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, - mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, - instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, - allowlisted_data_info_list, mount_data_dirs == JNI_TRUE, - mount_storage_dirs == JNI_TRUE); + bounding_capabilities, mount_external, se_info, nice_name, false, + is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, + is_top_app == JNI_TRUE, pkg_data_info_list, allowlisted_data_info_list, + mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE); } /** |