summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2012-09-20 12:34:19 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2012-09-20 12:34:19 +0000
commit1a362664c74f5dff3886e0e6e93e56c347204b90 (patch)
treee65a077370119cb68cc0beb929293e6bfe5558e2
parentbd8ba8cae6c333f007e5c8ca7b31dec50d6a8fef (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@
-rw-r--r--sys/kern/uipc_socket.c42
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;