Hace algún tiempo, fui a ver un servidor, que bajo FreeBSD 7.2 actuaba como firewall utilizando IPFilter y hacia NAT entre otros equipos de la LAN interna. El mismo había tenido unos reinicios inesperados, sin saber el verdadero origen de los mismos. Esto de por si representaba un problema, ya que incrementaba el downtime del mismo, y debiendo a que el las particiones del OS se encontraban bajo UFS, podía corromper los filesystems y forzar a la ejecución de fsck entre reboot y reboot.
Al acceder al equipo, encuentro en /var/log/messages.1 que el equipo, había booteado a las 9:42 AM del día 4 de Diciembre, por lo cual fijandome en logs anteriores encontré que el mismo había entrado en panic, y que había generado el coredump: vmcore.8.
En el directorio /var/crash encuentro varios coredumps de periodos de tiempos comprendidos entre el año 2008 y 2011.
Por lo cual comienzo a debuggear el coredump generado (vmcore.8), con kgdb. Al ejecutar esto, me muestra la siguiente información:
Fatal trap 12: page fault while in kernel modeSe puede apreciar que se intenta cargar una página de memoria, que parece no estar presente, o incorrectamente mapeada, por lo cual, el kernel crashea con page fault, ejecutando el trap 12.
cpuid = 0; apic id = 00
fault virtual address = 0x4
fault code = supervisor read, page not present
instruction pointer = 0x20:0xc33ac8ab
stack pointer = 0x28:0xc2f909bc
frame pointer = 0x28:0xc2f90a38
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, def32 1, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 21 (irq17: xl1)
trap number = 12
panic: page fault
cpuid = 0
Uptime: 11h41m30s
Physical memory: 499 MB
Dumping 83 MB: 68 52 36 20 4
#0 doadump () at pcpu.h:196
196 __asm __volatile("movl %%fs:0,%0" : "=r" (td));
En la línea current process, se encuentra que es en el IRQ 17, en lo que es la interfaz xl1 conectada al equipo. Al hacer ifconfig xl1, encontramos lo siguiente:
xl1: flags=8843metric 0 mtu 1500
options=9
ether 00:10:4b:c6:65:3b
inet 190.122.08.91 netmask 0xfffffff8 broadcast 190.122.08.124
media: Ethernet autoselect (100baseTX)
status: active
Dentro de kgdb, al hacer un backtrace encuentro lo siguiente:
(kgdb) bt
#0 doadump () at pcpu.h:196
#1 0xc07ec1f7 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:418
#2 0xc07ec4c9 in panic (fmt=Variable "fmt" is not available.
) at /usr/src/sys/kern/kern_shutdown.c:574
#3 0xc0b18f2c in trap_fatal (frame=0xc2f9097c, eva=4) at /usr/src/sys/i386/i386/trap.c:939
#4 0xc0b191b0 in trap_pfault (frame=0xc2f9097c, usermode=0, eva=4) at /usr/src/sys/i386/i386/trap.c:852
#5 0xc0b19c2c in trap (frame=0xc2f9097c) at /usr/src/sys/i386/i386/trap.c:530
#6 0xc0afe20b in calltrap () at /usr/src/sys/i386/i386/exception.s:159
#7 0xc33ac8ab in nat_new () from /boot/kernel/ipl.ko
#8 0xc33b0574 in fr_checknatin () from /boot/kernel/ipl.ko
#9 0xc33c9723 in fr_check () from /boot/kernel/ipl.ko
#10 0xc33c170e in fr_check_wrapper () from /boot/kernel/ipl.ko
#11 0xc0897418 in pfil_run_hooks (ph=0xc0d03100, mp=0xc2f90be8, ifp=0xc3191400, dir=1, inp=0x0) at /usr/src/sys/net/pfil.c:78
#12 0xc08d76e2 in ip_input (m=0xc32eaa00) at /usr/src/sys/netinet/ip_input.c:416
#13 0xc0895bb5 in netisr_dispatch (num=2, m=0xc32eaa00) at /usr/src/sys/net/netisr.c:185
#14 0xc088bb51 in ether_demux (ifp=0xc3191400, m=0xc32eaa00) at /usr/src/sys/net/if_ethersubr.c:834
#15 0xc088bf43 in ether_input (ifp=0xc3191400, m=0xc32eaa00) at /usr/src/sys/net/if_ethersubr.c:692
#16 0xc09ec818 in xl_rxeof (sc=0xc3199000) at /usr/src/sys/pci/if_xl.c:2022
#17 0xc09eed24 in xl_intr (arg=0xc3199000) at /usr/src/sys/pci/if_xl.c:2257
#18 0xc07c9f5b in ithread_loop (arg=0xc3190300) at /usr/src/sys/kern/kern_intr.c:1088
#19 0xc07c6a59 in fork_exit (callout=0xc07c9da0, arg=0xc3190300, frame=0xc2f90d38) at /usr/src/sys/kern/kern_fork.c:810
#20 0xc0afe2b0 in fork_trampoline () at /usr/src/sys/i386/i386/exception.s:264
(kgdb) p *0xc33ac8ab
$1 = 251937163
Lo que indica que el crash se produce al acceder a la función nat_new(), mapeado su segmento .text en la dirección 0xc33ac8ab, cuyo código de fuente se encuentra en /usr/src/sys/contrib/ipfilter/netinet/ip_nat.c, en el cual se realiza el encapsulado, fragmentación y traslado de direcciones, para aplicar NAT.
Dicha función se compone de tres secciones:
- Crear una nueva estructura NAT para la regla MAP para las conexiones entrantes.
- Crear una nueva estructura NAT para la regla RDR para las conexiones salientes.
- Construir dicha estructuras y ponerla dentro de la tabla de NAT.
- np(I) -> Puntero a la regla de NAT
- fin(I) -> Puntero a la información paquete, obtenido en las funciones anteriores.
- flags(i) -> Que se encuentran en el último paquete.
- direction(i) -> Dirección del paquete (IN/OUT) para luego la función new_nat() pueda aplicar MAP o RDR.
Para reproducir el problema, se puede hacer lo siguiente:
Se debe crear un archivo llamado tcpfrag.nat, con el siguiente contenido:
[out,xl1]Luego ejecutando:
4500 00a0 0000 0100 3f06 7555 0101 0101 0201 0101
0401 0019 0000 0000 0000 0000 5010 2000 86b7 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
#: ipftest -F hex -N tcpfrag.nat -i tcpfrag.pktEsto es debido a que en el archivo /etc/ipnat.rules, se encuentran cargadas las siguientes reglas sobre la interfaz de red xl1.
bimap xl1 172.18.2.12/32 -> 190.122.08.91/32Según busque entre los reportes de bugs de FreeBSD, el problema existe y el motivo del problema puede ser debido a que un fragmento TCP que matchee con una regla que es para otro cualquier protocolo, debido a que se duplica su entrada en la cache de NAT.
bimap xl1 172.18.2.13/32 -> 190.122.08.91/32
bimap xl1 172.18.2.14/32 -> 190.122.08.91/32
bimap xl1 172.18.2.15/32 -> 190.122.08.91/32
Dicha referencia puede ser encontrada en el siguiente link:
http://www.freebsd.org/cgi/query-pr.cgi?pr=137392
Dicho bug, se encuentra abierto al momento, y lleva reportado ya 2 años (Agosto del 2009), fue categorizado como "Medio". Debido a que es posible generar en un host remoto, paquetes con una payload ligeramente modificada y producir una denegación de servicio en el servidor, haciendo entrar en panic el kernel, y produciendo por lo tanto un reboot forzado del mismo.
Según encontré, aún no hay ningún parche oficial para solucionar dicho problema, y en esta empresa se necesita la utilización de las reglas bimap, por lo cual, la única solución accesible y razonable que encontré es migrar dichas reglas a Packet Filter. En el caso de Solaris, no tuve la oportunidad de testearlo, si alguién lo hace, por favor me avisa!.
Dicho bug, se encuentra abierto al momento, y lleva reportado ya 2 años (Agosto del 2009), fue categorizado como "Medio". Debido a que es posible generar en un host remoto, paquetes con una payload ligeramente modificada y producir una denegación de servicio en el servidor, haciendo entrar en panic el kernel, y produciendo por lo tanto un reboot forzado del mismo.
Según encontré, aún no hay ningún parche oficial para solucionar dicho problema, y en esta empresa se necesita la utilización de las reglas bimap, por lo cual, la única solución accesible y razonable que encontré es migrar dichas reglas a Packet Filter. En el caso de Solaris, no tuve la oportunidad de testearlo, si alguién lo hace, por favor me avisa!.
Hola, perdoname que te corrija.
ResponderEliminarEl bug donde lo viste, esta marcado como ducplicado, y si vas al link del duplicado, dice cerrado, si fue arreglado.
http://www.freebsd.org/cgi/query-pr.cgi?pr=3D1316=
Saludos.
Gracias! Arme este post basándome en un informé que realice para octubre del año pasado, hasta entonces se encontraba abierto. Gracias por la info!.
ResponderEliminarDe nada, aunque, me corrijo!!, mira, si bien el bug fue cerrado por duplicado, fue "mal cerrado".
ResponderEliminarY por lo que veo, existe aun incluso en freebsd 8.2 stable:
http://lists.freebsd.org/pipermail/freebsd-net/2011-February/028064.html
o kern/138177 net [ipfilter] FreeBSD crashing repeatedly in ip_nat.c:257
Es muy comico, los bsdderos dicen que *BSD es mas seguro que GNU/Linux, y sin fallos, y esto?, te crashean el server de forma remota :P.
Esta activo, pregunte en su canal (#freebsd freenode):
hi folks, this bug is fixed in 8.2 stable?.
http://lists.freebsd.org/pipermail/freebsd-net/2011-February/028064.html
o kern/138177 net [ipfilter] FreeBSD crashing repeatedly in ip_nat.c:257
http://www.freebsd.org/cgi/query-pr.cgi?pr=138177
wow
critical and open
from 2009
anon: hard to say, there's not enough feedback from the submitter to determine if it's fixed or not.
En vista de eso, y la lista que podrás ver de fallos en network que aún posee FreeBSD, se podría decir que la seguridad que ostentan los de FreeBSD es una falsa seguridad, solo basada en la fama de OpenBSD?.
Tenes idea si OpenBSD posee el mismo fallo?.
Saludos y gracias!.
Excelente info :-) En OpenBSD no lo experimenté. De todas formas IPF es algo que ya esta deprecado, ya que esto se soluciona migrando a PF que ofrece ventajas prácticas aún mayores que IPF. De todas formas, no quita que FreeBSD sea un excelente OS.
ResponderEliminar