mbuf: avoid assertion failure when splitting mbuf cluster

From OpenBSD:

	commit 7b4d35e0a60ba1dd4daf4b1c2932020a22463a89
	Author: bluhm <bluhm@openbsd.org>
	Date:   Fri Oct 20 16:25:15 2023 +0000

	    Avoid assertion failure when splitting mbuf cluster.

	    m_split() calls m_align() to initialize the data pointer of newly
	    allocated mbuf.  If the new mbuf will be converted to a cluster,
	    this is not necessary.  If additionally the new mbuf is larger than
	    MLEN, this can lead to a panic.
	    Only call m_align() when a valid m_data is needed.  This is the
	    case if we do not refecence the existing cluster, but memcpy() the
	    data into the new mbuf.

	    Reported-by: syzbot+0e6817f5877926f0e96a@syzkaller.appspotmail.com
	    OK claudio@ deraadt@

The issue is harmless if DIAGNOSTIC is not enabled.

XXX pullup-10
XXX pullup-9
This commit is contained in:
ozaki-r 2023-11-27 02:50:27 +00:00
parent c9712969ab
commit e629b37024
1 changed files with 4 additions and 10 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: uipc_mbuf.c,v 1.251 2023/04/12 06:48:08 riastradh Exp $ */ /* $NetBSD: uipc_mbuf.c,v 1.252 2023/11/27 02:50:27 ozaki-r Exp $ */
/* /*
* Copyright (c) 1999, 2001, 2018 The NetBSD Foundation, Inc. * Copyright (c) 1999, 2001, 2018 The NetBSD Foundation, Inc.
@ -62,7 +62,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_mbuf.c,v 1.251 2023/04/12 06:48:08 riastradh Exp $"); __KERNEL_RCSID(0, "$NetBSD: uipc_mbuf.c,v 1.252 2023/11/27 02:50:27 ozaki-r Exp $");
#ifdef _KERNEL_OPT #ifdef _KERNEL_OPT
#include "opt_mbuftrace.h" #include "opt_mbuftrace.h"
@ -1343,10 +1343,7 @@ m_split_internal(struct mbuf *m0, int len0, int wait, bool copyhdr)
len_save = m0->m_pkthdr.len; len_save = m0->m_pkthdr.len;
m0->m_pkthdr.len = len0; m0->m_pkthdr.len = len0;
if (m->m_flags & M_EXT) if ((m->m_flags & M_EXT) == 0 && remain > MHLEN) {
goto extpacket;
if (remain > MHLEN) {
/* m can't be the lead packet */ /* m can't be the lead packet */
m_align(n, 0); m_align(n, 0);
n->m_len = 0; n->m_len = 0;
@ -1357,8 +1354,6 @@ m_split_internal(struct mbuf *m0, int len0, int wait, bool copyhdr)
return NULL; return NULL;
} }
return n; return n;
} else {
m_align(n, remain);
} }
} else if (remain == 0) { } else if (remain == 0) {
n = m->m_next; n = m->m_next;
@ -1369,14 +1364,13 @@ m_split_internal(struct mbuf *m0, int len0, int wait, bool copyhdr)
if (n == NULL) if (n == NULL)
return NULL; return NULL;
MCLAIM(n, m->m_owner); MCLAIM(n, m->m_owner);
m_align(n, remain);
} }
extpacket:
if (m->m_flags & M_EXT) { if (m->m_flags & M_EXT) {
n->m_data = m->m_data + len; n->m_data = m->m_data + len;
MCLADDREFERENCE(m, n); MCLADDREFERENCE(m, n);
} else { } else {
m_align(n, remain);
memcpy(mtod(n, void *), mtod(m, char *) + len, remain); memcpy(mtod(n, void *), mtod(m, char *) + len, remain);
} }