NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/60491: arp creates state for invalid messages
The following reply was made to PR kern/60491; it has been noted by GNATS.
From: Manuel Bouyer <bouyer%antioche.eu.org@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: kern-bug-people%netbsd.org@localhost, gnats-admin%netbsd.org@localhost, netbsd-bugs%netbsd.org@localhost,
campbell+netbsd%mumble.net@localhost
Subject: Re: kern/60491: arp creates state for invalid messages
Date: Wed, 28 Oct 2026 15:59:31 +0100
On Wed, Oct 21, 2026 at 04:00:52PM +0200, Manuel Bouyer wrote:
> [ 19315.4531276] --- interrupt ---
>
> The change is:
> - KASSERT(op == ARPOP_REPLY || op == ARPOP_REQUEST);
> + KASSERTMSG(op == ARPOP_REPLY || op == ARPOP_REQUEST,
> + "op not REQUEST or REPLY: %d", op);
>
> Looks like m_makewritable() may be at fault here.
Now running with this patch:
? sys/netinet/if_arp.c.assertmsg
? sys/netinet/if_arp.c.assertmsg2
Index: sys/netinet/if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.321
diff -u -p -u -r1.321 if_arp.c
--- sys/netinet/if_arp.c 23 Jul 2026 21:49:19 -0000 1.321
+++ sys/netinet/if_arp.c 28 Oct 2026 13:56:37 -0000
@@ -742,6 +742,8 @@ arpintr(void *arg __unused)
ARP_STATINC(ARP_STAT_RCVBADPROTO);
goto free;
}
+ KASSERT(ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REPLY ||
+ ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REQUEST);
in_arpinput(m);
continue;
default:
@@ -793,12 +795,16 @@ in_arpinput(struct mbuf *m)
int s;
char ipbuf[INET_ADDRSTRLEN];
bool find_source, do_dad;
+ struct mbuf *om = m;
+ KASSERT(ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REPLY ||
+ ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REQUEST);
if (__predict_false(m_makewritable(&m, 0, m->m_pkthdr.len, M_DONTWAIT)))
goto out;
ah = mtod(m, struct arphdr *);
op = ntohs(ah->ar_op);
- KASSERT(op == ARPOP_REPLY || op == ARPOP_REQUEST);
+ KASSERTMSG(op == ARPOP_REPLY || op == ARPOP_REQUEST,
+ "op not REQUEST or REPLY: %d %p %p", op, m, om);
if (ah->ar_pln != sizeof(struct in_addr))
goto out;
@@ -1895,7 +1901,11 @@ in_revarpinput(struct mbuf *m)
switch (op) {
case ARPOP_REQUEST:
case ARPOP_REPLY: /* per RFC */
+ KASSERT(ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REPLY ||
+ ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REQUEST);
m_put_rcvif(rcvif, &s);
+ KASSERT(ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REPLY ||
+ ntohs(mtod(m, struct arphdr *)->ar_op) == ARPOP_REQUEST);
in_arpinput(m);
return;
case ARPOP_REVREPLY:
I got this panic:
[ 603891.0584629] panic: kernel diagnostic assertion "op == ARPOP_REPLY || op == ARPOP_REQUEST" failed: file "/dsk/l1/misc/bouyer/HEAD/clean/src/sys/netinet/if_arp.c", line 806 op not REQUEST or REPLY: 65535 0xffff85ca8b4ff7e0 0xffff85ca73cdebc0
[ 603891.1323430] cpu0: Begin traceback...
[ 603891.1440383] vpanic() at netbsd:vpanic+0x18d
[ 603891.1584130] kern_assert() at netbsd:kern_assert+0x61
[ 603891.1722752] in_arpinput() at netbsd:in_arpinput+0x52c
[ 603891.1887326] arpintr() at netbsd:arpintr+0x11c
[ 603891.1995472] softint_dispatch() at netbsd:softint_dispatch+0x124
db{0}> show mbuf /v 0xffff85ca8b4ff7e0
MBUF(0) 0xffff85ca8b4ff7e0
data=0xffff85ca8b4ff850, len=0, type=1, flags=0x102<PKTHDR,BCAST>
owner=0x0, next=0xffff85ca73cdebc0, nextpkt=0x0
leadingspace=0, trailingspace=400, readonly=0
pktlen=46, rcvif=0xffff8f0001f66060, csum_flags=0, csum_data=0x0, segsz=0
ETHER: DST = 00:01:08:00:06:04
ETHER: SRC = 00:01:f4:cf:e2:d4
ETHER: TYPE = 0x4b00(unknown)
offset 0014: 84 e3 67 01
offset 0018: 00 00 00 00
offset 0022: 00 00 84 e3
offset 0026: 67 9e 00 00
offset 0030: 00 00 00 00
offset 0034: 00 00 00 00
offset 0038: 00 00 00 00
offset 0042: 00 00 00 00
db{0}> show mbuf /v 0xffff85ca73cdebc0
MBUF(0) 0xffff85ca73cdebc0
data=0xffff85ca73ac680e, len=46, type=1, flags=0x9000101<EXT,BCAST,EXT_CLUSTER
,EXT_RW>
owner=0x0, next=0x0, nextpkt=0x0
leadingspace=14, trailingspace=1988, readonly=0
ext_refcnt=1, ext_buf=0xffff85ca73ac6800, ext_size=2048, ext_free=0x0, ext_arg
=0x0
ETHER: DST = 00:01:08:00:06:04
ETHER: SRC = 00:01:f4:cf:e2:d4
ETHER: TYPE = 0x4b00(unknown)
offset 0014: 84 e3 67 01
offset 0018: 00 00 00 00
offset 0022: 00 00 84 e3
offset 0026: 67 9e 00 00
offset 0030: 00 00 00 00
offset 0034: 00 00 00 00
offset 0038: 00 00 00 00
offset 0042: 00 00 00 00
So it looks like that after m_makewritable(), we end up with a mbuf with no
data (len = 0), but which is chained with our old mbuf. But the data here don't
make much sense; these ethernet addresses are unknown on my network and
the ether type doesn't make sense either.
But if we look at 0xffff85ca73ac6800 (the start of the mbuf cluster area):
db{0}> x/x 0xffff85ca73ac6800
ffff85ca73ac6800: ffffffff
db{0}>
ffff85ca73ac6804: cff4ffff
db{0}>
ffff85ca73ac6808: 4bd4e2
db{0}>
ffff85ca73ac680c: 1000608
db{0}>
ffff85ca73ac6810: 4060008
db{0}>
ffff85ca73ac6814: cff40100
db{0}>
ffff85ca73ac6818: 4bd4e2
db{0}>
ffff85ca73ac681c: 167e384
db{0}>
ffff85ca73ac6820: 0
db{0}>
ffff85ca73ac6824: e3840000
This gives:
DST: ff:ff:ff:ff:ff:ff
SRC: f4:cf:e2:d4:4b:00 (this is a known address on my network)
ETYPE: 0x0806 (this is ETHERTYPE_ARP)
ar_hrd: 0001 (ARPHRD_ETHER)
This makes more sense if we assume fields after ETYPE have been overwritten
(we reached the area pointed to by mbuf->data)
I didn't look closely enough at m_makewritable() to explain how we could end
up in this situation.
Anyway I don't think we can use mtod() on a mbuf whose len is 0, and it doens't
looks like m_makewritable() garantees that the first mbuf will contain the
whole arp header.
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Home |
Main Index |
Thread Index |
Old Index