Due to a stupid mistake the patch I just posted was an early broken version
(some length checks inversed).
Please replace it with the one below.
Sorry about that!
Marc
On Tue, Jul 31, 2001 at 12:42:59PM -0400, Marc Boucher wrote:
> Hi folks,
>
> Enclosed is a patch which should eliminate the crashes involving
> netfilter/iptables/nat (and often pppoe) that several people have been
> experiencing under kernels >= 2.4.4.
>
> Basically the nat manip_pkt handlers were corrupting
> skb_shinfo(skb)->frag_list
> (thus causing a crash in skb_drop_fraglist()) by stupidly writing beyond
> skb->end when attempting to update fields (like tcp->check) in truncated
> inner-ICMP headers.
>
> Cheers
> Marc
>
--- linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_core.c 2001/07/31 15:31:51
1.1
+++ linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_core.c 2001/07/31 17:27:06
@@ -824,6 +824,16 @@
? "DST" : "SRC",
NIPQUAD(info->manips[i].manip.ip),
ntohs(info->manips[i].manip.u.udp.port));
+
+ if((skb->len <= ((void *)inner - (void *)iph)) ||
+ (skb->len < ((void *)(
+ (u_int32_t *)inner + inner->ihl
+ ) - (void *)iph))) {
+ DEBUGP("icmp_reply_translation: skb too small
for inner IP header\n");
+ READ_UNLOCK(&ip_nat_lock);
+ return NF_DROP;
+ }
+
manip_pkt(inner->protocol, inner,
skb->len - ((void *)inner - (void *)iph),
&info->manips[i].manip,
--- linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_proto_icmp.c 2001/07/31
15:37:44 1.1
+++ linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_proto_icmp.c 2001/07/31
17:27:08
@@ -9,6 +9,12 @@
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
static int
icmp_in_range(const struct ip_conntrack_tuple *tuple,
enum ip_nat_manip_type maniptype,
@@ -48,6 +54,11 @@
enum ip_nat_manip_type maniptype)
{
struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+
+ if(((void *)(hdr+1) - (void *)iph) > len) {
+ DEBUGP("icmp_manip_pkt: too small\n");
+ return;
+ }
hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF,
manip->u.icmp.id,
--- linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_proto_tcp.c 2001/07/31
15:37:45 1.1
+++ linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_proto_tcp.c 2001/07/31
17:35:20
@@ -9,6 +9,12 @@
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
static int
tcp_in_range(const struct ip_conntrack_tuple *tuple,
enum ip_nat_manip_type maniptype,
@@ -83,6 +89,12 @@
u_int32_t oldip;
u_int16_t *portptr;
+
+ if(((void *)&hdr->dest + sizeof(hdr->dest) - (void *)iph) > len) {
+ DEBUGP("tcp_manip_pkt: too small\n");
+ return;
+ }
+
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
oldip = iph->saddr;
@@ -92,10 +104,17 @@
oldip = iph->daddr;
portptr = &hdr->dest;
}
- hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
+
+ /* this could be a inner header returned in icmp packet; in such
+ cases we cannot update the checksum field since it is outside of
+ the 64 bits of transport layer headers typically included */
+ if(((void *)&hdr->check + sizeof(hdr->check) - (void *)iph) <= len) {
+ hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
ip_nat_cheat_check(*portptr ^ 0xFFFF,
manip->u.tcp.port,
hdr->check));
+ }
+
*portptr = manip->u.tcp.port;
}
--- linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_proto_udp.c 2001/07/31
15:37:45 1.1
+++ linux-2.4.7-mb/net/ipv4/netfilter/ip_nat_proto_udp.c 2001/07/31
17:27:15
@@ -9,6 +9,12 @@
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
static int
udp_in_range(const struct ip_conntrack_tuple *tuple,
enum ip_nat_manip_type maniptype,
@@ -80,6 +86,11 @@
struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
u_int32_t oldip;
u_int16_t *portptr;
+
+ if(((void *)&hdr->check + sizeof(hdr->check) - (void *)iph) > len) {
+ DEBUGP("udp_manip_pkt: too small\n");
+ return;
+ }
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
|