Bug 93170

Summary: Changing system date causes panic in nd6_timer
Product: Base System Reporter: Kris Kennaway <kris>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 7.0-CURRENT   
Hardware: Any   
OS: Any   

Description Kris Kennaway freebsd_committer freebsd_triage 2006-02-11 06:20:07 UTC
I ran ntpdate on an amd64 system with ipv6 enabled and a skewed clock
(ntpdate stepped it back by about an hour), and immediately got a
use-after-free panic in ifaddr.  When I rebooted with memguard enabled
on this malloc type and retried, I got this panic upon changing the
date forward, then back, then forward again (also note the garbage
return data from ntpdate):

# date 200606011200
Thu Jun  1 12:00:00 UTC 2006
# ntpdate ntp.apple.com
16 Jan 00:40:18 ntpdate[612]: step time server 17.254.0.28 offset -~9000pm6}9426375508.195959 sec
# date 200606011200
Thu Jun  1 12:00:00 UTC 2006

Fatal trap 12: page fault while in kernel mode
cpuid = 0; apic id = 00
fault virtual address   = 0xffffffff91bd2198
fault code              = supervisor write, protection violation
instruction pointer     = 0x8:0xffffffff80321346
stack pointer           = 0x10:0xffffffffbcfa1b60
frame pointer           = 0x10:0xffffffffbcfa1b90
code segment            = base rx0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 14 (swi4: clock sio)
[thread pid 14 tid 100010 ]
Stopped at      nd6_timer+0x106:        movl    %eax,0x198(%rbx)
db> wh
Tracing pid 14 tid 100010 td 0xffffff03e15d6c30
nd6_timer() at nd6_timer+0x106
softclock() at softclock+0x279
ithread_execute_handlers() at ithread_execute_handlers+0x12f
ithread_loop() at ithread_loop+0x99
fork_exit() at fork_exit+0xdf
fork_trampoline() at fork_trampoline+0xe
--- trap 0, rip = 0, rsp = 0xffffffffbcfa1d40, rbp = 0 ---

Unfortunately I can't dump on this system, but:

(kgdb) list *(nd6_timer+0x106)
0xffffffff80321346 is in nd6_timer (../../../netinet6/nd6.c:585).
580                                     goto addrloop; /* XXX: see below */
581                     }
582                     if (IFA6_IS_DEPRECATED(ia6)) {
583                             int oldflags = ia6->ia6_flags;
584
585                             ia6->ia6_flags |= IN6_IFF_DEPRECATED;
586
587                             /*
588                              * If a temporary address has just become deprecated,
589                              * regenerate a new one if possible.

How-To-Repeat: 
Run the above two commands in a loop
Comment 1 dwmalone 2006-02-11 16:59:38 UTC
I'm fairly sure I know what's going on here, as I've seen a few
more of these panics. There seems to be a bundle of IPv6 neighbour
discovery code that uses splnet() and hasn't had any locking added
to it yet. One of these bits of code is walking some global lists
and is obviously getting into trouble.

I believe this same code is also causing dirhash panics people have
reported 'cos some of the memory it is using is getting reused by
dirhash.

I sent the message below to Robert a while ago - since I haven't
heard back from him, I'm going to have a go at adding some locking.

	David.

Subject: IPv6 address list locking.
Date: Fri, 20 Jan 2006 17:48:57 +0000
From: David Malone <dwmalone@maths.tcd.ie>
Message-ID:  <200601201748.aa69772@salmon.maths.tcd.ie>

Hi Robert,

I've been trying to trace some use-after-free problems that have
paniced the kernel in dirhash. A few weeks ago I got a panic that
indicated that the ifnet malloc pool might be the problem. Using
memguard on my desktop in Dublin paniced today and, judging by the
reports of the guy who reset it for me, it paniced at nd6_timer+0xe8.

This looks like a bit of nd6_timer code that accesses a global list
of IPv6 addresses stored in a variable called in6_ifaddr. Rather
annoyingly this variable has the same name as a structure, so it
is difficult to grep for. However, I don't see any locking of
accesses to this variable.

Do you have a scheme for locking globals like this in the IPv6
stack? Does it look like nd6_timeout is violaing this locking?

	David.

in6.c:  for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
in6.c:  for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
in6.c:  for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
in6_src.c:      for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
nd6.c:  for (ia6 = in6_ifaddr; ia6; ia6 = nia6) {
nd6.c:                  for (ia = in6_ifaddr; ia; ia = ia_next) {
nd6_rtr.c:      for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
nd6_rtr.c:              for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
nd6_rtr.c:              for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
nd6_rtr.c:      for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
Comment 2 K. Macy freebsd_committer freebsd_triage 2007-11-20 06:59:13 UTC
State Changed
From-To: open->feedback


Does this still happen?
Comment 3 Mark Linimon freebsd_committer freebsd_triage 2008-03-02 02:40:46 UTC
State Changed
From-To: feedback->suspended

Feedback was not received, but it does not sound as though this problem 
has been fixed.  Mark as suspended since no one seems to be working on it.
Comment 4 Bruce Cran freebsd_committer freebsd_triage 2009-03-28 23:43:52 UTC
State Changed
From-To: suspended->closed

Fixed in rev 1.63 of src/sys/netinet6/nd6.c