Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c438d56b authored by David Dai's avatar David Dai Committed by Automerger Merge Worker
Browse files

Permit CAP_SYS_NICE for virtualmachine groups am: b1a06182

parents 8b7049cc b1a06182
Loading
Loading
Loading
Loading
+61 −34
Original line number Diff line number Diff line
@@ -667,8 +667,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 "
@@ -680,6 +681,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));
@@ -1875,9 +1897,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,
@@ -1891,6 +1913,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);
@@ -1898,7 +1923,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() &&
@@ -2165,6 +2190,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;
@@ -2198,26 +2240,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);
  }

@@ -2494,6 +2517,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, jboolean mount_sysprop_overrides) {
    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,
@@ -2532,10 +2556,11 @@ 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, mount_sysprop_overrides == 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,
                         mount_sysprop_overrides == JNI_TRUE);
    }
    return pid;
}
@@ -2568,7 +2593,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, false);
@@ -2725,12 +2750,14 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
        jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs,
        jboolean mount_storage_dirs, jboolean mount_sysprop_overrides) {
    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, mount_sysprop_overrides == 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,
                     mount_sysprop_overrides == JNI_TRUE);
}

/**