Another integer overflow: A recv() call with a size of 2^32 bytes causes
soreceive() to spin in an endless loop, resulting in a system freeze.
The diff below prevents this behaviour by establishing an upper bound
for uio_resid before assigning the value to an integer variable with
smaller width. Also the 'offset' and 'resid' variables are converted to
use the correct integer types.
cheers,
natano
Index: kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.144
diff -u -p -u -r1.144 uipc_socket.c
--- kern/uipc_socket.c 5 Dec 2015 10:11:53 -0000 1.144
+++ kern/uipc_socket.c 31 Dec 2015 21:26:01 -0000
@@ -613,13 +613,14 @@ soreceive(struct socket *so, struct mbuf
{
struct mbuf *m, **mp;
struct mbuf *cm;
- int flags, len, error, s, offset;
+ int flags, len, error, s;
+ u_long offset;
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
int moff, type = 0;
size_t orig_resid = uio->uio_resid;
int uio_error = 0;
- int resid;
+ size_t resid;
mp = mp0;
if (paddr)
@@ -639,8 +640,8 @@ soreceive(struct socket *so, struct mbuf
if (error)
goto bad;
do {
- error = uiomovei(mtod(m, caddr_t),
- (int) min(uio->uio_resid, m->m_len), uio);
+ error = uiomove(mtod(m, caddr_t),
+ ulmin(uio->uio_resid, m->m_len), uio);
m = m_free(m);
} while (uio->uio_resid && error == 0 && m);
bad:
@@ -833,11 +834,9 @@ dontblock:
panic("receive 3");
#endif
so->so_state &= ~SS_RCVATMARK;
- len = uio->uio_resid;
+ len = ulmin(uio->uio_resid, m->m_len - moff);
if (so->so_oobmark && len > so->so_oobmark - offset)
len = so->so_oobmark - offset;
- if (len > m->m_len - moff)
- len = m->m_len - moff;
/*
* If mp is set, just pass back the mbufs.
* Otherwise copy them out via the uio, then free.