From 6842d00cebef368a4ade9c9cd3dc92804b84c88d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 7 Jul 2017 02:14:23 +0200 Subject: [PATCH] setpriv: allow modifying ambient capabilities With Linux 4.3, a new set of capabilities has been introduced with the ambient capabilities. These aim to solve the problem that it was impossible to grant run programs with elevated privileges across non-root users. Quoting from capabilities(7): This is a set of capabilities that are preserved across an execve(2) of a program that is not privileged. The ambient capability set obeys the invariant that no capability can ever be ambient if it is not both permitted and inheritable. With this new set of capabilities it is now possible to run an executable with elevated privileges as a different user, making it much easier to do proper privilege separation. Note though that the `--ambient-caps` switch is not part of any released version of util-linux, yet. It has been applied in 0c92194ee (setpriv: support modifying the set of ambient capabilities, 2017-06-24) and will probably be part of v2.31. function old new delta parse_cap - 174 +174 setpriv_main 1246 1301 +55 .rodata 146307 146347 +40 static.setpriv_longopts 40 55 +15 packed_usage 32092 32079 -13 Signed-off-by: Patrick Steinhardt Signed-off-by: Denys Vlasenko --- util-linux/setpriv.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c index a1fa889e7..8d9c218a3 100644 --- a/util-linux/setpriv.c +++ b/util-linux/setpriv.c @@ -57,7 +57,8 @@ //usage: ) //usage: "\n--nnp,--no-new-privs Ignore setuid/setgid bits and file capabilities" //usage: IF_FEATURE_SETPRIV_CAPABILITIES( -//usage: "\n--inh-caps CAP[,CAP...] Set inheritable capabilities" +//usage: "\n--inh-caps CAP,CAP Set inheritable capabilities" +//usage: "\n--ambient-caps CAP,CAP Set ambient capabilities" //usage: ) //setpriv from util-linux 2.28: @@ -100,15 +101,19 @@ #ifndef PR_CAP_AMBIENT #define PR_CAP_AMBIENT 47 #define PR_CAP_AMBIENT_IS_SET 1 +#define PR_CAP_AMBIENT_RAISE 2 +#define PR_CAP_AMBIENT_LOWER 3 #endif enum { IF_FEATURE_SETPRIV_DUMP(OPTBIT_DUMP,) IF_FEATURE_SETPRIV_CAPABILITIES(OPTBIT_INH,) + IF_FEATURE_SETPRIV_CAPABILITIES(OPTBIT_AMB,) OPTBIT_NNP, IF_FEATURE_SETPRIV_DUMP(OPT_DUMP = (1 << OPTBIT_DUMP),) IF_FEATURE_SETPRIV_CAPABILITIES(OPT_INH = (1 << OPTBIT_INH),) + IF_FEATURE_SETPRIV_CAPABILITIES(OPT_AMB = (1 << OPTBIT_AMB),) OPT_NNP = (1 << OPTBIT_NNP), }; @@ -313,16 +318,14 @@ static int dump(void) #endif /* FEATURE_SETPRIV_DUMP */ #if ENABLE_FEATURE_SETPRIV_CAPABILITIES -static void parse_cap(unsigned long *index, int *add, const char *cap) +static void parse_cap(unsigned long *index, const char *cap) { unsigned long i; switch (cap[0]) { case '-': - *add = 0; break; case '+': - *add = 1; break; default: bb_error_msg_and_die("invalid capability '%s'", cap); @@ -361,12 +364,12 @@ static void set_inh_caps(char *capstring) capstring = strtok(capstring, ","); while (capstring) { unsigned long cap; - int add; - parse_cap(&cap, &add, capstring); + parse_cap(&cap, capstring); if (CAP_TO_INDEX(cap) >= caps.u32s) bb_error_msg_and_die("invalid capability cap"); - if (add) + + if (capstring[0] == '+') caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap); else caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap); @@ -379,6 +382,26 @@ static void set_inh_caps(char *capstring) if (ENABLE_FEATURE_CLEAN_UP) free(caps.data); } + +static void set_ambient_caps(char *string) +{ + char *cap; + + cap = strtok(string, ","); + while (cap) { + unsigned long index; + + parse_cap(&index, cap); + if (cap[0] == '+') { + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, index, 0, 0) < 0) + bb_perror_msg("cap_ambient_raise"); + } else { + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, index, 0, 0) < 0) + bb_perror_msg("cap_ambient_lower"); + } + cap = strtok(NULL, ","); + } +} #endif /* FEATURE_SETPRIV_CAPABILITIES */ int setpriv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -392,14 +415,15 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv) "no-new-privs\0" No_argument "\xff" IF_FEATURE_SETPRIV_CAPABILITIES( "inh-caps\0" Required_argument "\xfe" + "ambient-caps\0" Required_argument "\xfd" ) ; int opts; - IF_FEATURE_SETPRIV_CAPABILITIES(char *inh_caps;) + IF_FEATURE_SETPRIV_CAPABILITIES(char *inh_caps, *ambient_caps;) applet_long_options = setpriv_longopts; opts = getopt32(argv, "+"IF_FEATURE_SETPRIV_DUMP("d") - IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:", &inh_caps)); + IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:\xfd:", &inh_caps, &ambient_caps)); argv += optind; #if ENABLE_FEATURE_SETPRIV_DUMP @@ -417,6 +441,8 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_SETPRIV_CAPABILITIES if (opts & OPT_INH) set_inh_caps(inh_caps); + if (opts & OPT_AMB) + set_ambient_caps(ambient_caps); #endif if (!argv[0]) -- 2.25.1