System crash with slip+ip_queue+dnat
Sami Ponkanen
sami.ponkanen@vtt.fi
Mon, 17 Dec 2001 17:57:00 +0200
Hello,
Firstly, my network:
A <--- slip ---> B <--- slip ---> C
I was trying to do the following at host B:
1. get a UDP packet sent by a local process (src: B dest: A) to user space
via ip_queue and libipq
2. give a verdict to the packet
3. redirect the packet back to host B with dnat
However when the packet is reinjected back to kernel space (in step 2 I
think) I get a kernel oops.
This happens only with UDP+slip. TCP works perfectly and so does UDP if I use
ppp or ethernet. Similarly slip+UDP does not crash the system if the UDP
source is on C and B is acting as a router.
The crash is reproducible (atleast on my system) with the code attached below.
Both kernel versions I tested (2.4.7 and 2.4.16) crashed, the ksymoops-dump
below is from 2.4.7.
Versions of most important stuff:
linux-2.4.7
iptables-1.2.4
libc-2.2.4.so
slattach 1.21
I'm not sure if I am reading the ksymoops-dump correctly, but the lines with
references to "eth_header" do seem a bit odd, since as I understand the
packet should go via lo or slip and not the ethernet interface.
Any ideas how I could solve my problem? I have to use slip, since last time I
tried ppp did not work well with diffserv stuff.
Thanks,
Sami Pönkänen
slip_crasher.c:
/*
* slip_crasher.c
*
* 1. Set up slip
* /sbin/slattach -p slip -s 9600 /dev/ttyS0
* /sbin/ifconfig sl0 192.168.1.2 pointopoint 192.168.1.1
*
* 2. Do the iptables stuff
* modprobe ip_queue
* iptables -t mangle -A OUTPUT -s 192.168.1.2 -d 192.168.1.1 -p udp -j QUEUE
* iptables -t nat -A OUTPUT -s 192.168.1.2 -d 192.168.1.1 -p udp -j DNAT
--to-destination 192.168.1.2
*
* 3. Compile and run slip_crasher
* gcc -L/path/to/libipq/lib -I/path/to/libipq/include -o slip_crasher
slip_crasher.c -lipq
* ./slip_crasher
*
* 3. Send a couple of UDP packets from 192.168.1.2 to 192.168.1.1
*
* 4. Sit back and enjoy
*/
#include "libipq/libipq.h"
#include <stdio.h>
#define BUF_SIZE 65536
int main()
{
struct ipq_handle *h;
char buf[BUF_SIZE];
size_t buf_size = BUF_SIZE, read_bytes;
int i;
h = ipq_create_handle(0);
ipq_set_mode(h, IPQ_COPY_PACKET, BUF_SIZE);
printf("created ipq handle\n");
for(i=0; i<2;)
{
read_bytes = ipq_read(h, buf, buf_size, 0);
printf("read %d bytes\n", (int) read_bytes);
if(read_bytes >= 0)
{
switch ( ipq_message_type(buf) )
{
case IPQM_PACKET:
{
ipq_packet_msg_t *m = ipq_get_packet(buf);
i++;
printf("packet %d\n", i);
fflush(stdout);
/* When i reaches 2 watch your system crash... */
ipq_set_verdict(h, m->packet_id, 1, m->data_len,
m->payload);
}
}
}
}
return 0;
}
ksymoops:
ksymoops 2.4.3 on i586 2.4.7. Options used
-V (default)
-k /var/log/ksymoops/20011217154948.ksyms (specified)
-l /proc/modules (default)
-o /lib/modules/2.4.7/ (specified)
-m /boot/System.map-2.4.7 (specified)
Error (compare_ksyms_lsmod): module slip is in ksyms but not in lsmod
skput:under: c01ca44d:67 put:14 dev:lokernel BUG at skbuff.c:110!
invalid operand: 0000
CPU: 0
EIP: 0010:[<c01c10e1>]
Using defaults from ksymoops -t elf32-i386 -a i386
EFLAGS: 00010286
eax: 0000001c ebx: 00000800 ecx: c1e92000 edx: c026f224
esi: c2e18800 edi: c0fc4140 ebp: 00000000 esp: c17e5c70
ds: 0018 es: 0018 ss:0018
Process slip_crasher (pid:218, stackpage=c17e5000)
Stack: c024b08c c024b280 0000006e c01ca456 c2e18800 0000000e c01ca44d c1ddb5c0
c2e18800 c0fc4140 c027bd20 c01c7c46 c2e18800 c027bd20 00000800 c0fc4168
00000000 00000035 c2e18800 c1ddb5c0 00000000 00000002 c01d5264 c2e18800
Call Trace: [<c01ca456>] [<c01ca44d>] [<c01c7c46>] [<c01d5264>] [<c01ca24e>]
[<c01d4141>] [<c01d51d0>]
[<c01d51c9>] [<c01ca369>] [<c02029ab>] [<c0202a80>] [<c0202efd>]
[<c0206868>] [<c0206271>] [<c02066f3>]
[<c01be675>] [<c01bf7b8>] [<c0187e48>] [<c01bd457>] [<c0184f06>]
[<c0188536>] [<c017d820>] [<c017965d>]
[<c01bfc2c>] [<c0106b43>]
Code: 0f 0b 83 c4 0c c3 90 a1 68 f8 2b c0 57 56 53 f7 d8 8b 7c 24
>>EIP; c01c10e0 <skb_under_panic+3c/44> <=====
Trace; c01ca456 <eth_header+36/114>
Trace; c01ca44c <eth_header+2c/114>
Trace; c01c7c46 <neigh_resolve_output+ce/1a8>
Trace; c01d5264 <ip_finish_output2+94/d4>
Trace; c01ca24e <nf_hook_slow+136/188>
Trace; c01d4140 <ip_output+50/58>
Trace; c01d51d0 <ip_finish_output2+0/d4>
Trace; c01d51c8 <output_maybe_reroute+c/14>
Trace; c01ca368 <nf_reinject+c8/180>
Trace; c02029aa <ipq_set_verdict+72/84>
Trace; c0202a80 <ipq_receive_peer+c4/d8>
Trace; c0202efc <netlink_receive_user_sk+14c/1bc>
Trace; c0206868 <netlink_data_ready+1c/64>
Trace; c0206270 <netlink_unicast+28c/2d4>
Trace; c02066f2 <netlink_sendmsg+1fa/20c>
Trace; c01be674 <sock_sendmsg+68/88>
Trace; c01bf7b8 <sys_sendmsg+18c/1e8>
Trace; c0187e48 <do_con_write+594/64c>
Trace; c01bd456 <vgacon_cursor+17e/188>
Trace; c0184f06 <set_cursor+6e/88>
Trace; c0188536 <con_flush_chars+16/20>
Trace; c017d820 <write_chan+1fc/214>
Trace; c017965c <tty_write+154/1c0>
Trace; c01bfc2c <sys_socketcall+1e4/200>
Trace; c0106b42 <system_call+32/40>
Code; c01c10e0 <skb_under_panic+3c/44>
00000000 <_EIP>:
Code; c01c10e0 <skb_under_panic+3c/44> <=====
0: 0f 0b ud2a <=====
Code; c01c10e2 <skb_under_panic+3e/44>
2: 83 c4 0c add $0xc,%esp
Code; c01c10e4 <skb_under_panic+40/44>
5: c3 ret
Code; c01c10e6 <skb_under_panic+42/44>
6: 90 nop
Code; c01c10e6 <skb_under_panic+42/44>
7: a1 68 f8 2b c0 mov 0xc02bf868,%eax
Code; c01c10ec <alloc_skb+4/190>
c: 57 push %edi
Code; c01c10ec <alloc_skb+4/190>
d: 56 push %esi
Code; c01c10ee <alloc_skb+6/190>
e: 53 push %ebx
Code; c01c10ee <alloc_skb+6/190>
f: f7 d8 neg %eax
Code; c01c10f0 <alloc_skb+8/190>
11: 8b 7c 24 00 mov 0x0(%esp,1),%edi
Kernel panic: Aiee, killing interrupt handler!
1 error issued. Results may not be reliable.