Merge pull request #16727 from wusto/core-fix-securebits
core: fix securebits setting
This commit is contained in:
commit
895abf3fdd
|
@ -161,28 +161,21 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
|
||||
_cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
|
||||
int capability_gain_cap_setpcap(cap_t *ret_before_caps) {
|
||||
_cleanup_cap_free_ cap_t caps = 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. */
|
||||
|
||||
before_cap = cap_get_proc();
|
||||
if (!before_cap)
|
||||
caps = cap_get_proc();
|
||||
if (!caps)
|
||||
return -errno;
|
||||
|
||||
if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
|
||||
if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
|
||||
return -errno;
|
||||
|
||||
if (fv != CAP_SET) {
|
||||
_cleanup_cap_free_ cap_t temp_cap = NULL;
|
||||
static const cap_value_t v = CAP_SETPCAP;
|
||||
|
||||
temp_cap = cap_dup(before_cap);
|
||||
temp_cap = cap_dup(caps);
|
||||
if (!temp_cap)
|
||||
return -errno;
|
||||
|
||||
|
@ -193,8 +186,27 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now) {
|
|||
log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
|
||||
|
||||
/* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
|
||||
* we'll fail later, when we actually intend to drop some capabilities. */
|
||||
* we'll fail later, when we actually intend to drop some capabilities or try to set securebits. */
|
||||
}
|
||||
if (ret_before_caps)
|
||||
/* Return the capabilities as they have been before setting CAP_SETPCAP */
|
||||
*ret_before_caps = TAKE_PTR(caps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
|
||||
_cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
|
||||
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. */
|
||||
|
||||
r = capability_gain_cap_setpcap(&before_cap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
after_cap = cap_dup(before_cap);
|
||||
if (!after_cap)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
unsigned cap_last_cap(void);
|
||||
int have_effective_cap(int value);
|
||||
int capability_gain_cap_setpcap(cap_t *return_caps);
|
||||
int capability_bounding_set_drop(uint64_t keep, bool right_now);
|
||||
int capability_bounding_set_drop_usermode(uint64_t keep);
|
||||
|
||||
|
|
|
@ -1077,26 +1077,42 @@ static int enforce_groups(gid_t gid, const gid_t *supplementary_gids, int ngids)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_securebits(int bits, int mask) {
|
||||
int current, applied;
|
||||
current = prctl(PR_GET_SECUREBITS);
|
||||
if (current < 0)
|
||||
return -errno;
|
||||
/* Clear all securebits defined in mask and set bits */
|
||||
applied = (current & ~mask) | bits;
|
||||
if (current == applied)
|
||||
return 0;
|
||||
if (prctl(PR_SET_SECUREBITS, applied) < 0)
|
||||
return -errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int enforce_user(const ExecContext *context, uid_t uid) {
|
||||
assert(context);
|
||||
int r;
|
||||
|
||||
if (!uid_is_valid(uid))
|
||||
return 0;
|
||||
|
||||
/* Sets (but doesn't look up) the uid and make sure we keep the
|
||||
* capabilities while doing so. */
|
||||
* capabilities while doing so. For setting secure bits the capability CAP_SETPCAP is
|
||||
* required, so we also need keep-caps in this case.
|
||||
*/
|
||||
|
||||
if (context->capability_ambient_set != 0) {
|
||||
if (context->capability_ambient_set != 0 || context->secure_bits != 0) {
|
||||
|
||||
/* First step: If we need to keep capabilities but
|
||||
* drop privileges we need to make sure we keep our
|
||||
* caps, while we drop privileges. */
|
||||
if (uid != 0) {
|
||||
int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
|
||||
|
||||
if (prctl(PR_GET_SECUREBITS) != sb)
|
||||
if (prctl(PR_SET_SECUREBITS, sb) < 0)
|
||||
return -errno;
|
||||
/* Add KEEP_CAPS to the securebits */
|
||||
r = set_securebits(1<<SECURE_KEEP_CAPS, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4337,12 +4353,27 @@ static int exec_child(
|
|||
#endif
|
||||
|
||||
/* PR_GET_SECUREBITS is not privileged, while PR_SET_SECUREBITS is. So to suppress potential EPERMs
|
||||
* we'll try not to call PR_SET_SECUREBITS unless necessary. */
|
||||
if (prctl(PR_GET_SECUREBITS) != secure_bits)
|
||||
* we'll try not to call PR_SET_SECUREBITS unless necessary. Setting securebits requires
|
||||
* CAP_SETPCAP. */
|
||||
if (prctl(PR_GET_SECUREBITS) != secure_bits) {
|
||||
/* CAP_SETPCAP is required to set securebits. This capabilitiy is raised into the
|
||||
* effective set here.
|
||||
* The effective set is overwritten during execve with the following values:
|
||||
* - ambient set (for non-root processes)
|
||||
* - (inheritable | bounding) set for root processes)
|
||||
*
|
||||
* Hence there is no security impact to raise it in the effective set before execve
|
||||
*/
|
||||
r = capability_gain_cap_setpcap(NULL);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CAPABILITIES;
|
||||
return log_unit_error_errno(unit, r, "Failed to gain CAP_SETPCAP for setting secure bits");
|
||||
}
|
||||
if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
|
||||
*exit_status = EXIT_SECUREBITS;
|
||||
return log_unit_error_errno(unit, errno, "Failed to set process secure bits: %m");
|
||||
}
|
||||
}
|
||||
|
||||
if (context_has_no_new_privileges(context))
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
|
||||
|
|
Loading…
Reference in New Issue