main: add configuration option to alter capability bounding set for PID 1
This also ensures that caps dropped from the bounding set are also dropped from the inheritable set, to be extra-secure. Usually that should change very little though as the inheritable set is empty for all our uses anyway.
This commit is contained in:
+88
-1
@@ -40,7 +40,8 @@ int have_effective_cap(int value) {
|
||||
cap_flag_value_t fv;
|
||||
int r;
|
||||
|
||||
if (!(cap = cap_get_proc()))
|
||||
cap = cap_get_proc();
|
||||
if (!cap)
|
||||
return -errno;
|
||||
|
||||
if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0)
|
||||
@@ -84,3 +85,89 @@ unsigned long cap_last_cap(void) {
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int capability_bounding_set_drop(uint64_t drop, bool right_now) {
|
||||
unsigned long i;
|
||||
cap_t after_cap = NULL, temp_cap = NULL;
|
||||
cap_flag_value_t fv;
|
||||
int r;
|
||||
|
||||
/* If we are run as PID 1 we will lack CAP_SETPCAP by default
|
||||
* in the effective set (yes, the kernel drops that when
|
||||
* executing init!), so get it back temporarily so that we can
|
||||
* call PR_CAPBSET_DROP. */
|
||||
|
||||
after_cap = cap_get_proc();
|
||||
if (!after_cap)
|
||||
return -errno;
|
||||
|
||||
if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
|
||||
cap_free(after_cap);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (fv != CAP_SET) {
|
||||
static const cap_value_t v = CAP_SETPCAP;
|
||||
|
||||
temp_cap = cap_dup(after_cap);
|
||||
if (!temp_cap) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (cap_set_proc(temp_cap) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= cap_last_cap(); i++) {
|
||||
|
||||
if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
|
||||
cap_value_t v;
|
||||
|
||||
/* Drop it from the bounding set */
|
||||
if (prctl(PR_CAPBSET_DROP, i) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
v = i;
|
||||
|
||||
/* Also drop it from the inheritable set, so
|
||||
* that anything we exec() loses the
|
||||
* capability for good. */
|
||||
if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* If we shall apply this right now drop it
|
||||
* also from our own capability sets. */
|
||||
if (right_now) {
|
||||
if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
|
||||
cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (temp_cap)
|
||||
cap_free(temp_cap);
|
||||
|
||||
if (after_cap) {
|
||||
cap_set_proc(after_cap);
|
||||
cap_free(after_cap);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
unsigned long cap_last_cap(void);
|
||||
int have_effective_cap(int value);
|
||||
int capability_bounding_set_drop(uint64_t caps, bool right_now);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user