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

Commit 72042c99 authored by Luis Hector Chavez's avatar Luis Hector Chavez
Browse files

Improve container capability bounding in containers

This change stops relying on the ro.boot.container property for dropping
a subset of capabilities and instead relies on the effective capability
mask of the Zygote process, prior to forking.

When Android is running in a pid/mount/net/user namespace, even if a
particular capability is present, some operations that require that
capability check whether it is allowed in the init namespace (instead of
in the current namespace), so they would fail even with the capability
granted within the namespace. So, explicitly dropping the capabilities
from the beginning allows for clearer signalling of which operations can
be expected to work instead of failing silently for mysterious reasons.

Bug: 63579953
Test: aosp_bullhead-eng still boots
Test: Running Zygote without CAP_SYS_MODULE makes it such that
      system_server does not request it.

Change-Id: I1d18d13341bcc04e701fd14092e7e94961728620
parent b279ec51
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ import android.security.keystore.AndroidKeyStoreProvider;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructCapUserData;
import android.system.StructCapUserHeader;
import android.text.Hyphenator;
import android.util.EventLog;
import android.util.Log;
@@ -80,7 +82,6 @@ public class ZygoteInit {

    private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
    private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
    private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container";

    private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
    private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
@@ -567,12 +568,20 @@ public class ZygoteInit {
            OsConstants.CAP_SYS_RESOURCE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG,
            OsConstants.CAP_WAKE_ALARM
            OsConstants.CAP_WAKE_ALARM,
            OsConstants.CAP_BLOCK_SUSPEND
        );
        /* Containers run without this capability, so avoid setting it in that case */
        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
        /* Containers run without some capabilities, so drop any caps that are not available. */
        StructCapUserHeader header = new StructCapUserHeader(
                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
        StructCapUserData[] data;
        try {
            data = Os.capget(header);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to capget()", ex);
        }
        capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);

        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
+20 −0
Original line number Diff line number Diff line
@@ -678,6 +678,22 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
  }
  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;

    __user_cap_data_struct capdata[2];
    if (capget(&capheader, &capdata[0]) == -1) {
        ALOGE("capget failed: %s", strerror(errno));
        RuntimeAbort(env, __LINE__, "capget failed");
    }

    return capdata[0].effective |
           (static_cast<uint64_t>(capdata[1].effective) << 32);
}
}  // anonymous namespace

namespace android {
@@ -728,6 +744,10 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
      capabilities |= (1LL << CAP_BLOCK_SUSPEND);
    }

    // Containers run without some capabilities, so drop any caps that are not
    // available.
    capabilities &= GetEffectiveCapabilityMask(env);

    return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
            rlimits, capabilities, capabilities, mount_external, se_info,
            se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);