Hi DHCP developers,

Andrew Pollock [2008-01-14 20:48 -0800]:
> This bug was received some time ago, and I forwarded it on to
> dhcp-hackers, because I wasn't aware of dhcp-bugs at the time.

Just confirming that I still think that the server derooting patch
makes sense; it is unintrusive and robust.

The client patch is more delicate, though, since it needs a suid root
wrapper to call the dhclient script. I think it might be better to
drop that and replace it with an SELinux or AppArmor policy.

FYI I attach the upstream parts of the patch (the one on
patches.ubuntu.com is for Debian and also contains the packaging
changes, and the upstream patches as diff-of-diffs). It still needs
some autoconfiscation, though.

Thanks,

Martin

-- 
Martin Pitt        http://www.piware.de
Ubuntu Developer   http://www.ubuntu.com
Debian Developer   http://www.debian.org
diff -Nur dhcp3-3.0.1.old/server/dhcpd.c dhcp3-3.0.1/server/dhcpd.c
--- dhcp3-3.0.1.old/server/dhcpd.c	2005-04-11 18:39:29.845552696 +0200
+++ dhcp3-3.0.1/server/dhcpd.c	2005-04-11 19:19:24.436519536 +0200
@@ -45,6 +45,7 @@
 
 #include "dhcpd.h"
 #include "version.h"
+#include "droppriv.h"
 #include <omapip/omapip_p.h>
 
 static void usage PROTO ((void));
@@ -226,6 +227,10 @@
 	char *traceoutfile = (char *)0;
 #endif
 
+        /* drop privileges */
+        cap_value_t capsneeded[] = { CAP_NET_RAW, CAP_NET_BIND_SERVICE };
+        drop_privileges( "dhcpd", "dhcpd", 2, capsneeded, -1 );
+
 	/* Make sure we have stdin, stdout and stderr. */
 	status = open ("/dev/null", O_RDWR);
 	if (status == 0)
@@ -599,6 +604,9 @@
 	omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
 			     (omapi_object_t *)0, "state", server_running);
 
+        /* drop all remaining capabilities */
+        drop_privileges( "dhcpd", "dhcpd", 0, NULL, -1 );
+
 	/* Receive packets and dispatch them... */
 	dispatch ();
 
diff -Nur dhcp3-3.0.1.old/server/Makefile.dist dhcp3-3.0.1/server/Makefile.dist
--- dhcp3-3.0.1.old/server/Makefile.dist	2005-04-11 18:39:29.845552696 +0200
+++ dhcp3-3.0.1/server/Makefile.dist	2005-04-11 18:50:07.370634152 +0200
@@ -34,6 +34,7 @@
 INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes
 DHCPLIB = ../common/libdhcp.a $(BINDLIB) ../omapip/libomapi.a ../dst/libdst.a
 CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS)
+LIBS  = -lcap
 
 all:	$(PROG) $(CATMANPAGES)
 
diff -Nurp dhcp3-3.0.1.old/common/droppriv.c dhcp3-3.0.1/common/droppriv.c
--- dhcp3-3.0.1.old/common/droppriv.c	1970-01-01 01:00:00.000000000 +0100
+++ dhcp3-3.0.1/common/droppriv.c	2005-05-12 15:38:52.000000000 +0200
@@ -0,0 +1,96 @@
+/**
+ * droppriv.c - drop privileges of a program running as root
+ * 
+ * (C) 2004 Martin Pitt <[EMAIL PROTECTED]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ */
+
+#include "droppriv.h"
+#include <sys/prctl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+void
+drop_privileges( const char* user, const char* group, int numcaps,
+	cap_value_t* caps, int errorexit )
+{
+    cap_t cap;
+    struct passwd *pw = NULL;
+    struct group *gr = NULL;
+
+    /* determine user and group id */
+    if( user != NULL ) {
+	pw = getpwnam( user );
+	if( !pw )  {
+	    fprintf( stderr, "drop_privileges: user %s does not exist\n", user );
+	    exit( errorexit );
+	}
+    }
+
+    if( group != NULL ) {
+	gr = getgrnam( group );
+	if( !gr ) {
+	    fprintf( stderr, "drop_privileges: group %s does not exist\n", group );
+	    exit( errorexit );
+	}
+    }
+
+    /* keep capabilities */
+    if( numcaps > 0 ) {
+        int result;
+
+        if( prctl( PR_SET_KEEPCAPS, 1, 0, 0, 0 ) ) {
+            perror( "drop_privileges: could not keep capabilities" );
+            exit( errorexit );
+        }
+
+        /* test whether cap_set_proc works */
+        cap = cap_get_proc();
+        if( cap ) {
+            result = cap_set_proc( cap );
+            cap_free( cap );
+            if( result )
+                return;
+        } else
+            return;
+    }
+
+
+    /* change uid/gid */
+    if( gr != NULL && setgid( gr->gr_gid ) ) {
+	perror( "drop_privileges: could not set group id" );
+	exit( errorexit );
+    }
+
+    if( pw != NULL && setuid( pw->pw_uid ) ) {
+	perror( "drop_privileges: could not set user id" );
+	exit( errorexit );
+    }
+
+    /* set necessary capabilities */
+    if( numcaps > 0 ) {
+        cap = cap_init();
+        if( cap_set_flag( cap, CAP_PERMITTED, numcaps, caps, CAP_SET ) ||
+            cap_set_flag( cap, CAP_EFFECTIVE, numcaps, caps, CAP_SET ) ) {
+            perror( "drop_privileges: cap_set_flag" );
+            exit( errorexit );
+        }
+
+        if( cap_set_proc( cap ) ) {
+            perror( "drop_privileges: could not install capabilities" );
+            exit( errorexit );
+        }
+
+        if( cap_free( cap ) ) {
+            perror( "drop_privileges: cap_free" );
+            exit( errorexit );
+        }
+    }
+}
+
diff -Nurp dhcp3-3.0.1.old/common/Makefile.dist dhcp3-3.0.1/common/Makefile.dist
--- dhcp3-3.0.1.old/common/Makefile.dist	2004-06-14 23:08:42.000000000 +0200
+++ dhcp3-3.0.1/common/Makefile.dist	2005-05-12 15:31:47.000000000 +0200
@@ -25,11 +25,11 @@ SEDMANPAGES = dhcp-options.man5 dhcp-eva
 SRC    = raw.c parse.c nit.c icmp.c dispatch.c conflex.c upf.c bpf.c socket.c \
 	 lpf.c dlpi.c packet.c tr.c ethernet.c iscprint.c memory.c print.c \
 	 options.c inet.c tree.c tables.c alloc.c fddi.c ctrace.c dns.c \
-	 resolv.c execute.c discover.c comapi.c
+	 resolv.c execute.c discover.c comapi.c droppriv.c
 OBJ    = raw.o parse.o nit.o icmp.o dispatch.o conflex.o upf.o bpf.o socket.o \
 	 lpf.o dlpi.o packet.o tr.o ethernet.o iscprint.o memory.o print.o \
 	 options.o inet.o tree.o tables.o alloc.o fddi.o ctrace.o dns.o \
-	 resolv.o execute.o discover.o comapi.o
+	 resolv.o execute.o discover.o comapi.o droppriv.o
 MAN    = dhcp-options.5 dhcp-eval.5
 
 INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes
diff -Nurp dhcp3-3.0.1.old/includes/droppriv.h dhcp3-3.0.1/includes/droppriv.h
--- dhcp3-3.0.1.old/includes/droppriv.h	1970-01-01 01:00:00.000000000 +0100
+++ dhcp3-3.0.1/includes/droppriv.h	2005-05-12 15:31:47.000000000 +0200
@@ -0,0 +1,31 @@
+/**
+ * droppriv.h - drop privileges of a program running as root
+ *
+ * (C) 2004 Martin Pitt <[EMAIL PROTECTED]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ */
+
+#ifndef _DROPPRIV_H
+#define _DROPPRIV_H
+
+#include <sys/capability.h>
+
+/**
+ * Drop all but necessary privileges from a program that is started as
+ * root. Set the running user id and group id to the corresponding
+ * values of 'user' and 'group' (NULL values cause the current
+ * user/group not to change). Drops all capabilities but the
+ * ones specified in caps. numcaps is the number of entries in
+ * caps. On error, a message is printed to stderr and the program
+ * terminates with exit code 'errorexit'.
+ */
+void
+drop_privileges( const char* user, const char* group, int numcaps,
+       cap_value_t* caps, int errorexit );
+
+#endif
+

Attachment: signature.asc
Description: Digital signature

Reply via email to