Krzysztof Halasa wrote: > Patrick McHardy <[EMAIL PROTECTED]> writes: > > >>It might be the case that your network device has a >>hard_header_len > LL_MAX_HEADER, which could trigger >>a corruption. > > > Hmm... GRE tunnels add 24 bytes... I just noticed the following code in > include/linux/netdevice.h: > > /* > * Compute the worst case header length according to the protocols > * used. > */ > #if !defined(CONFIG_NET_IPIP) && \ > !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) > #define MAX_HEADER LL_MAX_HEADER > #else > #define MAX_HEADER (LL_MAX_HEADER + 48) > #endif > > I don't use AX25, Token Ring, the old IPIP tunnels nor IPv6 here, but > I wonder if GRE tunnel (which is basically another, more compatible > form of IPIP) need the same treatment as IPIP.
Both ipip and gre do this: dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); which explains it. It is a bug in the REJECT target, but I was wondering whether you were really seeing this. It looks like it makes sense to add GRE to the MAX_HEADER case above though. >>Please try this patch on top of the REJECT patch (ideally after >>verifying that the REJECT patch is really introducing the >>corruption). > > > That was certain. The patch fixed the problem, confirmed with current > git tree as well. Thanks for looking at it. Thanks. Dave, please apply this patch. [NETFILTER]: ipt_REJECT: fix memory corruption On devices with hard_header_len > LL_MAX_HEADER ip_route_me_harder() reallocates the skb, leading to memory corruption when using the stale tcph pointer to update the checksum. Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]>
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index ad0312d..264763a 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -114,6 +114,14 @@ static void send_reset(struct sk_buff *o tcph->window = 0; tcph->urg_ptr = 0; + /* Adjust TCP checksum */ + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), + nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + csum_partial((char *)tcph, + sizeof(struct tcphdr), 0)); + /* Set DF, id = 0 */ nskb->nh.iph->frag_off = htons(IP_DF); nskb->nh.iph->id = 0; @@ -129,14 +137,8 @@ #endif if (ip_route_me_harder(&nskb, addr_type)) goto free_nskb; - /* Adjust TCP checksum */ nskb->ip_summed = CHECKSUM_NONE; - tcph->check = 0; - tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), - nskb->nh.iph->saddr, - nskb->nh.iph->daddr, - csum_partial((char *)tcph, - sizeof(struct tcphdr), 0)); + /* Adjust IP TTL */ nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);