libmisc: retain setfcap when mapping uid 0
When uid 0 maps host uid 0 into the child userns newer kernels require CAP_SETFCAP be retained as this allows the caller to create fscaps that are valid in the ancestor userns. This was a security issue (in very rare circumstances). So whenever host uid 0 is mapped, retain CAP_SETFCAP if the caller had it. Userspace won't need to set CAP_SETFCAP on newuidmap as this is really only a scenario that real root should be doing which always has CAP_SETFCAP. And if they don't then they are in a locked-down userns. (LXC sometimes maps host uid 0 during chown operations in a helper userns but will not rely on newuidmap for that. But we don't want to risk regressing callers that want to rely on this behavior.) Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
parent
e6416fd81b
commit
91d4ab622b
@ -123,6 +123,25 @@ struct map_range *get_map_ranges(int ranges, int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
#define ULONG_DIGITS ((((sizeof(unsigned long) * CHAR_BIT) + 9)/10)*3)
|
#define ULONG_DIGITS ((((sizeof(unsigned long) * CHAR_BIT) + 9)/10)*3)
|
||||||
|
|
||||||
|
#if HAVE_SYS_CAPABILITY_H
|
||||||
|
static inline bool maps_lower_root(int cap, int ranges, struct map_range *mappings)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
struct map_range *mapping;
|
||||||
|
|
||||||
|
if (cap != CAP_SETUID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mapping = mappings;
|
||||||
|
for (idx = 0; idx < ranges; idx++, mapping++) {
|
||||||
|
if (mapping->lower == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The ruid refers to the caller's uid and is used to reset the effective uid
|
* The ruid refers to the caller's uid and is used to reset the effective uid
|
||||||
* back to the callers real uid.
|
* back to the callers real uid.
|
||||||
@ -177,6 +196,12 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
|
|||||||
/* Lockdown new{g,u}idmap by dropping all unneeded capabilities. */
|
/* Lockdown new{g,u}idmap by dropping all unneeded capabilities. */
|
||||||
memset(data, 0, sizeof(data));
|
memset(data, 0, sizeof(data));
|
||||||
data[0].effective = CAP_TO_MASK(cap);
|
data[0].effective = CAP_TO_MASK(cap);
|
||||||
|
/*
|
||||||
|
* When uid 0 from the ancestor userns is supposed to be mapped into
|
||||||
|
* the child userns we need to retain CAP_SETFCAP.
|
||||||
|
*/
|
||||||
|
if (maps_lower_root(cap, ranges, mappings))
|
||||||
|
data[0].effective |= CAP_TO_MASK(CAP_SETFCAP);
|
||||||
data[0].permitted = data[0].effective;
|
data[0].permitted = data[0].effective;
|
||||||
if (capset(&hdr, data) < 0) {
|
if (capset(&hdr, data) < 0) {
|
||||||
fprintf(stderr, _("%s: Could not set caps\n"), Prog);
|
fprintf(stderr, _("%s: Could not set caps\n"), Prog);
|
||||||
|
Loading…
Reference in New Issue
Block a user