Subject: new sysctl - privilaged ports runtime option?
To: None <tech-kern@netbsd.org>
From: Joe Reed <jnr@po.cwru.edu>
List: tech-kern
Date: 08/06/2002 15:19:08
--------------Boundary-00=_W3VFASR6F7TGC74BXQ0R
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 8bit


hi

i've wondered for a while now why we have the <1024 privelaged port
restriction a compile-time option and not a runtime one.  in my opinion,
there is no reason why one should have to compile a kernel of a freshly
installed system just to run processes like sendmail and httpd as a
unprivilaged user.  we have net.inet{,6}.ip{,6}.{gateway,forwarding} as
runtime settings, why not the reserved ports?

i've added 2 new sysctl's net.inet.ip.reservedports and
net.inet6.ip6.reservedports which when set to 0, remove the <1024
restriction, and when set to 1 enforce it.

the kernel configuration option NOPRIVPORTS is used to set the default value
for these sysctl's.

since the change only affects the bind(2) operation, i don't believe this
will adversely affect the performance of the network operations.

i'd like some feedback on this before i send-pr it.  i think i've got this
right, but i'd like to hear from people who know more than i:
 1) is this a worthwhile change?  are there other issues i have not
considered?
 2) is this the correct implementation for what i'm trying to accomplish?

i've attached diffs of src/sys/netinet/ and src/sys/netinet6 which contain
all the changes for the implementation of the 2 sysctls.

 --joe

-------------------------------------------------------


--------------Boundary-00=_W3VFASR6F7TGC74BXQ0R
Content-Type: text/plain;
  charset="iso-8859-1";
  name="netinet.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="netinet.diff"

Index: in.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/in.h,v
retrieving revision 1.58
diff -u -r1.58 in.h
--- in.h	2002/05/13 13:34:32	1.58
+++ in.h	2002/08/06 17:28:44
@@ -379,7 +379,8 @@
 #define	IPCTL_LOWPORTMAX       17	/* maximum reserved port */
 #define	IPCTL_MAXFRAGPACKETS   18	/* max packets reassembly queue */
 #define IPCTL_GRE_TTL          19	/* default TTL for gre encap packet */
-#define	IPCTL_MAXID	       20
+#define IPCTL_RESERVEDPORTS    20	/* reserved ports toggle */
+#define	IPCTL_MAXID	       21
 
 #define	IPCTL_NAMES { \
 	{ 0, 0 }, \
@@ -402,6 +403,7 @@
 	{ "lowportmax", CTLTYPE_INT }, \
 	{ "maxfragpackets", CTLTYPE_INT }, \
 	{ "grettl", CTLTYPE_INT }, \
+	{ "reservedports", CTLTYPE_INT} , \
 }
 #endif /* !_POSIX_C_SOURCE && !_XOPEN_SOURCE */
 
Index: in_pcb.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/in_pcb.c,v
retrieving revision 1.79
diff -u -r1.79 in_pcb.c
--- in_pcb.c	2002/06/11 19:39:59	1.79
+++ in_pcb.c	2002/08/06 17:28:44
@@ -223,9 +223,7 @@
 	struct sockaddr_in *sin;
 	u_int16_t lport = 0;
 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
-#ifndef IPNOPRIVPORTS
 	int error;
-#endif
 
 	if (TAILQ_FIRST(&in_ifaddr) == 0)
 		return (EADDRNOTAVAIL);
@@ -264,12 +262,12 @@
 	}
 	if (lport) {
 		struct inpcb *t;
-#ifndef IPNOPRIVPORTS
-		/* GROSS */
-		if (ntohs(lport) < IPPORT_RESERVED &&
-		    (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))))
-			return (EACCES);
-#endif
+
+		if (reservedports) 
+			if (ntohs(lport) < IPPORT_RESERVED &&
+			    (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))))
+				return (EACCES);
+
 		if (so->so_uid && !IN_MULTICAST(sin->sin_addr.s_addr)) {
 			t = in_pcblookup_port(table, sin->sin_addr, lport, 1);
 		/*
@@ -298,10 +296,10 @@
 		u_int16_t *lastport;
 
 		if (inp->inp_flags & INP_LOWPORT) {
-#ifndef IPNOPRIVPORTS
-			if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
-				return (EACCES);
-#endif
+			if (reservedports)
+				if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
+					return (EACCES);
+
 			min = lowportmin;
 			max = lowportmax;
 			lastport = &table->inpt_lastlow;
Index: ip_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_input.c,v
retrieving revision 1.154
diff -u -r1.154 ip_input.c
--- ip_input.c	2002/06/30 22:40:34	1.154
+++ ip_input.c	2002/08/06 17:28:44
@@ -197,6 +197,12 @@
 int	ipprintfs = 0;
 #endif
 
+#ifdef NOPRIVPORTS
+int reservedports = 0;
+#else
+int reservedports = 1;
+#endif
+
 struct rttimer_queue *ip_mtudisc_timeout_q = NULL;
 
 extern	struct domain inetdomain;
@@ -1833,9 +1839,7 @@
 		error = sysctl_int(oldp, oldlenp, newp, newlen, &anonportmin);
 		if (anonportmin >= anonportmax || anonportmin < 0
 		    || anonportmin > 65535
-#ifndef IPNOPRIVPORTS
-		    || anonportmin < IPPORT_RESERVED
-#endif
+			|| ( reservedports && anonportmin < IPPORT_RESERVED)
 		    ) {
 			anonportmin = old;
 			return (EINVAL);
@@ -1846,9 +1850,7 @@
 		error = sysctl_int(oldp, oldlenp, newp, newlen, &anonportmax);
 		if (anonportmin >= anonportmax || anonportmax < 0
 		    || anonportmax > 65535
-#ifndef IPNOPRIVPORTS
-		    || anonportmax < IPPORT_RESERVED
-#endif
+			|| ( reservedports && anonportmax < IPPORT_RESERVED)
 		    ) {
 			anonportmax = old;
 			return (EINVAL);
@@ -1889,8 +1891,9 @@
 				  &ip_gre_ttl));
 #endif
 
-#ifndef IPNOPRIVPORTS
 	case IPCTL_LOWPORTMIN:
+		if (reservedports == 0)
+			return (EOPNOTSUPP);
 		old = lowportmin;
 		error = sysctl_int(oldp, oldlenp, newp, newlen, &lowportmin);
 		if (lowportmin >= lowportmax
@@ -1902,6 +1905,8 @@
 		}
 		return (error);
 	case IPCTL_LOWPORTMAX:
+		if (reservedports == 0) 
+			return (EOPNOTSUPP);
 		old = lowportmax;
 		error = sysctl_int(oldp, oldlenp, newp, newlen, &lowportmax);
 		if (lowportmin >= lowportmax
@@ -1912,11 +1917,13 @@
 			return (EINVAL);
 		}
 		return (error);
-#endif
 
 	case IPCTL_MAXFRAGPACKETS:
 		return (sysctl_int(oldp, oldlenp, newp, newlen,
 		    &ip_maxfragpackets));
+
+	case IPCTL_RESERVEDPORTS:
+		return (sysctl_int(oldp, oldlenp, newp, newlen, &reservedports));
 
 	default:
 		return (EOPNOTSUPP);
Index: ip_var.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/ip_var.h,v
retrieving revision 1.48
diff -u -r1.48 ip_var.h
--- ip_var.h	2002/06/30 22:40:35	1.48
+++ ip_var.h	2002/08/06 17:28:44
@@ -200,6 +200,7 @@
 extern int   anonportmax;		/* maximum ephemeral port */
 extern int   lowportmin;		/* minimum reserved port */
 extern int   lowportmax;		/* maximum reserved port */
+extern int   reservedports;		/* reserved port toggle */
 extern struct rttimer_queue *ip_mtudisc_timeout_q;
 #ifdef GATEWAY
 extern int ip_maxflows;

--------------Boundary-00=_W3VFASR6F7TGC74BXQ0R
Content-Type: text/plain;
  charset="iso-8859-1";
  name="netinet6.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="netinet6.diff"

Index: in6.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/in6.h,v
retrieving revision 1.41
diff -u -r1.41 in6.h
--- in6.h	2002/06/08 21:22:31	1.41
+++ in6.h	2002/08/06 17:30:42
@@ -544,7 +544,8 @@
 #define IPV6CTL_MAXFRAGS	41	/* max fragments */
 /* New entries should be added here from current IPV6CTL_MAXID value. */
 /* to define items, should talk with KAME guys first, for *BSD compatibility */
-#define IPV6CTL_MAXID		42
+#define IPV6CTL_RESERVEDPORTS 42
+#define IPV6CTL_MAXID		43
 
 #define IPV6CTL_NAMES { \
 	{ 0, 0 }, \
@@ -589,6 +590,7 @@
 	{ 0, 0 }, \
 	{ 0, 0 }, \
 	{ "maxfrags", CTLTYPE_INT }, \
+	{ "reservedports", CTLTYPE_INT }, \
 }
 
 #endif /* !_POSIX_C_SOURCE && !_XOPEN_SOURCE */
Index: in6_pcb.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/in6_pcb.c,v
retrieving revision 1.49
diff -u -r1.49 in6_pcb.c
--- in6_pcb.c	2002/06/11 19:40:00	1.49
+++ in6_pcb.c	2002/08/06 17:30:42
@@ -237,18 +237,18 @@
 			}
 		}
 		if (lport) {
-#ifndef IPNOPRIVPORTS
-			int priv;
-
-			/*
-			 * NOTE: all operating systems use suser() for
-			 * privilege check!  do not rewrite it into SS_PRIV.
-			 */
-			priv = (p && !suser(p->p_ucred, &p->p_acflag)) ? 1 : 0;
-			/* GROSS */
-			if (ntohs(lport) < IPV6PORT_RESERVED && !priv)
-				return(EACCES);
-#endif
+			if (ip6_reservedports) {
+				int priv;
+	
+				/*
+				 * NOTE: all operating systems use suser() for
+				 * privilege check!  do not rewrite it into SS_PRIV.
+				 */
+				priv = (p && !suser(p->p_ucred, &p->p_acflag)) ? 1 : 0;
+				/* GROSS */
+				if (ntohs(lport) < IPV6PORT_RESERVED && !priv)
+					return(EACCES);
+			}
 
 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
 				/* should check this but we can't ... */
Index: in6_proto.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/in6_proto.c,v
retrieving revision 1.43
diff -u -r1.43 in6_proto.c
--- in6_proto.c	2002/06/09 14:43:12	1.43
+++ in6_proto.c	2002/08/06 17:30:42
@@ -254,6 +254,12 @@
 #endif /* GATEWAY6 */
 #endif /* !IPV6FORWARDING */
 
+#ifndef NOPRIVPORTS
+int ip6_reservedports = 1;
+#else
+int ip6_reservedports = 0;
+#endif
+
 #ifndef	IPV6_SENDREDIRECTS
 #define	IPV6_SENDREDIRECTS	1
 #endif
Index: in6_src.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/in6_src.c,v
retrieving revision 1.13
diff -u -r1.13 in6_src.c
--- in6_src.c	2002/06/08 20:06:44	1.13
+++ in6_src.c	2002/08/06 17:30:42
@@ -353,12 +353,12 @@
 		wild = IN6PLOOKUP_WILDCARD;
 
 	if (in6p->in6p_flags & IN6P_LOWPORT) {
-#ifndef IPNOPRIVPORTS
-		struct proc *p = curproc;		/* XXX */
-
-		if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
-			return (EACCES);
-#endif
+		if (ip6_reservedports) {
+			struct proc *p = curproc;		/* XXX */
+	
+			if (p == 0 || (suser(p->p_ucred, &p->p_acflag) != 0))
+				return (EACCES);
+		}
 		min = ip6_lowportmin;
 		max = ip6_lowportmax;
 	} else {
Index: ip6_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6_input.c,v
retrieving revision 1.57
diff -u -r1.57 ip6_input.c
--- ip6_input.c	2002/06/30 22:40:39	1.57
+++ ip6_input.c	2002/08/06 17:30:42
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_input.c,v 1.57 2002/06/30 22:40:39 thorpej Exp $	*/
+/*	$NetBSD: ip6_input.c,v 1.56 2002/06/09 14:43:12 itojun Exp $	*/
 /*	$KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $	*/
 
 /*
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.57 2002/06/30 22:40:39 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.56 2002/06/09 14:43:12 itojun Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -1478,9 +1478,7 @@
 		    &ip6_anonportmin);
 		if (ip6_anonportmin >= ip6_anonportmax || ip6_anonportmin < 0 ||
 		    ip6_anonportmin > 65535
-#ifndef IPNOPRIVPORTS
-		    || ip6_anonportmin < IPV6PORT_RESERVED
-#endif
+		    || (ip6_reservedports && ip6_anonportmin < IPV6PORT_RESERVED)
 		    ) {
 			ip6_anonportmin = old;
 			return (EINVAL);
@@ -1492,16 +1490,16 @@
 		    &ip6_anonportmax);
 		if (ip6_anonportmin >= ip6_anonportmax || ip6_anonportmax < 0 ||
 		    ip6_anonportmax > 65535
-#ifndef IPNOPRIVPORTS
-		    || ip6_anonportmax < IPV6PORT_RESERVED
-#endif
+		    || (ip6_reservedports && ip6_anonportmax < IPV6PORT_RESERVED)
 		    ) {
 			ip6_anonportmax = old;
 			return (EINVAL);
 		}
 		return (error);
-#ifndef IPNOPRIVPORTS
 	case IPV6CTL_LOWPORTMIN:
+		if (ip6_reservedports == 0)
+			return (EOPNOTSUPP);
+
 		old = ip6_lowportmin;
 		error = sysctl_int(oldp, oldlenp, newp, newlen,
 		    &ip6_lowportmin);
@@ -1513,6 +1511,9 @@
 		}
 		return (error);
 	case IPV6CTL_LOWPORTMAX:
+		if (ip6_reservedports == 0)
+			return (EOPNOTSUPP);
+
 		old = ip6_lowportmax;
 		error = sysctl_int(oldp, oldlenp, newp, newlen,
 		    &ip6_lowportmax);
@@ -1523,9 +1524,11 @@
 			return (EINVAL);
 		}
 		return (error);
-#endif
 	case IPV6CTL_MAXFRAGS:
 		return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_maxfrags);
+	case IPV6CTL_RESERVEDPORTS:
+		return sysctl_int(oldp, oldlenp, newp, newlen,
+				  &ip6_reservedports);
 	default:
 		return EOPNOTSUPP;
 	}
Index: ip6_var.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/ip6_var.h,v
retrieving revision 1.22
diff -u -r1.22 ip6_var.h
--- ip6_var.h	2002/06/30 22:40:40	1.22
+++ ip6_var.h	2002/08/06 17:30:44
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_var.h,v 1.22 2002/06/30 22:40:40 thorpej Exp $	*/
+/*	$NetBSD: ip6_var.h,v 1.21 2002/06/08 21:22:33 itojun Exp $	*/
 /*	$KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $	*/
 
 /*
@@ -222,6 +222,7 @@
 extern int	ip6_rr_prune;		/* router renumbering prefix
 					 * walk list every 5 sec.    */
 extern int	ip6_v6only;
+extern int	ip6_reservedports;	/* reserved ports */
 
 extern struct socket *ip6_mrouter; 	/* multicast routing daemon */
 extern int	ip6_sendredirects;	/* send IP redirects when forwarding? */

--------------Boundary-00=_W3VFASR6F7TGC74BXQ0R--