Skip to content

Commit

Permalink
nspawn: don't hard fail when setting capabilities
Browse files Browse the repository at this point in the history
The OCI changes in systemd#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 systemd#12539
  • Loading branch information
anitazha committed Jun 20, 2019
1 parent b19eab1 commit f5793fc
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
38 changes: 38 additions & 0 deletions src/basic/capability-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/basic/capability-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
13 changes: 12 additions & 1 deletion src/nspawn/nspawn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(EPERM, "Cannot set capabilities that are not in the bounding set.");

} else {
q = (CapabilityQuintet) {
.bounding = arg_caps_retain,
.effective = uid == 0 ? arg_caps_retain : 0,
Expand All @@ -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 bounding set.");

}

return capability_quintet_enforce(&q);
}

Expand Down

0 comments on commit f5793fc

Please sign in to comment.