[PATCH v2 5/9] setpriv: dump inheritable capability set

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


The setpriv executable from util-linux also dumps out information on the
different capability sets known by the kernel. By default, these are the
inheritable capabilities, bounding capabilities and (not yet released)
the ambient capabilities, which have been introduced with Linux 4.3.
This patch introduces the ability to dump the set of inheritable
capabilities.
---
 util-linux/setpriv.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 150 insertions(+), 2 deletions(-)

diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index 740b51610..d5fcde73d 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -23,6 +23,26 @@
 //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))
 
@@ -55,6 +75,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"
@@ -75,13 +99,113 @@ enum {
 	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",
+	"dac_read_search",
+	"fowner",
+	"fsetid",
+	"kill",
+	"setgid",
+	"setuid",
+	"setpcap",
+	"linux_immutable",
+	"net_bind_service",
+	"net_broadcast",
+	"net_admin",
+	"net_raw",
+	"ipc_lock",
+	"ipc_owner",
+	"sys_module",
+	"sys_rawio",
+	"sys_chroot",
+	"sys_ptrace",
+	"sys_pacct",
+	"sys_admin",
+	"sys_boot",
+	"sys_nice",
+	"sys_resource",
+	"sys_time",
+	"sys_tty_config",
+	"mknod",
+	"lease",
+	"audit_write",
+	"audit_control",
+	"setfcap",
+	"mac_override",
+	"mac_admin",
+	"syslog",
+	"wake_alarm",
+	"block_suspend",
+	"audit_read",
+};
+#endif /* FEATURE_SETPRIV_CAPABILITY_NAMES */
+
+static void initcaps(void)
+{
+	cap_header = xmalloc(sizeof(*cap_header));
+
+	cap_header->pid = 0;
+	cap_header->version = _LINUX_CAPABILITY_VERSION;
+
+	if ((capget(cap_header, NULL)) < 0)
+		bb_simple_perror_msg_and_die("capget");
+
+	switch (cap_header->version) {
+		case _LINUX_CAPABILITY_VERSION_1:
+			cap_u32s = _LINUX_CAPABILITY_U32S_1;
+			break;
+		case _LINUX_CAPABILITY_VERSION_2:
+			cap_u32s = _LINUX_CAPABILITY_U32S_2;
+			break;
+		case _LINUX_CAPABILITY_VERSION_3:
+			cap_u32s = _LINUX_CAPABILITY_U32S_3;
+			break;
+		default:
+			bb_error_msg_and_die("unsupported capability version");
+	}
+}
+#endif /* FEATURE_SETPRIV_CAPABILITIES */
+
 #if ENABLE_FEATURE_SETPRIV_DUMP
+#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
+static cap_user_data_t getcaps(void)
+{
+	cap_user_data_t result;
+
+	result = xmalloc(sizeof(*result) * cap_u32s);
+	if (capget(cap_header, result) < 0)
+		bb_simple_perror_msg_and_die("capget");
+
+	return result;
+}
+
+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 ngids, nnp;
+	int i, ngids, nnp;
 
 	if (getresuid(&ruid, &euid, &suid) < 0)
 		bb_simple_perror_msg_and_die("getresgid");
@@ -98,6 +222,10 @@ 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);
 	printf("gid: %d\n", rgid);
@@ -107,7 +235,6 @@ static int dump(void)
 	if (ngids == 0) {
 		printf("[none]");
 	} else {
-		int i;
 		for (i = 0; i < ngids; i++) {
 			if (i)
 				putchar(',');
@@ -118,6 +245,23 @@ 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)) {
+			if (n)
+				putchar(',');
+			printcap(i);
+			n++;
+		}
+	}
+	if (!n)
+		printf("[none]");
+	putchar('\n');
+
+	free(caps);
+#endif
+
 	free(gids);
 	return 0;
 }
@@ -140,6 +284,10 @@ int setpriv_main(int argc UNUSED_PARAM, char **argv)
 	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)
-- 
2.13.2



More information about the busybox mailing list