[PATCH 9/9] setpriv: allow modifying ambient capabilities

Patrick Steinhardt ps at pks.im
Thu Jun 29 17:34:36 UTC 2017


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.
---
 util-linux/setpriv.c | 46 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 39 insertions(+), 7 deletions(-)

diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index c072b0ef0..6ca5db799 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -24,13 +24,15 @@
 //usage:	"[OPTIONS] PROG [ARGS]"
 //usage:#define setpriv_full_usage "\n\n"
 //usage:       "Run PROG with different privilege settings\n"
-//usage:     "\n-d,--dump		Show current capabilities"
-//usage:     "\n--nnp,--no-new-privs	Ignore setuid/setgid bits and file capabilities"
-//usage:     "\n--inh-caps <caps,...>	Set inheritable capabilities"
+//usage:     "\n-d,--dump			Show current capabilities"
+//usage:     "\n--nnp,--no-new-privs		Ignore setuid/setgid bits and file capabilities"
+//usage:     "\n--inh-caps <caps,...>		Set inheritable capabilities"
+//usage:     "\n--ambient-caps <caps,...>	Set ambient capabilities"
 
-//setpriv from util-linux 2.28:
+//setpriv from util-linux e5c9736d214eeffd4a0dcaf1f78f64a6366bc8e7:
 // -d, --dump               show current state (and do not exec anything)
 // --nnp, --no-new-privs    disallow granting new privileges
+// --ambient-caps <caps,...> set ambient capabilities
 // --inh-caps <caps,...>    set inheritable capabilities
 // --bounding-set <caps>    set capability bounding set
 // --ruid <uid>             set real uid
@@ -67,6 +69,8 @@
 #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
 
 static cap_user_header_t cap_header;
@@ -75,7 +79,8 @@ static int cap_u32s;
 enum {
 	OPT_DUMP = (1 << 0),
 	OPT_INH  = (1 << 1),
-	OPT_NNP  = (1 << 2),
+	OPT_AMB  = (1 << 2),
+	OPT_NNP  = (1 << 3),
 };
 
 static const char *capabilities[] = {
@@ -323,6 +328,29 @@ static void set_inh_caps(char *capstring)
 	free(caps);
 }
 
+static void set_ambient_caps(char *string)
+{
+	char *cap;
+
+	cap = strtok(string, ",");
+	while (cap) {
+		unsigned long index;
+		int add;
+
+		parse_cap(&index, &add, cap);
+
+		if (add) {
+			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, ",");
+	}
+}
+
 int setpriv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int setpriv_main(int argc UNUSED_PARAM, char **argv)
 {
@@ -331,13 +359,14 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv)
 		"nnp\0"          No_argument		"\xff"
 		"no-new-privs\0" No_argument		"\xff"
 		"inh-caps\0"     Required_argument	"\xfe"
+		"ambient-caps\0" Required_argument	"\xfd"
 		;
-	char *inh_caps;
+	char *inh_caps, *ambient_caps;
 	int opts;
 
 	opt_complementary = "";
 	applet_long_options = setpriv_longopts;
-	opts = getopt32(argv, "+d\xfe:", &inh_caps);
+	opts = getopt32(argv, "+d\xfe:\xfd:", &inh_caps, &ambient_caps);
 
 	argc -= optind;
 	argv += optind;
@@ -362,5 +391,8 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv)
 	if (opts & OPT_INH)
 		set_inh_caps(inh_caps);
 
+	if (opts & OPT_AMB)
+		set_ambient_caps(ambient_caps);
+
 	BB_EXECVP_or_die(argv);
 }
-- 
2.13.2



More information about the busybox mailing list