[PATCH v2 0/9] setpriv: dumping and modification of capabilities

Patrick Steinhardt ps at pks.im
Sun Jul 2 13:42:49 UTC 2017


Hi,

this is version 2 of my patch series to implement dumping and
modification of privilege state for capabilities in setpriv(1).
The previous version can be found at [1].

I've now split the code into different features that can be
enabled or disabled at build-time, as suggested by Assaf. There
are currently three features which I guess should
be sufficient for most use cases:

- FEATURE_SETPRIV_DUMP: enables or disables the
  dumping-functionality to print the current environment's
  privilege state.
- FEATURE_SETPRIV_CAPABILITIES: enables or disables handling
  capabilities. This includes the ability to dump
  capabilities as well as the "--inh-caps" and
  "--ambient-caps" switches.
- FEATURE_SETPRIV_CAPABILITY_NAMES: enables or disables
  parsing and dumping capability by their long names (e.g.
  "net_bind_service" instead of "cap_10").

I've attached the interdiff below.

Regards
Patrick

[1]: http://lists.busybox.net/pipermail/busybox/2017-June/085527.html

Patrick Steinhardt (9):
  setpriv: do not process remaining args
  setpriv: prepare option parsing logic for additional opts
  setpriv: dump user and group info
  setpriv: dump no-new-privs info
  setpriv: dump inheritable capability set
  setpriv: dump capability bounding set
  setpriv: dump ambient capabilities
  setpriv: allow modifying inheritable caps
  setpriv: allow modifying ambient capabilities

 util-linux/setpriv.c | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 421 insertions(+), 8 deletions(-)

-- 
2.13.2

diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index 6ca5db799..7b85af961 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -15,6 +15,34 @@
 //config:	help
 //config:	  Run a program with different Linux privilege settings.
 //config:	  Requires kernel >= 3.5
+//config:
+//config:config FEATURE_SETPRIV_DUMP
+//config:	bool "Support dumping current privilege state"
+//config:	default y
+//config:	depends on SETPRIV
+//config:	help
+//config:		Enables the "--dump" switch to print out the current privilege
+//config:		state. This is helpful for diagnosing problems.
+//config:
+//config:config FEATURE_SETPRIV_CAPABILITIES
+//config:	bool "Support capabilities"
+//config:	default y
+//config:	depends on SETPRIV
+//config:	help
+//config:		Capabilities can be used to grant processes additional rights
+//config:		without the necessity to always execute as the root user.
+//config:		Enabling this option enables "--dump" to show information on
+//config:		capabilities.
+//config:
+//config:config FEATURE_SETPRIV_CAPABILITY_NAMES
+//config:	bool "Support capability names"
+//config:	default y
+//config:	depends on SETPRIV && FEATURE_SETPRIV_CAPABILITIES
+//config:	help
+//config:		Capabilities can be either referenced via a human-readble name,
+//config:		e.g. "net_admin", or using their index, e.g. "cap_12". Enabling
+//config:		this option allows using the human-readable names in addition to
+//config:		the index-based names.
 
 //applet:IF_SETPRIV(APPLET(setpriv, BB_DIR_BIN, BB_SUID_DROP))
 
@@ -24,10 +52,16 @@
 //usage:	"[OPTIONS] PROG [ARGS]"
 //usage:#define setpriv_full_usage "\n\n"
 //usage:       "Run PROG with different privilege settings\n"
+//usage:	IF_FEATURE_SETPRIV_DUMP(
 //usage:     "\n-d,--dump			Show current capabilities"
+//usage:	)
 //usage:     "\n--nnp,--no-new-privs		Ignore setuid/setgid bits and file capabilities"
+//usage:	IF_FEATURE_SETPRIV_CAPABILITIES(
 //usage:     "\n--inh-caps <caps,...>		Set inheritable capabilities"
+//usage:	)
+//usage:	IF_FEATURE_SETPRIV_CAPABILITIES(
 //usage:     "\n--ambient-caps <caps,...>	Set ambient capabilities"
+//usage:	)
 
 //setpriv from util-linux e5c9736d214eeffd4a0dcaf1f78f64a6366bc8e7:
 // -d, --dump               show current state (and do not exec anything)
@@ -48,8 +82,10 @@
 // --selinux-label <label>  set SELinux label
 // --apparmor-profile <pr>  set AppArmor profile
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 #include <linux/capability.h>
 #include <sys/capability.h>
+#endif
 #include <sys/prctl.h>
 #include <unistd.h>
 #include "libbb.h"
@@ -73,16 +109,28 @@
 #define PR_CAP_AMBIENT_LOWER 3
 #endif
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 static cap_user_header_t cap_header;
 static int cap_u32s;
+#endif
 
 enum {
-	OPT_DUMP = (1 << 0),
-	OPT_INH  = (1 << 1),
-	OPT_AMB  = (1 << 2),
-	OPT_NNP  = (1 << 3),
+	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),
 };
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
+static cap_user_header_t cap_header;
+static int cap_u32s;
+
+#if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
 static const char *capabilities[] = {
 	"chown",
 	"dac_override",
@@ -123,6 +171,7 @@ static const char *capabilities[] = {
 	"block_suspend",
 	"audit_read",
 };
+#endif /* FEATURE_SETPRIV_CAPABILITY_NAMES */
 
 static void initcaps(void)
 {
@@ -148,7 +197,9 @@ static void initcaps(void)
 			bb_error_msg_and_die("unsupported capability version");
 	}
 }
+#endif /* FEATURE_SETPRIV_CAPABILITIES */
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 static cap_user_data_t getcaps(void)
 {
 	cap_user_data_t result;
@@ -159,22 +210,31 @@ static cap_user_data_t getcaps(void)
 
 	return result;
 }
+#endif
 
+#if ENABLE_FEATURE_SETPRIV_DUMP
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 static void printcap(unsigned long cap)
 {
+#if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
 	if (cap < ARRAY_SIZE(capabilities))
 		printf(capabilities[cap]);
 	else
+#endif
 		printf("cap_%lu", cap);
 }
+#endif /* FEATURE_SETPRIV_CAPABILITIES */
 
 static int dump(void)
 {
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 	cap_user_data_t caps;
+	int n;
+#endif
 	uid_t ruid, euid, suid;
 	gid_t rgid, egid, sgid;
 	gid_t *gids;
-	int i, n, ngids, nnp;
+	int i, ngids, nnp;
 
 	if (getresuid(&ruid, &euid, &suid) < 0)
 		bb_simple_perror_msg_and_die("getresgid");
@@ -191,7 +251,9 @@ static int dump(void)
 	if ((nnp = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)) < 0)
 		bb_simple_perror_msg_and_die("prctl: GET_NO_NEW_PRIVS");
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 	caps = getcaps();
+#endif
 
 	printf("uid: %d\n", ruid);
 	printf("euid: %d\n", euid);
@@ -212,6 +274,7 @@ static int dump(void)
 
 	printf("no_new_privs: %d\n", nnp);
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 	printf("Inheritable capabilities: ");
 	for (n = 0, i = 0; cap_valid(i); i++) {
 		if (caps->inheritable & CAP_TO_MASK(i)) {
@@ -261,11 +324,15 @@ static int dump(void)
 		printf("[none]");
 	putchar('\n');
 
+	free(caps);
+#endif
+
 	free(gids);
-	free(caps);
 	return 0;
 }
+#endif /* FEATURE_SETPRIV_DUMP */
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 static void parse_cap(unsigned long *index, int *add, const char *cap)
 {
 	unsigned long i;
@@ -284,6 +351,15 @@ static void parse_cap(unsigned long *index, int *add, const char *cap)
 
 	cap++;
 
+	if ((sscanf(cap, "cap_%lu", &i)) == 1) {
+		if (!cap_valid(i))
+			bb_error_msg_and_die("unsupported capability 'cap_%lu'", i);
+
+		*index = i;
+		return;
+	}
+
+#if ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
 	for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
 		if (strcmp(capabilities[i], cap))
 			continue;
@@ -294,6 +370,7 @@ static void parse_cap(unsigned long *index, int *add, const char *cap)
 		*index = i;
 		return;
 	}
+#endif
 
 	bb_error_msg_and_die("unknown capability '%s'", cap);
 }
@@ -350,35 +427,44 @@ static void set_ambient_caps(char *string)
 		cap = strtok(NULL, ",");
 	}
 }
+#endif /* FEATURE_SETPRIV_CAPABILITIES */
 
 int setpriv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int setpriv_main(int argc UNUSED_PARAM, char **argv)
 {
 	static const char setpriv_longopts[] ALIGN1 =
-		"dump\0"         No_argument		"d"
+		IF_FEATURE_SETPRIV_DUMP("dump\0"         No_argument	"d")
 		"nnp\0"          No_argument		"\xff"
 		"no-new-privs\0" No_argument		"\xff"
-		"inh-caps\0"     Required_argument	"\xfe"
-		"ambient-caps\0" Required_argument	"\xfd"
+		IF_FEATURE_SETPRIV_CAPABILITIES("inh-caps\0"     Required_argument	"\xfe")
+		IF_FEATURE_SETPRIV_CAPABILITIES("ambient-caps\0" Required_argument	"\xfd")
 		;
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 	char *inh_caps, *ambient_caps;
+#endif
 	int opts;
 
 	opt_complementary = "";
 	applet_long_options = setpriv_longopts;
-	opts = getopt32(argv, "+d\xfe:\xfd:", &inh_caps, &ambient_caps);
+	opts = getopt32(argv, "+"
+			IF_FEATURE_SETPRIV_DUMP("d")
+			IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:\xfd:" , &inh_caps, &ambient_caps));
 
 	argc -= optind;
 	argv += optind;
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 	initcaps();
+#endif
 
+#if ENABLE_FEATURE_SETPRIV_DUMP
 	if (opts & OPT_DUMP) {
 		if ((opts & ~OPT_DUMP) || argc)
 			bb_error_msg_and_die("setpriv: --dump is incompatible with all other options");
 
 		return dump();
 	}
+#endif
 
 	if (!argc)
 		bb_error_msg_and_die("no program specified");
@@ -388,11 +474,13 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv)
 			bb_simple_perror_msg_and_die("prctl: NO_NEW_PRIVS");
 	}
 
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
 	if (opts & OPT_INH)
 		set_inh_caps(inh_caps);
 
 	if (opts & OPT_AMB)
 		set_ambient_caps(ambient_caps);
+#endif
 
 	BB_EXECVP_or_die(argv);
 }


More information about the busybox mailing list