diff options
| author | 2017-07-12 10:03:30 -0700 | |
|---|---|---|
| committer | 2017-08-16 08:21:58 -0700 | |
| commit | 72042c99a65b91fb701f1b13a0ba4b225769eece (patch) | |
| tree | e48465b15b36513c58d600f3910e0148e7ac805c | |
| parent | b279ec51b6e53396509848ce025f4bdbdd608da6 (diff) | |
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
| -rw-r--r-- | core/java/com/android/internal/os/ZygoteInit.java | 19 | ||||
| -rw-r--r-- | core/jni/com_android_internal_os_Zygote.cpp | 20 |
2 files changed, 34 insertions, 5 deletions
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index b7dff963abe8..7d61349ed4c1 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -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", diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index cb53106dbf28..d43849087a99 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -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); |