[PATCH 2.6.10 1/1] netfilter: fix crash on nat+icmp packets

From: mukesh agrawal
Date: Tue Mar 01 2005 - 20:43:45 EST



This patch fixes a kernel crashing bug when using NAT. The crash occurs in the case when we send out a UDP packet to a closed port on another host, with the UDP packet being SNATed. The remote host replies with an ICMP port unreachable (type 3, code 3). We need to adjust the ICMP packet, because the UDP packet was SNATed.

The cause of the crash is that udp_manip_pkt reads *pskb into iph before calling skb_ip_make_writable, and fails to update iph after the call. Since skb_ip_make_writable may delete the original skb when it makes a copy, a page fault may occur when udp_manip_pkt later dereferences iph.

I suspect that normally, the relevant skbuff holds a UDP packet, and either the skbuff is unshared (so no copy is made, and the skbuff remains valid), or is shared, but remains so while udp_manip_pkt is running (and hence, the old reference to the skbuff is still okay).

When we get an ICMP reply for a SNATed UDP packet, ip_nat_proto_udp is asked to modify the UDP header inside the payload of the ICMP packet. (The call chain is ip_nat_fn -> icmp_reply_translation -> ip_nat_manip_pkt -> udp_manip_pkt.)

Since the UDP header is beyond the ICMP header, skb_ip_make_writable copies the skbuff, and deletes the original. Then udp_manip_pkt's iph is invalid, and dereferencing it causes a page fault.

Glancing at the code for tcp_manip_pkt, I think it would have the same problem, but I haven't tested that case. The patch below fixes the UDP case only.

(For the record, my kernel tree also has the tproxy patch from http://www.balabit.com/downloads/tproxy/linux-2.4/cttproxy-2.6.10-2.0.0.tar.gz applied. But I think this bug is independent of that patch.)

diff -uprN linux-2.6.10.orig/net/ipv4/netfilter/ip_nat_proto_udp.c linux-2.6.10.fixed/net/ipv4/netfilter/ip_nat_proto_udp.c
--- linux-2.6.10.orig/net/ipv4/netfilter/ip_nat_proto_udp.c 2004-12-24 16:34:01.000000000 -0500
+++ linux-2.6.10.fixed/net/ipv4/netfilter/ip_nat_proto_udp.c 2005-03-01 19:32:21.000000000 -0500
@@ -95,6 +95,9 @@ udp_manip_pkt(struct sk_buff **pskb,

if (!skb_ip_make_writable(pskb, hdroff + sizeof(hdr)))
return 0;
+ /* skb_ip_make_writable may have copied the skb, and deleted
+ the original */
+ iph = (struct iphdr *)((*pskb)->data + iphdroff);

hdr = (void *)(*pskb)->data + hdroff;
if (maniptype == IP_NAT_MANIP_SRC) {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/