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