unshare: Move implementation of --keep-caps option to library function
unshare.c open codes some logic to copy the permitted capability set to the ambient set in order to implement the --keep-caps option. Move this logic to lib/caputils.c so that we can reuse it in nsenter. Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
53d2257daf
commit
acb72212eb
3 changed files with 42 additions and 36 deletions
|
@ -31,4 +31,6 @@ extern int capget(cap_user_header_t header, const cap_user_data_t data);
|
|||
|
||||
extern int cap_last_cap(void);
|
||||
|
||||
extern void cap_permitted_to_ambient(void);
|
||||
|
||||
#endif /* CAPUTILS_H */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "caputils.h"
|
||||
#include "pathnames.h"
|
||||
#include "procfs.h"
|
||||
#include "nls.h"
|
||||
|
||||
static int test_cap(unsigned int cap)
|
||||
{
|
||||
|
@ -87,6 +88,43 @@ int cap_last_cap(void)
|
|||
return cap;
|
||||
}
|
||||
|
||||
void cap_permitted_to_ambient(void)
|
||||
{
|
||||
/* We use capabilities system calls to propagate the permitted
|
||||
* capabilities into the ambient set because we may have
|
||||
* already forked so be in async-signal-safe context. */
|
||||
struct __user_cap_header_struct header = {
|
||||
.version = _LINUX_CAPABILITY_VERSION_3,
|
||||
.pid = 0,
|
||||
};
|
||||
struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = {{ 0 }};
|
||||
uint64_t effective, cap;
|
||||
|
||||
if (capget(&header, payload) < 0)
|
||||
err(EXIT_FAILURE, _("capget failed"));
|
||||
|
||||
/* In order the make capabilities ambient, we first need to ensure
|
||||
* that they are all inheritable. */
|
||||
payload[0].inheritable = payload[0].permitted;
|
||||
payload[1].inheritable = payload[1].permitted;
|
||||
|
||||
if (capset(&header, payload) < 0)
|
||||
err(EXIT_FAILURE, _("capset failed"));
|
||||
|
||||
effective = ((uint64_t)payload[1].effective << 32) | (uint64_t)payload[0].effective;
|
||||
|
||||
for (cap = 0; cap < (sizeof(effective) * 8); cap++) {
|
||||
/* This is the same check as cap_valid(), but using
|
||||
* the runtime value for the last valid cap. */
|
||||
if (cap > (uint64_t) cap_last_cap())
|
||||
continue;
|
||||
|
||||
if ((effective & (1 << cap))
|
||||
&& prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0)
|
||||
err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed"));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM_CAPUTILS
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
|
|
@ -1089,42 +1089,8 @@ int main(int argc, char *argv[])
|
|||
if (force_uid && setuid(uid) < 0) /* change UID */
|
||||
err(EXIT_FAILURE, _("setuid failed"));
|
||||
|
||||
/* We use capabilities system calls to propagate the permitted
|
||||
* capabilities into the ambient set because we have already
|
||||
* forked so are in async-signal-safe context. */
|
||||
if (keepcaps && (unshare_flags & CLONE_NEWUSER)) {
|
||||
struct __user_cap_header_struct header = {
|
||||
.version = _LINUX_CAPABILITY_VERSION_3,
|
||||
.pid = 0,
|
||||
};
|
||||
|
||||
struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = {{ 0 }};
|
||||
uint64_t effective, cap;
|
||||
|
||||
if (capget(&header, payload) < 0)
|
||||
err(EXIT_FAILURE, _("capget failed"));
|
||||
|
||||
/* In order the make capabilities ambient, we first need to ensure
|
||||
* that they are all inheritable. */
|
||||
payload[0].inheritable = payload[0].permitted;
|
||||
payload[1].inheritable = payload[1].permitted;
|
||||
|
||||
if (capset(&header, payload) < 0)
|
||||
err(EXIT_FAILURE, _("capset failed"));
|
||||
|
||||
effective = ((uint64_t)payload[1].effective << 32) | (uint64_t)payload[0].effective;
|
||||
|
||||
for (cap = 0; cap < (sizeof(effective) * 8); cap++) {
|
||||
/* This is the same check as cap_valid(), but using
|
||||
* the runtime value for the last valid cap. */
|
||||
if (cap > (uint64_t) cap_last_cap())
|
||||
continue;
|
||||
|
||||
if ((effective & (1 << cap))
|
||||
&& prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0)
|
||||
err(EXIT_FAILURE, _("prctl(PR_CAP_AMBIENT) failed"));
|
||||
}
|
||||
}
|
||||
if (keepcaps && (unshare_flags & CLONE_NEWUSER))
|
||||
cap_permitted_to_ambient();
|
||||
|
||||
if (optind < argc) {
|
||||
execvp(argv[optind], argv + optind);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue