capability: keep CAP_SETPCAP while dropping bounding caps

The kernel only allows dropping bounding caps as long as we have
CAP_SETPCAP. Hence, let's keep that before dropping the bounding caps,
and afterwards drop them too.
This commit is contained in:
Lennart Poettering 2019-03-06 11:31:20 +01:00
parent 75910ed9f4
commit 9a2c59119c

View file

@ -363,6 +363,7 @@ bool ambient_capabilities_supported(void) {
int capability_quintet_enforce(const CapabilityQuintet *q) {
_cleanup_cap_free_ cap_t c = NULL;
bool need_set_proc_again = false;
int r;
if (q->ambient != (uint64_t) -1) {
@ -393,7 +394,6 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, CAP_SET) < 0)
return -errno;
if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
return -errno;
@ -472,9 +472,39 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
}
}
if (changed)
if (cap_set_proc(c) < 0)
if (changed) {
_cleanup_cap_free_ cap_t modified = NULL;
/* In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit
* longer. Let's add it to our list hence for now. */
if (q->bounding != (uint64_t) -1) {
cap_value_t cv = CAP_SETPCAP;
modified = cap_dup(c);
if (!modified)
return -ENOMEM;
if (cap_set_flag(modified, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
return -errno;
if (cap_set_flag(modified, CAP_EFFECTIVE, 1, &cv, CAP_SET) < 0)
return -errno;
if (cap_compare(modified, c) == 0) {
/* No change? then drop this nonsense again */
cap_free(modified);
modified = NULL;
}
}
/* Now, let's enforce the caps for the first time. Note that this is where we acquire
* caps in any of the sets we currently don't have. We have to do this before
* droppoing the bounding caps below, since at that point we can never acquire new
* caps in inherited/permitted/effective anymore, but only lose them.*/
if (cap_set_proc(modified ?: c) < 0)
return -errno;
need_set_proc_again = !!modified;
}
}
if (q->bounding != (uint64_t) -1) {
@ -483,5 +513,13 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
return r;
}
/* If needed, let's now set the caps again, this time in the final version, which differs from what
* we have already set only in the CAP_SETPCAP bit, which we needed for dropping the bounding
* bits. This call only undoes bits and doesn't acquire any which means the bounding caps don't
* matter. */
if (need_set_proc_again)
if (cap_set_proc(c) < 0)
return -errno;
return 0;
}