Module Name:    src
Committed By:   elad
Date:           Thu Apr 30 18:18:34 UTC 2009

Modified Files:
        src/sys/netinet: in_pcb.c
        src/sys/netinet6: in6_pcb.c in6_pcb.h udp6_output.c

Log Message:
- Make in6_pcbbind_{addr,port}() static

- Properly authorize port binding in in_pcbsetport() and in6_pcbsetport()

- Pass struct sockaddr_in6 to in6_pcbsetport() instead of just the address,
  so that we have a more complete context

- Adjust udp6_output() to craft a sockaddr_in6 as it calls in6_pcbsetport()

- Fix an issue in in_pcbbind() where we used the "dom_sa_any" pointer and
  not a copy of it, pointed out by bouyer@, thanks!

Mailing list reference:

        http://mail-index.netbsd.org/tech-net/2009/04/29/msg001259.html


To generate a diff of this commit:
cvs rdiff -u -r1.133 -r1.134 src/sys/netinet/in_pcb.c
cvs rdiff -u -r1.106 -r1.107 src/sys/netinet6/in6_pcb.c
cvs rdiff -u -r1.33 -r1.34 src/sys/netinet6/in6_pcb.h
cvs rdiff -u -r1.37 -r1.38 src/sys/netinet6/udp6_output.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet/in_pcb.c
diff -u src/sys/netinet/in_pcb.c:1.133 src/sys/netinet/in_pcb.c:1.134
--- src/sys/netinet/in_pcb.c:1.133	Thu Apr 23 17:02:26 2009
+++ src/sys/netinet/in_pcb.c	Thu Apr 30 18:18:34 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_pcb.c,v 1.133 2009/04/23 17:02:26 elad Exp $	*/
+/*	$NetBSD: in_pcb.c,v 1.134 2009/04/30 18:18:34 elad Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.133 2009/04/23 17:02:26 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.134 2009/04/30 18:18:34 elad Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -224,8 +224,7 @@
 }
 
 static int
-in_pcbsetport(struct in_addr *laddr, struct inpcb *inp,
-    struct sockaddr_in *sin, kauth_cred_t cred)
+in_pcbsetport(struct sockaddr_in *sin, struct inpcb *inp, kauth_cred_t cred)
 {
 	struct inpcbtable *table = inp->inp_table;
 	struct socket *so = inp->inp_socket;
@@ -233,23 +232,33 @@
 	u_int16_t  mymin, mymax;
 	u_int16_t *lastport;
 	u_int16_t lport = 0;
+	enum kauth_network_req req;
+	int error;
 
 	if (inp->inp_flags & INP_LOWPORT) {
 #ifndef IPNOPRIVPORTS
-		if (kauth_authorize_network(cred,
-		    KAUTH_NETWORK_BIND,
-		    KAUTH_REQ_NETWORK_BIND_PRIVPORT, so,
-		    sin, NULL))
-			return (EACCES);
+		req = KAUTH_REQ_NETWORK_BIND_PRIVPORT;
+#else
+		req = KAUTH_REQ_NETWORK_BIND_PORT;
 #endif
+
 		mymin = lowportmin;
 		mymax = lowportmax;
 		lastport = &table->inpt_lastlow;
 	} else {
+		req = KAUTH_REQ_NETWORK_BIND_PORT;
+
 		mymin = anonportmin;
 		mymax = anonportmax;
 		lastport = &table->inpt_lastport;
 	}
+
+	/* XXX-kauth: KAUTH_REQ_NETWORK_BIND_AUTOASSIGN_{,PRIV}PORT */
+	error = kauth_authorize_network(cred, KAUTH_NETWORK_BIND, req, so, sin,
+	    NULL);
+	if (error)
+		return (error);
+
 	if (mymin > mymax) {	/* sanity check */
 		u_int16_t swp;
 
@@ -262,9 +271,17 @@
 	for (cnt = mymax - mymin + 1; cnt; cnt--, lport--) {
 		if (lport < mymin || lport > mymax)
 			lport = mymax;
-		if (!in_pcblookup_port(table, inp->inp_laddr,
-		    htons(lport), 1))
+		if (!in_pcblookup_port(table, sin->sin_addr, htons(lport), 1)) {
+			/* We have a free port, check with the secmodel(s). */
+			error = kauth_authorize_network(cred,
+			    KAUTH_NETWORK_BIND, req, so, sin, NULL);
+			if (error) {
+				/* Secmodel says no. Keep looking. */
+				continue;
+			}
+
 			goto found;
+		}
 	}
 
 	return (EAGAIN);
@@ -322,7 +339,7 @@
 	} 
 
 	if (sin->sin_port == 0) {
-		error = in_pcbsetport(&inp->inp_laddr, inp, sin, cred);
+		error = in_pcbsetport(sin, inp, cred);
 		if (error)
 			return (error);
 	} else {
@@ -394,6 +411,7 @@
 {
 	struct inpcb *inp = v;
 	struct sockaddr_in *sin = NULL; /* XXXGCC */
+	struct sockaddr_in lsin;
 	int error;
 
 	if (inp->inp_af != AF_INET)
@@ -409,8 +427,9 @@
 		if (nam->m_len != sizeof (*sin))
 			return (EINVAL);
 	} else {
-		sin = (struct sockaddr_in *)
-		    __UNCONST(inp->inp_socket->so_proto->pr_domain->dom_sa_any);
+		lsin = *((const struct sockaddr_in *)
+		    inp->inp_socket->so_proto->pr_domain->dom_sa_any);
+		sin = &lsin;
 	}
 
 	/* Bind address. */

Index: src/sys/netinet6/in6_pcb.c
diff -u src/sys/netinet6/in6_pcb.c:1.106 src/sys/netinet6/in6_pcb.c:1.107
--- src/sys/netinet6/in6_pcb.c:1.106	Wed Apr 22 18:35:01 2009
+++ src/sys/netinet6/in6_pcb.c	Thu Apr 30 18:18:34 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_pcb.c,v 1.106 2009/04/22 18:35:01 elad Exp $	*/
+/*	$NetBSD: in6_pcb.c,v 1.107 2009/04/30 18:18:34 elad Exp $	*/
 /*	$KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.106 2009/04/22 18:35:01 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.107 2009/04/30 18:18:34 elad Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -187,7 +187,7 @@
 /*
  * Bind address from sin6 to in6p.
  */
-int
+static int
 in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
 {
 	int error;
@@ -257,7 +257,7 @@
 /*
  * Bind port from sin6 to in6p.
  */
-int
+static int
 in6_pcbbind_port(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
 {
 	struct inpcbtable *table = in6p->in6p_table;
@@ -325,7 +325,7 @@
 
 	if (sin6->sin6_port == 0) {
 		int e;
-		e = in6_pcbsetport(&in6p->in6p_laddr, in6p, l);
+		e = in6_pcbsetport(sin6, in6p, l);
 		if (e != 0)
 			return (e);
 	} else {

Index: src/sys/netinet6/in6_pcb.h
diff -u src/sys/netinet6/in6_pcb.h:1.33 src/sys/netinet6/in6_pcb.h:1.34
--- src/sys/netinet6/in6_pcb.h:1.33	Mon Apr 20 18:14:30 2009
+++ src/sys/netinet6/in6_pcb.h	Thu Apr 30 18:18:34 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_pcb.h,v 1.33 2009/04/20 18:14:30 elad Exp $	*/
+/*	$NetBSD: in6_pcb.h,v 1.34 2009/04/30 18:18:34 elad Exp $	*/
 /*	$KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $	*/
 
 /*
@@ -153,8 +153,6 @@
 void	in6_pcbinit(struct inpcbtable *, int, int);
 int	in6_pcballoc(struct socket *, void *);
 int	in6_pcbbind(void *, struct mbuf *, struct lwp *);
-int	in6_pcbbind_addr(struct in6pcb *, struct sockaddr_in6 *, struct lwp *);
-int	in6_pcbbind_port(struct in6pcb *, struct sockaddr_in6 *, struct lwp *);
 int	in6_pcbconnect(void *, struct mbuf *, struct lwp *);
 void	in6_pcbdetach(struct in6pcb *);
 void	in6_pcbdisconnect(struct in6pcb *);
@@ -172,7 +170,7 @@
 
 /* in in6_src.c */
 int	in6_selecthlim(struct in6pcb *, struct ifnet *);
-int	in6_pcbsetport(struct in6_addr *, struct in6pcb *, struct lwp *);
+int	in6_pcbsetport(struct sockaddr_in6 *, struct in6pcb *, struct lwp *);
 
 extern struct rtentry *
 	in6_pcbrtentry(struct in6pcb *);

Index: src/sys/netinet6/udp6_output.c
diff -u src/sys/netinet6/udp6_output.c:1.37 src/sys/netinet6/udp6_output.c:1.38
--- src/sys/netinet6/udp6_output.c:1.37	Fri Oct 24 22:30:32 2008
+++ src/sys/netinet6/udp6_output.c	Thu Apr 30 18:18:34 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp6_output.c,v 1.37 2008/10/24 22:30:32 dyoung Exp $	*/
+/*	$NetBSD: udp6_output.c,v 1.38 2009/04/30 18:18:34 elad Exp $	*/
 /*	$KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.37 2008/10/24 22:30:32 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.38 2009/04/30 18:18:34 elad Exp $");
 
 #include "opt_inet.h"
 
@@ -78,6 +78,7 @@
 #include <sys/proc.h>
 #include <sys/syslog.h>
 #include <sys/kauth.h>
+#include <sys/domain.h>
 
 #include <net/if.h>
 #include <net/route.h>
@@ -283,9 +284,22 @@
 				error = EADDRNOTAVAIL;
 			goto release;
 		}
-		if (in6p->in6p_lport == 0 &&
-		    (error = in6_pcbsetport(laddr, in6p, l)) != 0)
-			goto release;
+		if (in6p->in6p_lport == 0) {
+			/*
+			 * Craft a sockaddr_in6 for the local endpoint. Use the
+			 * "any" as a base, set the address, and recover the
+			 * scope.
+			 */
+			struct sockaddr_in6 lsin6 =
+			    *((const struct sockaddr_in6 *)in6p->in6p_socket->so_proto->pr_domain->dom_sa_any);
+			lsin6.sin6_addr = *laddr;
+			error = sa6_recoverscope(&lsin6);
+			if (error)
+				goto release;
+			error = in6_pcbsetport(&lsin6, in6p, l);
+			if (error)
+				goto release;
+		}
 	} else {
 		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
 			error = ENOTCONN;

Reply via email to