Properly handle read-only clusters in m_pullup(9).
authorbluhm <bluhm@openbsd.org>
Tue, 18 Jan 2022 12:38:21 +0000 (12:38 +0000)
committerbluhm <bluhm@openbsd.org>
Tue, 18 Jan 2022 12:38:21 +0000 (12:38 +0000)
If the first mbuf of a chain in m_pullup is a cluster, check if the
cluster is read-only (shared or an external buffer).  If so, don't
touch it and create a new mbuf for the pullup data.

This restores original 4.4BSD m_pullup, that not only returned
contiguous mbuf data of the specified length, but also converted
read-only clusters into writeable memory.  The latter feature was
lost during some refactoring.

from ehrhardt@; tested by weerd@; OK stsp@ bluhm@ claudio@

sys/kern/uipc_mbuf.c

index 648282d..bbb6932 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_mbuf.c,v 1.279 2021/03/06 09:20:49 jsg Exp $     */
+/*     $OpenBSD: uipc_mbuf.c,v 1.280 2022/01/18 12:38:21 bluhm Exp $   */
 /*     $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $   */
 
 /*
@@ -939,8 +939,6 @@ m_pullup(struct mbuf *m0, int len)
 
        head = M_DATABUF(m0);
        if (m0->m_len == 0) {
-               m0->m_data = head;
-
                while (m->m_len == 0) {
                        m = m_free(m);
                        if (m == NULL)
@@ -954,10 +952,11 @@ m_pullup(struct mbuf *m0, int len)
        tail = head + M_SIZE(m0);
        head += adj;
 
-       if (len <= tail - head) {
-               /* there's enough space in the first mbuf */
-
-               if (len > tail - mtod(m0, caddr_t)) {
+       if (!M_READONLY(m0) && len <= tail - head) {
+               /* we can copy everything into the first mbuf */
+               if (m0->m_len == 0) {
+                       m0->m_data = head;
+               } else if (len > tail - mtod(m0, caddr_t)) {
                        /* need to memmove to make space at the end */
                        memmove(head, mtod(m0, caddr_t), m0->m_len);
                        m0->m_data = head;
@@ -965,7 +964,7 @@ m_pullup(struct mbuf *m0, int len)
 
                len -= m0->m_len;
        } else {
-               /* the first mbuf is too small so make a new one */
+               /* the first mbuf is too small or read-only, make a new one */
                space = adj + len;
 
                if (space > MAXMCLBYTES)