- 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
This commit is contained in:
elad 2009-04-30 18:18:34 +00:00
parent 76ac165302
commit ddcbe0e1dd
4 changed files with 59 additions and 28 deletions

View File

@ -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 @@ 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, struct inpcb *inp,
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, struct inpcb *inp,
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, struct sockaddr_in *sin, kauth_cred_t cred)
}
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 @@ in_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
{
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 @@ in_pcbbind(void *v, struct mbuf *nam, struct lwp *l)
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. */

View File

@ -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 @@ 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, struct sockaddr_in6 *sin6, struct lwp *l)
/*
* 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, struct sockaddr_in6 *sin6, struct lwp *l)
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 {

View File

@ -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_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 *, struct mbuf *);
/* 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 *);

View File

@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.37 2008/10/24 22:30:32 dyoung Exp
#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 mbuf *m, struct mbuf *addr6,
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;