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