Blame SOURCES/0011-Drop-unnecessary-capabilities.patch

df4638
From 3b37f4b7bb3a17f8bd655be919915a1912062ea6 Mon Sep 17 00:00:00 2001
df4638
From: Pavel Zhukov <pzhukov@redhat.com>
df4638
Date: Thu, 21 Feb 2019 10:30:28 +0100
df4638
Subject: [PATCH 11/26] Drop unnecessary capabilities
df4638
Cc: pzhukov@redhat.com
df4638
df4638
dhclient (#517649, #546765), dhcpd/dhcrelay (#699713)
df4638
---
df4638
 client/Makefile.am       |  3 ++-
df4638
 client/dhclient-script.8 | 10 ++++++++++
df4638
 client/dhclient.8        | 29 +++++++++++++++++++++++++++++
df4638
 client/dhclient.c        | 24 ++++++++++++++++++++++++
df4638
 configure.ac             | 35 +++++++++++++++++++++++++++++++++++
df4638
 relay/Makefile.am        |  3 ++-
df4638
 relay/dhcrelay.c         | 29 +++++++++++++++++++++++++++++
df4638
 7 files changed, 131 insertions(+), 2 deletions(-)
df4638
df4638
diff --git a/client/Makefile.am b/client/Makefile.am
df4638
index d177159..0689185 100644
df4638
--- a/client/Makefile.am
df4638
+++ b/client/Makefile.am
df4638
@@ -17,6 +17,7 @@ dhclient_LDADD = ../common/libdhcp.@A@ ../omapip/libomapi.@A@ \
df4638
 		 @BINDLIBIRSDIR@/libirs.@A@ \
df4638
 		 @BINDLIBDNSDIR@/libdns.@A@ \
df4638
 		 @BINDLIBISCCFGDIR@/libisccfg.@A@ \
df4638
-		 @BINDLIBISCDIR@/libisc.@A@
df4638
+		 @BINDLIBISCDIR@/libisc.@A@ \
df4638
+		 $(CAPNG_LDADD)
df4638
 man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
df4638
 EXTRA_DIST = $(man_MANS)
df4638
diff --git a/client/dhclient-script.8 b/client/dhclient-script.8
df4638
index 0db5516..2eddb8f 100644
df4638
--- a/client/dhclient-script.8
df4638
+++ b/client/dhclient-script.8
df4638
@@ -243,6 +243,16 @@ repeatedly initialized to the values provided by one server, and then
df4638
 the other.   Assuming the information provided by both servers is
df4638
 valid, this shouldn't cause any real problems, but it could be
df4638
 confusing.
df4638
+.PP
df4638
+Normally, if dhclient was compiled with libcap-ng support,
df4638
+dhclient drops most capabilities immediately upon startup.
df4638
+While more secure, this greatly restricts the additional actions that
df4638
+hooks in dhclient-script can take. For example, any daemons that
df4638
+dhclient-script starts or restarts will inherit the restricted
df4638
+capabilities as well, which may interfere with their correct operation.
df4638
+Thus, the
df4638
+.BI \-nc
df4638
+option can be used to prevent dhclient from dropping capabilities.
df4638
 .SH SEE ALSO
df4638
 dhclient(8), dhcpd(8), dhcrelay(8), dhclient.conf(5) and
df4638
 dhclient.leases(5).
df4638
diff --git a/client/dhclient.8 b/client/dhclient.8
df4638
index 6d7fbdb..0145b9f 100644
df4638
--- a/client/dhclient.8
df4638
+++ b/client/dhclient.8
df4638
@@ -134,6 +134,9 @@ dhclient - Dynamic Host Configuration Protocol Client
df4638
 .B -w
df4638
 ]
df4638
 [
df4638
+.B -nc
df4638
+]
df4638
+[
df4638
 .B -B
df4638
 ]
df4638
 [
df4638
@@ -328,6 +331,32 @@ not to exit when it doesn't find any such interfaces.  The
df4638
 program can then be used to notify the client when a network interface
df4638
 has been added or removed, so that the client can attempt to configure an IP
df4638
 address on that interface.
df4638
+.TP
df4638
+.BI \-nc
df4638
+Do not drop capabilities.
df4638
+
df4638
+Normally, if
df4638
+.B dhclient
df4638
+was compiled with libcap-ng support,
df4638
+.B dhclient
df4638
+drops most capabilities immediately upon startup.  While more secure,
df4638
+this greatly restricts the additional actions that hooks in
df4638
+.B dhclient-script (8)
df4638
+can take.  (For example, any daemons that 
df4638
+.B dhclient-script (8)
df4638
+starts or restarts will inherit the restricted capabilities as well,
df4638
+which may interfere with their correct operation.)  Thus, the
df4638
+.BI \-nc
df4638
+option can be used to prevent
df4638
+.B dhclient
df4638
+from dropping capabilities.
df4638
+
df4638
+The
df4638
+.BI \-nc
df4638
+option is ignored if
df4638
+.B dhclient
df4638
+was not compiled with libcap-ng support.
df4638
+
df4638
 .TP
df4638
 .BI \-n
df4638
 Do not configure any interfaces.  This is most likely to be useful in
df4638
diff --git a/client/dhclient.c b/client/dhclient.c
df4638
index a86ab9e..5d3f5bc 100644
df4638
--- a/client/dhclient.c
df4638
+++ b/client/dhclient.c
df4638
@@ -41,6 +41,10 @@
df4638
 #include <sys/wait.h>
df4638
 #include <limits.h>
df4638
 
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+#include <cap-ng.h>
df4638
+#endif
df4638
+
df4638
 /*
df4638
  * Defined in stdio.h when _GNU_SOURCE is set, but we don't want to define
df4638
  * that when building ISC code.
df4638
@@ -266,6 +270,9 @@ main(int argc, char **argv) {
df4638
 	int timeout_arg = 0;
df4638
 	char *arg_conf = NULL;
df4638
 	int arg_conf_len = 0;
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+	int keep_capabilities = 0;
df4638
+#endif
df4638
 
df4638
 	/* Initialize client globals. */
df4638
 	memset(&default_duid, 0, sizeof(default_duid));
df4638
@@ -665,6 +672,10 @@ main(int argc, char **argv) {
df4638
 
df4638
 			dhclient_request_options = argv[i];
df4638
 
df4638
+		} else if (!strcmp(argv[i], "-nc")) {
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+                  keep_capabilities = 1;
df4638
+#endif
df4638
 		} else if (argv[i][0] == '-') {
df4638
 			usage("Unknown command: %s", argv[i]);
df4638
 		} else if (interfaces_requested < 0) {
df4638
@@ -725,6 +736,19 @@ main(int argc, char **argv) {
df4638
 		path_dhclient_script = s;
df4638
 	}
df4638
 
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+	/* Drop capabilities */
df4638
+	if (!keep_capabilities) {
df4638
+		capng_clear(CAPNG_SELECT_CAPS);
df4638
+		capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
df4638
+				CAP_DAC_OVERRIDE); // Drop this someday
df4638
+		capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
df4638
+				CAP_NET_ADMIN, CAP_NET_RAW,
df4638
+				CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, -1);
df4638
+		capng_apply(CAPNG_SELECT_CAPS);
df4638
+	}
df4638
+#endif
df4638
+
df4638
 	/* Set up the initial dhcp option universe. */
df4638
 	initialize_common_option_spaces();
df4638
 
df4638
diff --git a/configure.ac b/configure.ac
df4638
index a797438..15fc0d7 100644
df4638
--- a/configure.ac
df4638
+++ b/configure.ac
df4638
@@ -612,6 +612,41 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[void foo() __attribute__((noreturn));
df4638
 # Look for optional headers.
df4638
 AC_CHECK_HEADERS(sys/socket.h net/if_dl.h net/if6.h regex.h)
df4638
 
df4638
+# look for capabilities library
df4638
+AC_ARG_WITH(libcap-ng,
df4638
+    [  --with-libcap-ng=[auto/yes/no]  Add Libcap-ng support [default=auto]],,
df4638
+    with_libcap_ng=auto)
df4638
+
df4638
+# Check for Libcap-ng API
df4638
+#
df4638
+# libcap-ng detection
df4638
+if test x$with_libcap_ng = xno ; then
df4638
+    have_libcap_ng=no;
df4638
+else
df4638
+    # Start by checking for header file
df4638
+    AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no)
df4638
+
df4638
+    # See if we have libcap-ng library
df4638
+    AC_CHECK_LIB(cap-ng, capng_clear,
df4638
+                 CAPNG_LDADD=-lcap-ng,)
df4638
+
df4638
+    # Check results are usable
df4638
+    if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then
df4638
+       AC_MSG_ERROR(libcap-ng support was requested and the library was not found)
df4638
+    fi
df4638
+    if test x$CAPNG_LDADD != x -a $capng_headers = no ; then
df4638
+       AC_MSG_ERROR(libcap-ng libraries found but headers are missing)
df4638
+    fi
df4638
+fi
df4638
+AC_SUBST(CAPNG_LDADD)
df4638
+AC_MSG_CHECKING(whether to use libcap-ng)
df4638
+if test x$CAPNG_LDADD != x ; then
df4638
+    AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support])
df4638
+    AC_MSG_RESULT(yes)
df4638
+else
df4638
+    AC_MSG_RESULT(no)
df4638
+fi
df4638
+
df4638
 # Solaris needs some libraries for functions
df4638
 AC_SEARCH_LIBS(socket, [socket])
df4638
 AC_SEARCH_LIBS(inet_ntoa, [nsl])
df4638
diff --git a/relay/Makefile.am b/relay/Makefile.am
df4638
index 2ba5979..8900e0b 100644
df4638
--- a/relay/Makefile.am
df4638
+++ b/relay/Makefile.am
df4638
@@ -6,7 +6,8 @@ dhcrelay_LDADD = ../common/libdhcp.@A@ ../omapip/libomapi.@A@ \
df4638
 		 @BINDLIBIRSDIR@/libirs.@A@ \
df4638
 		 @BINDLIBDNSDIR@/libdns.@A@ \
df4638
 		 @BINDLIBISCCFGDIR@/libisccfg.@A@ \
df4638
-		 @BINDLIBISCDIR@/libisc.@A@
df4638
+		 @BINDLIBISCDIR@/libisc.@A@ \
df4638
+		 $(CAPNG_LDADD)
df4638
 man_MANS = dhcrelay.8
df4638
 EXTRA_DIST = $(man_MANS)
df4638
 
df4638
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
df4638
index ea1be18..7b4f4f1 100644
df4638
--- a/relay/dhcrelay.c
df4638
+++ b/relay/dhcrelay.c
df4638
@@ -32,6 +32,11 @@
df4638
 #include <sys/time.h>
df4638
 #include <isc/file.h>
df4638
 
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+#  include <cap-ng.h>
df4638
+   int keep_capabilities = 0;
df4638
+#endif
df4638
+
df4638
 TIME default_lease_time = 43200; /* 12 hours... */
df4638
 TIME max_lease_time = 86400; /* 24 hours... */
df4638
 struct tree_cache *global_options[256];
df4638
@@ -590,6 +595,10 @@ main(int argc, char **argv) {
df4638
 			if (++i == argc)
df4638
 				usage(use_noarg, argv[i-1]);
df4638
 			dhcrelay_sub_id = argv[i];
df4638
+#endif
df4638
+		} else if (!strcmp(argv[i], "-nc")) {
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+			keep_capabilities = 1;
df4638
 #endif
df4638
 		} else if (!strcmp(argv[i], "-pf")) {
df4638
 			if (++i == argc)
df4638
@@ -660,6 +669,17 @@ main(int argc, char **argv) {
df4638
 #endif
df4638
 	}
df4638
 
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+	/* Drop capabilities */
df4638
+	if (!keep_capabilities) {
df4638
+		capng_clear(CAPNG_SELECT_BOTH);
df4638
+		capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
df4638
+				CAP_NET_RAW, CAP_NET_BIND_SERVICE, -1);
df4638
+		capng_apply(CAPNG_SELECT_BOTH);
df4638
+		log_info ("Dropped all unnecessary capabilities.");
df4638
+	}
df4638
+#endif
df4638
+
df4638
 	if (!quiet) {
df4638
 		log_info("%s %s", message, PACKAGE_VERSION);
df4638
 		log_info(copyright);
df4638
@@ -816,6 +836,15 @@ main(int argc, char **argv) {
df4638
 	signal(SIGTERM, dhcp_signal_handler);  /* kill */
df4638
 #endif
df4638
 
df4638
+#ifdef HAVE_LIBCAP_NG
df4638
+	/* Drop all capabilities */
df4638
+	if (!keep_capabilities) {
df4638
+		capng_clear(CAPNG_SELECT_BOTH);
df4638
+		capng_apply(CAPNG_SELECT_BOTH);
df4638
+		log_info ("Dropped all capabilities.");
df4638
+	}
df4638
+#endif
df4638
+
df4638
 	/* Start dispatching packets and timeouts... */
df4638
 	dispatch();
df4638
 
df4638
-- 
df4638
2.14.5
df4638