--- a/sys/kern/libmchain/subr_mchain.c +++ b/sys/kern/libmchain/subr_mchain.c @@ -73,6 +73,8 @@ struct mbuf *m; m = m_gethdr(M_WAITOK, MT_DATA); + if (m == NULL) + return ENOBUFS; m->m_pkthdr.rcvif = NULL; m->m_len = 0; mb_initm(mbp, m); @@ -129,6 +131,8 @@ m = mbp->mb_cur; if (mbp->mb_mleft < size) { mn = m_get(M_WAITOK, MT_DATA); + if (mn == NULL) + return NULL; mbp->mb_cur = m->m_next = mn; m = mn; m->m_len = 0; @@ -206,6 +210,8 @@ if (m->m_next == NULL) m->m_next = m_getc(size, M_WAITOK, MT_DATA); m = m->m_next; + if (m == NULL) + return ENOBUFS; mleft = M_TRAILINGSPACE(m); continue; } @@ -306,6 +312,8 @@ struct mbuf *m; m = m_gethdr(M_WAITOK, MT_DATA); + if (m == NULL) + return ENOBUFS; m->m_pkthdr.rcvif = NULL; m->m_len = 0; md_initm(mdp, m); @@ -327,6 +335,8 @@ m_freem(mdp->md_top); mdp->md_top = NULL; } + mdp->md_cur = NULL; + mdp->md_pos = NULL; } /* @@ -512,10 +522,30 @@ { struct mbuf *m = mdp->md_cur, *rm; + int remain = 0; + struct mbuf *x; + u_char *pos; + + /* Verify the chain actually holds size bytes BEFORE m_copym + * (m_copym KASSERTs on INVARIANTS kernels for oversized requests + * and silently truncates on production kernels). */ + x = m; + pos = mdp->md_pos; + while (x) { + remain += mtod(x, u_char*) + x->m_len - pos; + pos = mtod(x, u_char*); + x = x->m_next; + } + if (size > remain) + return EBADRPC; + rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAITOK); if (rm == NULL) return EBADRPC; - md_get_mem(mdp, NULL, size, MB_MZERO); + if (md_get_mem(mdp, NULL, size, MB_MZERO) != 0) { + m_freem(rm); + return EBADRPC; + } *ret = rm; return 0; }