summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Luis Hector Chavez <lhchavez@google.com> 2017-07-12 10:03:30 -0700
committer Luis Hector Chavez <lhchavez@google.com> 2017-08-16 08:21:58 -0700
commit72042c99a65b91fb701f1b13a0ba4b225769eece (patch)
treee48465b15b36513c58d600f3910e0148e7ac805c
parentb279ec51b6e53396509848ce025f4bdbdd608da6 (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.java19
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp20
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);