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

Commit 1391c906 authored by David Dai's avatar David Dai Committed by Gerrit Code Review
Browse files

Merge changes from topic "vm_gid_caps" into main

* changes:
  Permit CAP_SYS_NICE for virtualmachine groups
  Link MANAGE_VIRTUAL_MACHINE permissions with virtualmachine gid
parents 2025947d f513c74f
Loading
Loading
Loading
Loading
+59 −34
Original line number Diff line number Diff line
@@ -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);
}

/**
+4 −0
Original line number Diff line number Diff line
@@ -124,6 +124,10 @@
        <group gid="security_log_writer" />
    </permission>

    <permission name="android.permission.MANAGE_VIRTUAL_MACHINE">
        <group gid="virtualmachine" />
    </permission>

    <!-- These are permissions that were mapped to gids but we need
         to keep them here until an upgrade from L to the current
         version is to be supported. These permissions are built-in