Removing an IPv6 address does not remove NDP entries on that
subnet
Ryan Stone
rysto32 at gmail.com
Thu Apr 26 14:03:21 UTC 2012
On Wed, Apr 25, 2012 at 3:59 AM, Li, Qing <qing.li at bluecoat.com> wrote:
> The patch is located at
>
> http://people.freebsd.org/~qingli/nd6_prefix.diff
>
> Please give it a try. I did only basic testing as of now and
> will do more tomorrow.
>
> --Qing
I tested this last night. Unfortunately this seems to be vulnerable
to the same races as our current ARP implementation. First, there is
a race between in6_lltable_lookup and in6_lltable_prefix_free. Here
is a crash that I reproduced last night:
Fatal trap 12: page fault while in kernel mode
cpuid = 0; apic id = 00
fault virtual address = 0x360
fault code = supervisor read data, page not present
instruction pointer = 0x20:0xffffffff808731a2
stack pointer = 0x28:0xffffff80003ea280
frame pointer = 0x28:0xffffff80003ea320
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 22170 (nc)
trap number = 12
panic: page fault
cpuid = 0
Uptime: 1h10m28s
Dumping 108 out of 489 MB:..15%..30%..45%..60%..74%..89%
#0 doadump (textdump=1)
at /usr/home/rstone/freebsd/head/sys/kern/kern_shutdown.c:268
268 if (textdump && textdump_pending) {
(kgdb) #0 doadump (textdump=1)
at /usr/home/rstone/freebsd/head/sys/kern/kern_shutdown.c:268
#1 0xffffffff808753b9 in kern_reboot (howto=260)
at /usr/home/rstone/freebsd/head/sys/kern/kern_shutdown.c:454
#2 0xffffffff80874dea in panic (fmt=0x0)
at /usr/home/rstone/freebsd/head/sys/kern/kern_shutdown.c:642
#3 0xffffffff80b72860 in trap_fatal (frame=0xc, eva=Variable "eva" is not avail
able.
)
at /usr/home/rstone/freebsd/head/sys/amd64/amd64/trap.c:852
#4 0xffffffff80b72a2a in trap_pfault (frame=0xffffff80003ea1d0, usermode=0)
at /usr/home/rstone/freebsd/head/sys/amd64/amd64/trap.c:769
#5 0xffffffff80b731ea in trap (frame=0xffffff80003ea1d0)
at /usr/home/rstone/freebsd/head/sys/amd64/amd64/trap.c:456
#6 0xffffffff80b5d7c3 in calltrap ()
at /usr/home/rstone/freebsd/head/sys/amd64/amd64/exception.S:228
#7 0xffffffff808731a2 in _rw_rlock (rw=0xfffffe00058f3410,
file=0xffffffff80df7e40 "/usr/home/rstone/freebsd/head/sys/netinet6/in6.c",
line=2615) at /usr/home/rstone/freebsd/head/sys/kern/kern_rwlock.c:388
#8 0xffffffff80a27bd9 in in6_lltable_lookup (llt=0xfffffe0002422600,
flags=0, l3addr=0xffffff80003ea6ec)
at /usr/home/rstone/freebsd/head/sys/netinet6/in6.c:2615
#9 0xffffffff80a409c6 in nd6_storelladdr (ifp=0xfffffe000241f000,
m=0xfffffe000503d500, dst=0xffffff80003ea6ec,
desten=0xffffff80003ea430 "\xc0\230\b\005", lle=0xffffff80003ea428)
#10 0xffffffff80936f24 in ether_output (ifp=0xfffffe000241f000,
m=0xfffffe000503d500, dst=0xffffff80003ea6ec, ro=Variable "ro" is not availa
ble.
)
at /usr/home/rstone/freebsd/head/sys/net/if_ethersubr.c:235
#11 0xffffffff80a417df in nd6_output_lle (ifp=0xfffffe000241f000,
origifp=0xfffffe000241f000, m0=0xfffffe000503d500,
dst=0xffffff80003ea6ec, rt0=Variable "rt0" is not available.
)
at /usr/home/rstone/freebsd/head/sys/netinet6/nd6.c:2081
#12 0xffffffff80a41a18 in nd6_output (ifp=Variable "ifp" is not available.
)
at /usr/home/rstone/freebsd/head/sys/netinet6/nd6.c:1828
#13 0xffffffff80a3c400 in ip6_output (m0=0x0, opt=Variable "opt" is
not available.)
at /usr/home/rstone/freebsd/head/sys/netinet6/ip6_output.c:1123
#14 0xffffffff80a4debe in udp6_send (so=Variable "so" is not available.
)
at /usr/home/rstone/freebsd/head/sys/netinet6/udp6_usrreq.c:782
#15 0xffffffff808e97de in sosend_dgram (so=0xfffffe00058d3d48,
addr=0x0, uio=Variable "uio" is not available.
at /usr/home/rstone/freebsd/head/sys/kern/uipc_socket.c:1118
#16 0xffffffff808cddad in soo_write (fp=Variable "fp" is not available.
)
at /usr/home/rstone/freebsd/head/sys/kern/sys_socket.c:102
#17 0xffffffff808c5f25 in dofilewrite (td=0xfffffe00050898c0, fd=3,
fp=0xfffffe0005134000, auio=0xffffff80003eaad0, offset=Variable "offset" is
not available.
) at file.h:271
#18 0xffffffff808c65ac in kern_writev (td=0xfffffe00050898c0, fd=3,
auio=0xffffff80003eaad0)
at /usr/home/rstone/freebsd/head/sys/kern/sys_generic.c:459
#19 0xffffffff808c66c4 in sys_write (td=Variable "td" is not available.
)
at /usr/home/rstone/freebsd/head/sys/kern/sys_generic.c:375
#20 0xffffffff80b71f79 in amd64_syscall (td=0xfffffe00050898c0, traced=0)
at subr_syscall.c:135
#21 0xffffffff80b5daa7 in Xfast_syscall ()
at /usr/home/rstone/freebsd/head/sys/amd64/amd64/exception.S:387
The line in in6_lltable_lookup that it crashes at (in6.c:2615) is the
LLE_RLOCK at the end of the function. From the vmcore I can see that
the lle was destroyed:
(kgdb) print *lle
$1 = {lle_next = {le_next = 0xdeadc0dedeadc0de, le_prev = 0xdeadc0dedeadc0de},
lle_lock = {lock_object = {
lo_name = 0xdeadc0dedeadc0de <Address 0xdeadc0dedeadc0de out of bounds>,
lo_flags = 3735929054, lo_data = 3735929054,
lo_witness = 0xdeadc0dedeadc0de}, rw_lock = 16045693110842147038},
lle_tbl = 0xdeadc0dedeadc0de, lle_head = 0xdeadc0dedeadc0de,
lle_free = 0xdeadc0dedeadc0de, la_hold = 0xdeadc0dedeadc0de,
la_numheld = -559038242, la_expire = -2401050962867404578, la_flags = 49374,
la_asked = 57005, la_preempt = 49374, ln_byhint = 57005, ln_state = -16162,
ln_router = 57005, ln_ntick = -2401050962867404578, lle_refcnt = -559038242,
ll_addr = {mac_aligned = 16045693110842147038, mac16 = {49374, 57005,
49374}}, lle_timer = {ln_timer_ch = {c_links = {sle = {
sle_next = 0xdeadc0dedeadc0de}, tqe = {
tqe_next = 0xdeadc0dedeadc0de, tqe_prev = 0xdeadc0dedeadc0de}},
c_time = -559038242, c_arg = 0xdeadc0dedeadc0de,
c_func = 0xdeadc0dedeadc0de, c_lock = 0xdeadc0dedeadc0de,
c_flags = -559038242, c_cpu = -559038242}, la_timer = {c_links = {sle = {
sle_next = 0xdeadc0dedeadc0de}, tqe = {
tqe_next = 0xdeadc0dedeadc0de, tqe_prev = 0xdeadc0dedeadc0de}},
c_time = -559038242, c_arg = 0xdeadc0dedeadc0de,
c_func = 0xdeadc0dedeadc0de, c_lock = 0xdeadc0dedeadc0de,
c_flags = -559038242, c_cpu = -559038242}}}
The test that I was running was I had one ping6 -f going to an IPv6
address as well as a loop of nc -u. In another terminal I had a
script constantly removing and adding the ipv6 address from which I
was pinging/ncing.
I haven't looked at the netinet6 code too closely yet but if it
follows the netinet implementation in6_lltable_prefix_free should
acquire the afdata_lock on the ifp before touching the lltable.
I haven't tried a test for this yet, but I also believe that
in6_lltable_prefix_free also doesn't drain the callout in the llentry
correctly. I try testing this to confirm this now.
More information about the freebsd-net
mailing list