summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnita Zhang <the.anitazha@gmail.com>2019-06-03 16:25:43 -0700
committerLennart Poettering <lennart@poettering.net>2019-06-20 21:46:36 +0200
commitf66ad46066a9911192f0b49eb06dae7dafc0c983 (patch)
tree12f50d541691c9ee7e9e92e23e53d9966d4ad94b
parenta5a4dfa1bc0078c858c250cbe6e97c0c04bf90f8 (diff)
downloadsystemd-f66ad46066a9911192f0b49eb06dae7dafc0c983.tar.gz
nspawn: don't hard fail when setting capabilities
The OCI changes in #9762 broke a use case in which we use nspawn from inside a container that has dropped capabilities from the bounding set that nspawn expected to retain. In an attempt to keep OCI compliance and support our use case, I made hard failing on setting capabilities not in the bounding set optional (hard fail if using OCI and log only if using nspawn cmdline). Fixes #12539
-rw-r--r--src/basic/capability-util.c38
-rw-r--r--src/basic/capability-util.h5
-rw-r--r--src/nspawn/nspawn.c13
3 files changed, 55 insertions, 1 deletions
diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c
index e3ed14f806..d62bb62de4 100644
--- a/src/basic/capability-util.c
+++ b/src/basic/capability-util.c
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "capability-util.h"
+#include "cap-list.h"
#include "fileio.h"
#include "log.h"
#include "macro.h"
@@ -364,6 +365,43 @@ bool ambient_capabilities_supported(void) {
return cache;
}
+bool capability_quintet_mangle(CapabilityQuintet *q) {
+ unsigned long i;
+ uint64_t combined, drop = 0;
+ bool ambient_supported;
+
+ assert(q);
+
+ combined = q->effective | q->bounding | q->inheritable | q->permitted;
+
+ ambient_supported = q->ambient != (uint64_t) -1;
+ if (ambient_supported)
+ combined |= q->ambient;
+
+ for (i = 0; i <= cap_last_cap(); i++) {
+ unsigned long bit = UINT64_C(1) << i;
+ if (!FLAGS_SET(combined, bit))
+ continue;
+
+ if (prctl(PR_CAPBSET_READ, i) > 0)
+ continue;
+
+ drop |= bit;
+
+ log_debug("Not in the current bounding set: %s", capability_to_name(i));
+ }
+
+ q->effective &= ~drop;
+ q->bounding &= ~drop;
+ q->inheritable &= ~drop;
+ q->permitted &= ~drop;
+
+ if (ambient_supported)
+ q->ambient &= ~drop;
+
+ return drop != 0; /* Let the caller know we changed something */
+}
+
int capability_quintet_enforce(const CapabilityQuintet *q) {
_cleanup_cap_free_ cap_t c = NULL, modified = NULL;
int r;
diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h
index e69b2fbb95..b5bce29ab5 100644
--- a/src/basic/capability-util.h
+++ b/src/basic/capability-util.h
@@ -69,4 +69,9 @@ static inline bool capability_quintet_is_set(const CapabilityQuintet *q) {
q->ambient != (uint64_t) -1;
}
+/* Mangles the specified caps quintet taking the current bounding set into account:
+ * drops all caps from all five sets if our bounding set doesn't allow them.
+ * Returns true if the quintet was modified. */
+bool capability_quintet_mangle(CapabilityQuintet *q);
+
int capability_quintet_enforce(const CapabilityQuintet *q);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 5079918ae1..1c0187ae5c 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -2317,7 +2317,11 @@ static int drop_capabilities(uid_t uid) {
if (q.ambient == (uint64_t) -1 && ambient_capabilities_supported())
q.ambient = 0;
- } else
+
+ if (capability_quintet_mangle(&q))
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Cannot set capabilities that are not in the current bounding set.");
+
+ } else {
q = (CapabilityQuintet) {
.bounding = arg_caps_retain,
.effective = uid == 0 ? arg_caps_retain : 0,
@@ -2326,6 +2330,13 @@ static int drop_capabilities(uid_t uid) {
.ambient = ambient_capabilities_supported() ? 0 : (uint64_t) -1,
};
+ /* If we're not using OCI, proceed with mangled capabilities (so we don't error out)
+ * in order to maintain the same behavior as systemd < 242. */
+ if (capability_quintet_mangle(&q))
+ log_warning("Some capabilities will not be set because they are not in the current bounding set.");
+
+ }
+
return capability_quintet_enforce(&q);
}