diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2012-09-20 12:34:19 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2012-09-20 12:34:19 +0000 |
commit | 1a362664c74f5dff3886e0e6e93e56c347204b90 (patch) | |
tree | e65a077370119cb68cc0beb929293e6bfe5558e2 /sys/kern | |
parent | bd8ba8cae6c333f007e5c8ca7b31dec50d6a8fef (diff) |
In somove() free the mbufs when necessary instead of freeing them
in the release path. Especially accessing m in a KDASSERT() could
go wrong.
OK claudio@
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/uipc_socket.c | 42 |
1 files changed, 21 insertions, 21 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 6724bd4aaca..de3c9f01cf3 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.107 2012/09/19 20:00:32 bluhm Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.108 2012/09/20 12:34:18 bluhm Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -1151,7 +1151,7 @@ int somove(struct socket *so, int wait) { struct socket *sosp = so->so_splice; - struct mbuf *m = NULL, **mp, *nextrecord; + struct mbuf *m, **mp, *nextrecord; u_long len, off, oobmark; long space; int error = 0, maxreached = 0; @@ -1229,14 +1229,17 @@ somove(struct socket *so, int wait) SBLASTRECORDCHK(&so->so_rcv, "somove"); SBLASTMBUFCHK(&so->so_rcv, "somove"); - KDASSERT(m->m_nextpkt == NULL); KASSERT(so->so_rcv.sb_mb == so->so_rcv.sb_lastrecord); #ifdef SOCKBUF_DEBUG sbcheck(&so->so_rcv); #endif - /* Send window update to source peer if receive buffer has changed. */ - if (m && so->so_proto->pr_flags & PR_WANTRCVD && so->so_pcb) + /* m might be NULL if the loop did break during the first iteration. */ + if (m == NULL) + goto release; + + /* Send window update to source peer as receive buffer has changed. */ + if (so->so_proto->pr_flags & PR_WANTRCVD && so->so_pcb) (so->so_proto->pr_usrreq)(so, PRU_RCVD, NULL, (struct mbuf *)0L, NULL, NULL); @@ -1256,7 +1259,7 @@ somove(struct socket *so, int wait) * Handle oob data. If any malloc fails, ignore error. * TCP urgent data is not very reliable anyway. */ - while (m && ((state & SS_RCVATMARK) || oobmark) && + while (((state & SS_RCVATMARK) || oobmark) && (so->so_options & SO_OOBINLINE)) { struct mbuf *o = NULL; @@ -1268,14 +1271,15 @@ somove(struct socket *so, int wait) if (o) { error = (*sosp->so_proto->pr_usrreq)(sosp, PRU_SEND, m, NULL, NULL, NULL); - m = o; if (error) { if (sosp->so_state & SS_CANTSENDMORE) error = EPIPE; + m_freem(o); goto release; } len -= oobmark; so->so_splicelen += oobmark; + m = o; o = m_get(wait, MT_DATA); } oobmark = 0; @@ -1288,6 +1292,7 @@ somove(struct socket *so, int wait) if (error) { if (sosp->so_state & SS_CANTSENDMORE) error = EPIPE; + m_freem(m); goto release; } len -= 1; @@ -1302,23 +1307,18 @@ somove(struct socket *so, int wait) } /* Append all remaining data to drain socket. */ - if (m) { - if (so->so_rcv.sb_cc == 0 || maxreached) - sosp->so_state &= ~SS_ISSENDING; - error = (*sosp->so_proto->pr_usrreq)(sosp, PRU_SEND, m, NULL, - NULL, NULL); - m = NULL; - if (error) { - if (sosp->so_state & SS_CANTSENDMORE) - error = EPIPE; - goto release; - } - so->so_splicelen += len; + if (so->so_rcv.sb_cc == 0 || maxreached) + sosp->so_state &= ~SS_ISSENDING; + error = (*sosp->so_proto->pr_usrreq)(sosp, PRU_SEND, m, NULL, NULL, + NULL); + if (error) { + if (sosp->so_state & SS_CANTSENDMORE) + error = EPIPE; + goto release; } + so->so_splicelen += len; release: - if (m) - m_freem(m); sosp->so_state &= ~SS_ISSENDING; if (error) so->so_error = error; |