diff options
author | rwatson <rwatson@FreeBSD.org> | 2008-07-18 10:47:07 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2008-07-18 10:47:07 +0000 |
commit | 4efb6d2a37b496ded581b12ed193e4ebe091076a (patch) | |
tree | 5cc7a11f44218d9193298934b3d1154f637e70df /sys/netinet | |
parent | 6dfc39c2b65e071af0416aab8ac653dede74f1b4 (diff) | |
download | FreeBSD-src-4efb6d2a37b496ded581b12ed193e4ebe091076a.zip FreeBSD-src-4efb6d2a37b496ded581b12ed193e4ebe091076a.tar.gz |
Eliminate use of the global ripsrc which was being used to pass address
information from rip_input() to rip_append(). Instead, pass the source
address for an IP datagram to rip_append() using a stack-allocated
sockaddr_in, similar to udp_input() and udp_append().
Prior to the move to rwlocks for inpcbinfo, this was not a problem, as
use of the global was synchronized using the ripcbinfo mutex, but with
read-locking there is the potential for a race during concurrent
receive.
This problem is not present in the IPv6 raw IP socket code, which
already used a stack variable for the address.
Spotted by: mav
MFC after: 1 week (before inpcbinfo rwlock changes)
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/raw_ip.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 902fc5d..ea81cdc 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -153,10 +153,9 @@ rip_init(void) EVENTHANDLER_PRI_ANY); } -static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; - static int -rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n) +rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n, + struct sockaddr_in *ripsrc) { int policyfail = 0; @@ -185,7 +184,7 @@ rip_append(struct inpcb *last, struct ip *ip, struct mbuf *n) ip_savecontrol(last, &opts, ip, n); SOCKBUF_LOCK(&so->so_rcv); if (sbappendaddr_locked(&so->so_rcv, - (struct sockaddr *)&ripsrc, n, opts) == 0) { + (struct sockaddr *)ripsrc, n, opts) == 0) { /* should notify about lost packet */ m_freem(n); if (opts) @@ -208,10 +207,14 @@ rip_input(struct mbuf *m, int off) struct ip *ip = mtod(m, struct ip *); int proto = ip->ip_p; struct inpcb *inp, *last; + struct sockaddr_in ripsrc; - INP_INFO_RLOCK(&ripcbinfo); + bzero(&ripsrc, sizeof(ripsrc)); + ripsrc.sin_len = sizeof(ripsrc); + ripsrc.sin_family = AF_INET; ripsrc.sin_addr = ip->ip_src; last = NULL; + INP_INFO_RLOCK(&ripcbinfo); LIST_FOREACH(inp, &ripcb, inp_list) { INP_RLOCK(inp); if (inp->inp_ip_p && inp->inp_ip_p != proto) { @@ -238,14 +241,14 @@ rip_input(struct mbuf *m, int off) n = m_copy(m, 0, (int)M_COPYALL); if (n != NULL) - (void) rip_append(last, ip, n); + (void) rip_append(last, ip, n, &ripsrc); /* XXX count dropped packet */ INP_RUNLOCK(last); } last = inp; } if (last != NULL) { - if (rip_append(last, ip, m) != 0) + if (rip_append(last, ip, m, &ripsrc) != 0) ipstat.ips_delivered--; INP_RUNLOCK(last); } else { |