Index: sys/kern/uipc_mbuf2.c =================================================================== --- sys/kern/uipc_mbuf2.c +++ sys/kern/uipc_mbuf2.c @@ -451,3 +451,68 @@ } return 1; } + + +#ifdef INVARIANTS +/** + * Test for FreeBSD-SA-19:22.mbuf. Given 3 mbufs, m0, m1, m2 in a sequence + * starting with m0, this vulnerability will repro if the user requests + * m_pulldown() of data in the sequence if: + * 1. The total length of the requested data stored across m0 and m1 cannot be + * appended to the end of m0 nor prepended to the beginning of m1. + * 2. Part of the data requested is stored in m2 also (the length of the data + * requested runs off the end of m1). + */ +static int +test_sa_19_22_mbuf_handler(SYSCTL_HANDLER_ARGS) +{ + const size_t TEST_DATA_LEN = 12; + const size_t TEST_BUF_LEN = MLEN - 4 + TEST_DATA_LEN + 1; + + char test_buf[MLEN - 4 + TEST_DATA_LEN + 1]; + char *TEST_DATA = "abcdefghijkl"; + char *d; + + struct mbuf *m0, *m1, *m2, *m3; + int ret, off; + + memset(test_buf, 'z', MLEN - 4); + memcpy(test_buf + MLEN - 4, TEST_DATA, TEST_DATA_LEN + 1); + + MGET(m0, M_WAITOK, MT_DATA); + MGET(m1, M_WAITOK, MT_DATA); + MGET(m2, M_WAITOK, MT_DATA); + + /* Stuff m0 to MLEN so that there's no trailing space left. */ + m_copyback(m0, 0, MLEN, (caddr_t)test_buf); + /* Trim the first 4 bytes of m1 so there's some headspace. */ + m_copyback(m1, 0, 8, (caddr_t)(test_buf + MLEN - 4)); + m_adj(m1, 4); + + m_copyback(m2, 0, 5, (caddr_t)(test_buf + TEST_BUF_LEN - 5)); + + m0->m_next = m1; + m1->m_next = m2; + + m3 = m_pulldown(m0, MLEN - 4, TEST_DATA_LEN, &off); + if (m3 == NULL) { + m_freem(m0); + return ENOMEM; + } + + d = mtod(m3, char *); + + if (!memcmp(d, TEST_DATA, TEST_DATA_LEN)) + ret = 0; + else + ret = 1; + + m_freem(m0); + return SYSCTL_OUT(req, &ret, sizeof(ret)); +} + +SYSCTL_PROC(_debug, OID_AUTO, test_sa_19_22_mbuf, + (CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE), NULL, 0, + test_sa_19_22_mbuf_handler, "I", + "Check for repro of FreeBSD-SA-19:22.mbuf"); +#endif Index: tests/sys/kern/Makefile =================================================================== --- tests/sys/kern/Makefile +++ tests/sys/kern/Makefile @@ -24,6 +24,7 @@ ATF_TESTS_C+= pdeathsig ATF_TESTS_SH+= coredump_phnum_test +ATF_TESTS_SH+= sa_19_22_mbuf_test BINDIR= ${TESTSDIR} PROGS+= coredump_phnum_helper Index: tests/sys/kern/sa_19_22_mbuf_test.sh =================================================================== --- /dev/null +++ tests/sys/kern/sa_19_22_mbuf_test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env atf-sh + +# Verify FreeBSD-SA-19:22:mbuf does not repro. + +atf_test_case sa_19_22_mbuf + +sa_19_22_mbuf_body() +{ + # sysctl has value 1 if issue is present, 0 if not. + atf_check -o inline:"0\n" sysctl -n debug.test_sa_19_22_mbuf +} + +atf_init_test_cases() +{ + atf_add_test_case sa_19_22_mbuf +}