From 45dab78e989a8e3f3cabb71ebc753e5a8fdcbcd6 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 1 Feb 2017 14:56:09 -0800 Subject: [PATCH] zygote: make all capabilities inheritable. Set CapInh to the full set of permitted capabilities, so that the crash handler can raise ambient capabilities to allow crash_dump to ptrace zygote-descended children without needing CAP_SYS_PTRACE. CapInh is restricted by filesystem capabilities if the ambient capability set hasn't been raised, so this should only have an effect when ambient capabilities are modified. Bug: http://b/34853272 Test: debuggerd -b `pidof system_server` Change-Id: I27d2aa4ab4fc47a183ce2b254be178de4d58840c --- core/jni/com_android_internal_os_Zygote.cpp | 33 +++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index a32dbad7838ff..3498108991fa1 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -253,13 +253,36 @@ static void DropCapabilitiesBoundingSet(JNIEnv* env) { ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify " "your kernel is compiled with file capabilities support"); } else { + ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno)); RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed"); } } } } -static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) { +static void SetInheritable(JNIEnv* env, uint64_t inheritable) { + __user_cap_header_struct capheader; + memset(&capheader, 0, sizeof(capheader)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; + + __user_cap_data_struct capdata[2]; + if (capget(&capheader, &capdata[0]) == -1) { + ALOGE("capget failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "capget failed"); + } + + capdata[0].inheritable = inheritable; + capdata[1].inheritable = inheritable >> 32; + + if (capset(&capheader, &capdata[0]) == -1) { + ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno)); + RuntimeAbort(env, __LINE__, "capset failed"); + } +} + +static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective, + uint64_t inheritable) { __user_cap_header_struct capheader; memset(&capheader, 0, sizeof(capheader)); capheader.version = _LINUX_CAPABILITY_VERSION_3; @@ -271,9 +294,12 @@ static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) { capdata[1].effective = effective >> 32; capdata[0].permitted = permitted; capdata[1].permitted = permitted >> 32; + capdata[0].inheritable = inheritable; + capdata[1].inheritable = inheritable >> 32; if (capset(&capheader, &capdata[0]) == -1) { - ALOGE("capset(%" PRId64 ", %" PRId64 ") failed", permitted, effective); + ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted, + effective, inheritable, strerror(errno)); RuntimeAbort(env, __LINE__, "capset failed"); } } @@ -508,6 +534,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra EnableKeepCapabilities(env); } + SetInheritable(env, permittedCapabilities); DropCapabilitiesBoundingSet(env); bool use_native_bridge = !is_system_server && (instructionSet != NULL) @@ -580,7 +607,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra } } - SetCapabilities(env, permittedCapabilities, effectiveCapabilities); + SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities); SetSchedulerPolicy(env);