NetBSD Problem Report #53189

From martin@duskware.de  Mon Apr 16 15:17:39 2018
Return-Path: <martin@duskware.de>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id A4B997A19F
	for <gnats-bugs@gnats.NetBSD.org>; Mon, 16 Apr 2018 15:17:39 +0000 (UTC)
From: martin@NetBSD.org
Reply-To: martin@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: reproducable kernel assertion
X-Send-Pr-Version: 3.95

>Number:         53189
>Category:       kern
>Synopsis:       reproducable kernel assertion
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Apr 16 15:20:00 +0000 2018
>Closed-Date:    Thu May 03 08:04:13 +0000 2018
>Last-Modified:  Thu May 03 08:04:13 +0000 2018
>Originator:     Martin Husemann
>Release:        NetBSD 8.99.14
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD space-truckin.duskware.de 8.99.14 NetBSD 8.99.14 (SUNXI) #35: Mon Apr 16 11:06:40 CEST 2018 martin@night-owl.duskware.de:/usr/src/sys/arch/evbarm/compile/SUNXI evbarm
Architecture: earmv7hfeb
Machine: evbarm
>Description:

Running this test case:

fs/psshfs/t_psshfs (587/738): 4 test cases
    inode_nos: 

reproducably panics my earmv7hfeb and sparc64 machines (but alpha seems
to survive).

[ 939.4386985] panic: m_verify_packet: M_PKTHDR set on secondary mbuf
[ 939.4510184] cpu0: Begin traceback...
[ 939.4510184] 0x9a811dcc: netbsd:db_panic+0x14
[ 939.4587925] 0x9a811de4: netbsd:vpanic+0x194
[ 939.4587925] 0x9a811dfc: netbsd:snprintf
[ 939.4587925] 0x9a811e2c: netbsd:m_verify_packet+0xc8
[ 939.4704970] 0x9a811f14: netbsd:ip6_input+0x790
[ 939.4704970] 0x9a811f4c: netbsd:ip6intr+0x88
[ 939.4805137] 0x9a811fac: netbsd:softint_dispatch+0x114
[ 939.4805137] 0x9d879dbc: netbsd:softint_switch+0x58
[ 939.4909527] 0x9d879dec: netbsd:splx+0xc8
[ 939.4909527] 0x9d879e84: netbsd:sosend+0x780
[ 939.5005167] 0x9d879eac: netbsd:soo_write+0x3c
[ 939.5005167] 0x9d879f04: netbsd:dofilewrite+0x98
[ 939.5114988] 0x9d879f34: netbsd:sys_write+0x70
[ 939.5114988] 0x9d879fac: netbsd:syscall+0x164



>How-To-Repeat:

cd /usr/tests/fs/psshfs && atf-run

>Fix:
n/a

>Release-Note:

>Audit-Trail:
From: "Maxime Villard" <maxv@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: src/sys/kern
Date: Mon, 16 Apr 2018 19:19:51 +0000

 Module Name:	src
 Committed By:	maxv
 Date:		Mon Apr 16 19:19:51 UTC 2018

 Modified Files:
 	src/sys/kern: uipc_mbuf.c

 Log Message:
 Disable the M_PKTHDR check for now. It causes PR/53189 (which is also
 reproducible on i386).

 It seems that someone is giving looutput a malformed chain.


 To generate a diff of this commit:
 cvs rdiff -u -r1.188 -r1.189 src/sys/kern/uipc_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Maxime Villard" <maxv@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: src/sys/netipsec
Date: Tue, 17 Apr 2018 06:23:30 +0000

 Module Name:	src
 Committed By:	maxv
 Date:		Tue Apr 17 06:23:30 UTC 2018

 Modified Files:
 	src/sys/netipsec: ipsec_mbuf.c

 Log Message:
 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.

 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().


 To generate a diff of this commit:
 cvs rdiff -u -r1.22 -r1.23 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-8] src/sys/netipsec
Date: Tue, 17 Apr 2018 15:06:20 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Apr 17 15:06:20 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-8]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #773):

 	sys/netipsec/ipsec_mbuf.c: revision 1.23,1.24

 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.

 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().

 Fix a pretty bad mistake, that has always been there.

 		m_adj(m1, -(m1->m_len - roff));
 		if (m1 != m)
 			m->m_pkthdr.len -= (m1->m_len - roff);

 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.

 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.16 -r1.16.2.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-7] src/sys/netipsec
Date: Tue, 17 Apr 2018 15:10:53 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Apr 17 15:10:53 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-7]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #1599):

 	sys/netipsec/ipsec_mbuf.c: revision 1.23,1.24 (via patch)

 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.

 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().

 Fix a pretty bad mistake, that has always been there.

 		m_adj(m1, -(m1->m_len - roff));
 		if (m1 != m)
 			m->m_pkthdr.len -= (m1->m_len - roff);

 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.

 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.12 -r1.12.30.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->analyzed
State-Changed-By: maxv@NetBSD.org
State-Changed-When: Tue, 17 Apr 2018 15:16:56 +0000
State-Changed-Why:
There are many places that actually put M_PKTHDR on secondary mbufs. In
your case, it was in tcp_build_datapkt().

I've disabled the check, and it will probably remain disabled. It is
difficult to know whether such chains can trigger bugs; they certainly
can, but only few places may be affected. So far, I identified only one
(IPsec), and I fixed it.

For now I believe the assumption should be:

	"M_PKTHDR should not be set on secondary mbufs. However,
	 everybody should be ready to handle this case."


From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-7-1] src/sys/netipsec
Date: Tue, 17 Apr 2018 15:38:12 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Apr 17 15:38:12 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-7-1]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #1599):

 	sys/netipsec/ipsec_mbuf.c: revision 1.23,1.24 (via patch)

 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.

 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().

 Fix a pretty bad mistake, that has always been there.

 		m_adj(m1, -(m1->m_len - roff));
 		if (m1 != m)
 			m->m_pkthdr.len -= (m1->m_len - roff);

 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.

 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.12 -r1.12.42.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-7-0] src/sys/netipsec
Date: Tue, 17 Apr 2018 15:38:57 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Tue Apr 17 15:38:57 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-7-0]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #1599):

 	sys/netipsec/ipsec_mbuf.c: revision 1.23,1.24 (via patch)

 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.

 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().

 Fix a pretty bad mistake, that has always been there.

 		m_adj(m1, -(m1->m_len - roff));
 		if (m1 != m)
 			m->m_pkthdr.len -= (m1->m_len - roff);

 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.

 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.12 -r1.12.34.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "SAITOH Masanobu" <msaitoh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-6] src/sys/netipsec
Date: Wed, 18 Apr 2018 06:59:10 +0000

 Module Name:	src
 Committed By:	msaitoh
 Date:		Wed Apr 18 06:59:10 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-6]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #1545):
 	sys/netipsec/ipsec_mbuf.c: revision 1.23
 	sys/netipsec/ipsec_mbuf.c: revision 1.24
 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.
 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().
 Fix a pretty bad mistake, that has always been there.
          m_adj(m1, -(m1->m_len - roff));
          if (m1 != m)
              m->m_pkthdr.len -= (m1->m_len - roff);
 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.
 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.12 -r1.12.10.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "SAITOH Masanobu" <msaitoh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-6-1] src/sys/netipsec
Date: Wed, 18 Apr 2018 07:17:24 +0000

 Module Name:	src
 Committed By:	msaitoh
 Date:		Wed Apr 18 07:17:24 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-6-1]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #1545):
 	sys/netipsec/ipsec_mbuf.c: revision 1.23
 	sys/netipsec/ipsec_mbuf.c: revision 1.24
 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.
 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().
 Fix a pretty bad mistake, that has always been there.
          m_adj(m1, -(m1->m_len - roff));
          if (m1 != m)
              m->m_pkthdr.len -= (m1->m_len - roff);
 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.
 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.12 -r1.12.24.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: "SAITOH Masanobu" <msaitoh@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/53189 CVS commit: [netbsd-6-0] src/sys/netipsec
Date: Wed, 18 Apr 2018 07:17:48 +0000

 Module Name:	src
 Committed By:	msaitoh
 Date:		Wed Apr 18 07:17:48 UTC 2018

 Modified Files:
 	src/sys/netipsec [netbsd-6-0]: ipsec_mbuf.c

 Log Message:
 Pull up following revision(s) (requested by maxv in ticket #1545):
 	sys/netipsec/ipsec_mbuf.c: revision 1.23
 	sys/netipsec/ipsec_mbuf.c: revision 1.24
 Don't assume M_PKTHDR is set only on the first mbuf of the chain. It
 should, but it looks like there are several places that can put M_PKTHDR
 on secondary mbufs (PR/53189), so drop this assumption right now to
 prevent further bugs.
 The check is replaced by (m1 != m), which is equivalent to the previous
 code: we want to modify m->m_pkthdr.len only when 'm' was not passed in
 m_adj().
 Fix a pretty bad mistake, that has always been there.
          m_adj(m1, -(m1->m_len - roff));
          if (m1 != m)
              m->m_pkthdr.len -= (m1->m_len - roff);
 This is wrong: m_adj will modify m1->m_len, so we're using a wrong value
 when manually adjusting m->m_pkthdr.len.
 Because of that, it is possible to exploit the attack I described in
 uipc_mbuf.c::rev1.182. The exploit is more complicated, but works 100%
 reliably.


 To generate a diff of this commit:
 cvs rdiff -u -r1.12 -r1.12.16.1 src/sys/netipsec/ipsec_mbuf.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: analyzed->closed
State-Changed-By: maxv@NetBSD.org
State-Changed-When: Thu, 03 May 2018 08:04:13 +0000
State-Changed-Why:
Close this PR. I disabled the KASSERT, because several places put M_PKTHDR
on secondary mbufs, and we're in such a state that it is not possible to
guarantee that this KASSERT is not fired on a regular basis.

So we must assume that the assumption does not hold, even though it would
be theoretically consistent if it did. I added a comment in uipc_mbuf.c.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.43 2018/01/16 07:36:43 maya Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2017 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.