tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

in_pcbsetport(), in6_pcbsetport()



Hi,

Attached is a diff that implements the following changes:

  - in6_pcbbind_{addr,port}() become static (I should have done this
    before).

  - in_pcbsetport(), in6_pcbsetport() properly authorize port binding.
    This is just a first part, I'm about to add a new request to
    indicate "auto-assign", but it shouldn't stand in the way of the
    changes here.

  - Pass sockaddr_in6 to in6_pcbsetport(), similarly to its netinet
    counterpart. Craft one in udp6_output() where we don't have it in
    our context.

  - Don't pass "laddr" to the aforementioned functions, as it's
    redundant now that both take a sockaddr_in{,6}.

Please review. No change in functionality is expected, but I'd like
eyes on this from people who are more familiar with the IPv6 stack.

Thanks,

-e.
Index: netinet/in_pcb.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.133
diff -u -p -r1.133 in_pcb.c
--- netinet/in_pcb.c    23 Apr 2009 17:02:26 -0000      1.133
+++ netinet/in_pcb.c    28 Apr 2009 22:59:10 -0000
@@ -224,8 +224,7 @@ in_pcballoc(struct socket *so, void *v)
 }
 
 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 @@ in_pcbsetport(struct in_addr *laddr, str
        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 @@ in_pcbsetport(struct in_addr *laddr, str
        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 @@ in_pcbbind_port(struct inpcb *inp, struc
        } 
 
        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 {
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.106
diff -u -p -r1.106 in6_pcb.c
--- netinet6/in6_pcb.c  22 Apr 2009 18:35:01 -0000      1.106
+++ netinet6/in6_pcb.c  28 Apr 2009 23:03:19 -0000
@@ -187,7 +187,7 @@ in6_pcballoc(struct socket *so, void *v)
 /*
  * 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 @@ in6_pcbbind_addr(struct in6pcb *in6p, st
 /*
  * 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 @@ in6_pcbbind_port(struct in6pcb *in6p, st
 
        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: netinet6/in6_pcb.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/in6_pcb.h,v
retrieving revision 1.33
diff -u -p -r1.33 in6_pcb.h
--- netinet6/in6_pcb.h  20 Apr 2009 18:14:30 -0000      1.33
+++ netinet6/in6_pcb.h  28 Apr 2009 23:03:35 -0000
@@ -153,8 +153,6 @@ void        in6_losing(struct in6pcb *);
 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 @@ void        in6_setsockaddr(struct in6pcb *, st
 
 /* 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: netinet6/in6_src.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.46
diff -u -p -r1.46 in6_src.c
--- netinet6/in6_src.c  18 Mar 2009 16:00:22 -0000      1.46
+++ netinet6/in6_src.c  28 Apr 2009 23:06:43 -0000
@@ -814,7 +814,7 @@ in6_selecthlim(struct in6pcb *in6p, stru
  * Find an empty port and set it to the specified PCB.
  */
 int
-in6_pcbsetport(struct in6_addr *laddr, struct in6pcb *in6p, struct lwp *l)
+in6_pcbsetport(struct sockaddr_in6 *sin6, struct in6pcb *in6p, struct lwp *l)
 {
        struct socket *so = in6p->in6p_socket;
        struct inpcbtable *table = in6p->in6p_table;
@@ -823,6 +823,8 @@ in6_pcbsetport(struct in6_addr *laddr, s
        u_int16_t lport, *lastport;
        int wild = 0;
        void *t;
+       int error;
+       enum kauth_network_req req;
 
        /* XXX: this is redundant when called from in6_pcbbind */
        if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
@@ -832,19 +834,28 @@ in6_pcbsetport(struct in6_addr *laddr, s
 
        if (in6p->in6p_flags & IN6P_LOWPORT) {
 #ifndef IPNOPRIVPORTS
-               if (l == 0 || (kauth_authorize_generic(l->l_cred,
-                   KAUTH_GENERIC_ISSUSER, NULL) != 0))
-                       return (EACCES);
+               req = KAUTH_REQ_NETWORK_BIND_PRIVPORT;
+#else
+               req = KAUTH_REQ_NETWORK_BIND_PORT;
 #endif
+
                minport = ip6_lowportmin;
                maxport = ip6_lowportmax;
                lastport = &table->inpt_lastlow;
        } else {
+               req = KAUTH_REQ_NETWORK_BIND_PORT;
+
                minport = ip6_anonportmin;
                maxport = ip6_anonportmax;
                lastport = &table->inpt_lastport;
        }
 
+       /* XXX-kauth: KAUTH_REQ_NETWORK_BIND_AUTOASSIGN_{,PRIV}PORT */
+       error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_BIND, req, so,
+           sin6, NULL);
+       if (error)
+               return (error);
+
        if (minport > maxport) {        /* sanity check */
                u_int16_t swp;
                
@@ -858,18 +869,27 @@ in6_pcbsetport(struct in6_addr *laddr, s
                if (lport < minport || lport > maxport)
                        lport = maxport;
 #ifdef INET
-               if (IN6_IS_ADDR_V4MAPPED(laddr)) {
+               if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
                        t = in_pcblookup_port(table,
-                           *(struct in_addr *)&laddr->s6_addr32[3],
+                           *(struct in_addr *)&sin6->sin6_addr.s6_addr32[3],
                            htons(lport), wild);
                } else
 #endif
                {
-                       t = in6_pcblookup_port(table, laddr, htons(lport),
-                           wild);
+                       t = in6_pcblookup_port(table, &sin6->sin6_addr,
+                           htons(lport), wild);
                }
-               if (t == 0)
+               if (t == 0) {
+                       /* We have a free port. Check with the secmodel. */
+                       error = kauth_authorize_network(l->l_cred,
+                           KAUTH_NETWORK_BIND, req, so, sin6, NULL);
+                       if (error) {
+                               /* Secmodel says no. Keep looking. */
+                               continue;
+                       }
+       
                        goto found;
+               }
        }
 
        return (EAGAIN);
Index: netinet6/udp6_output.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/udp6_output.c,v
retrieving revision 1.37
diff -u -p -r1.37 udp6_output.c
--- netinet6/udp6_output.c      24 Oct 2008 22:30:32 -0000      1.37
+++ netinet6/udp6_output.c      28 Apr 2009 23:02:27 -0000
@@ -78,6 +78,7 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_output.
 #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 @@ udp6_output(struct in6pcb *in6p, struct 
                                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 =
+                           
__UNCONST(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;


Home | Main Index | Thread Index | Old Index