From 03a85f8e25d52e15112eb5e146e2766337217ed5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 9 Jan 2003 07:21:03 -0800 Subject: Fix exec_mmap() to release the MM while we still have it active, to properly de-activate it and make the child_tid logic work correctly. Clear %fs/%gs in deactivate_mm() on x86, since our LDT will no longer be valid after this. Update mm_release() to deactivate MM state before releasing, and avoid the expensive child_tid FUTEX if we're the last user of the MM. --- include/linux/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 9545a1957089..9916d377a74b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -566,7 +566,7 @@ static inline void mmdrop(struct mm_struct * mm) /* mmput gets rid of the mappings and all user-space */ extern void mmput(struct mm_struct *); /* Remove the current tasks stale references to the old mm_struct */ -extern void mm_release(void); +extern void mm_release(struct task_struct *, struct mm_struct *); extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern void flush_thread(void); -- cgit v1.2.3 From bae2065beb3be9d1bfa591024af1e4c5d046c7a9 Mon Sep 17 00:00:00 2001 From: "Brian J. Murrell" Date: Thu, 9 Jan 2003 08:59:09 -0800 Subject: [NETFILTER]: UDP nat helper support. --- include/linux/netfilter_ipv4/ip_nat_helper.h | 7 ++ net/ipv4/netfilter/ip_nat_helper.c | 177 ++++++++++++++++++++++----- net/ipv4/netfilter/ip_nat_standalone.c | 1 + 3 files changed, 152 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h index 2c1fb8d9bb54..8e2996f76fed 100644 --- a/include/linux/netfilter_ipv4/ip_nat_helper.h +++ b/include/linux/netfilter_ipv4/ip_nat_helper.h @@ -50,6 +50,13 @@ extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb, unsigned int match_len, char *rep_buffer, unsigned int rep_len); +extern int ip_nat_mangle_udp_packet(struct sk_buff **skb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + char *rep_buffer, + unsigned int rep_len); extern int ip_nat_seq_adjust(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo); diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index 5279d1a2d2c9..6f53c4430469 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c @@ -8,6 +8,9 @@ * - add support for SACK adjustment * 14 Mar 2002 Harald Welte : * - merge SACK support into newnat API + * 16 Aug 2002 Brian J. Murrell : + * - make ip_nat_resize_packet more generic (TCP and UDP) + * - add ip_nat_mangle_udp_packet */ #include #include @@ -22,6 +25,7 @@ #include #include #include +#include #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) @@ -51,18 +55,12 @@ ip_nat_resize_packet(struct sk_buff **skb, int new_size) { struct iphdr *iph; - struct tcphdr *tcph; - void *data; int dir; struct ip_nat_seq *this_way, *other_way; DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n", (*skb)->len, new_size); - iph = (*skb)->nh.iph; - tcph = (void *)iph + iph->ihl*4; - data = (void *)tcph + tcph->doff*4; - dir = CTINFO2DIR(ctinfo); this_way = &ct->nat.info.seq[dir]; @@ -84,37 +82,41 @@ ip_nat_resize_packet(struct sk_buff **skb, } iph = (*skb)->nh.iph; - tcph = (void *)iph + iph->ihl*4; - data = (void *)tcph + tcph->doff*4; - - DEBUGP("ip_nat_resize_packet: Seq_offset before: "); - DUMP_OFFSET(this_way); - - LOCK_BH(&ip_nat_seqofs_lock); - - /* SYN adjust. If it's uninitialized, of this is after last - * correction, record it: we don't handle more than one - * adjustment in the window, but do deal with common case of a - * retransmit */ - if (this_way->offset_before == this_way->offset_after - || before(this_way->correction_pos, ntohl(tcph->seq))) { - this_way->correction_pos = ntohl(tcph->seq); - this_way->offset_before = this_way->offset_after; - this_way->offset_after = (int32_t) - this_way->offset_before + new_size - (*skb)->len; - } + if (iph->protocol == IPPROTO_TCP) { + struct tcphdr *tcph = (void *)iph + iph->ihl*4; + void *data = (void *)tcph + tcph->doff*4; + + DEBUGP("ip_nat_resize_packet: Seq_offset before: "); + DUMP_OFFSET(this_way); + + LOCK_BH(&ip_nat_seqofs_lock); + + /* SYN adjust. If it's uninitialized, of this is after last + * correction, record it: we don't handle more than one + * adjustment in the window, but do deal with common case of a + * retransmit */ + if (this_way->offset_before == this_way->offset_after + || before(this_way->correction_pos, ntohl(tcph->seq))) { + this_way->correction_pos = ntohl(tcph->seq); + this_way->offset_before = this_way->offset_after; + this_way->offset_after = (int32_t) + this_way->offset_before + new_size - + (*skb)->len; + } - UNLOCK_BH(&ip_nat_seqofs_lock); + UNLOCK_BH(&ip_nat_seqofs_lock); - DEBUGP("ip_nat_resize_packet: Seq_offset after: "); - DUMP_OFFSET(this_way); + DEBUGP("ip_nat_resize_packet: Seq_offset after: "); + DUMP_OFFSET(this_way); + } return 1; } /* Generic function for mangling variable-length address changes inside - * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP). + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX + * command in FTP). * * Takes care about all the nasty sequence number changes, checksumming, * skb enlargement, ... @@ -174,10 +176,11 @@ ip_nat_mangle_tcp_packet(struct sk_buff **skb, tcph = (void *)iph + iph->ihl*4; data = (void *)tcph + tcph->doff*4; - /* move post-replacement */ - memmove(data + match_offset + rep_len, - data + match_offset + match_len, - (*skb)->tail - (data + match_offset + match_len)); + if (rep_len != match_len) + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + (*skb)->tail - (data + match_offset + match_len)); /* insert data from buffer */ memcpy(data + match_offset, rep_buffer, rep_len); @@ -207,6 +210,114 @@ ip_nat_mangle_tcp_packet(struct sk_buff **skb, return 1; } + +/* Generic function for mangling variable-length address changes inside + * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX + * command in the Amanda protocol) + * + * Takes care about all the nasty sequence number changes, checksumming, + * skb enlargement, ... + * + * XXX - This function could be merged with ip_nat_mangle_tcp_packet which + * should be fairly easy to do. + */ +int +ip_nat_mangle_udp_packet(struct sk_buff **skb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + unsigned int match_offset, + unsigned int match_len, + char *rep_buffer, + unsigned int rep_len) +{ + struct iphdr *iph = (*skb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + unsigned char *data; + u_int32_t udplen, newlen, newudplen; + + udplen = (*skb)->len - iph->ihl*4; + newudplen = udplen - match_len + rep_len; + newlen = iph->ihl*4 + newudplen; + + if (newlen > 65535) { + if (net_ratelimit()) + printk("ip_nat_mangle_udp_packet: nat'ed packet " + "exceeds maximum packet size\n"); + return 0; + } + + if ((*skb)->len != newlen) { + if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) { + printk("resize_packet failed!!\n"); + return 0; + } + } + + /* Alexey says: if a hook changes _data_ ... it can break + original packet sitting in tcp queue and this is fatal */ + if (skb_cloned(*skb)) { + struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC); + if (!nskb) { + if (net_ratelimit()) + printk("Out of memory cloning TCP packet\n"); + return 0; + } + /* Rest of kernel will get very unhappy if we pass it + a suddenly-orphaned skbuff */ + if ((*skb)->sk) + skb_set_owner_w(nskb, (*skb)->sk); + kfree_skb(*skb); + *skb = nskb; + } + + /* skb may be copied !! */ + iph = (*skb)->nh.iph; + udph = (void *)iph + iph->ihl*4; + data = (void *)udph + sizeof(struct udphdr); + + if (rep_len != match_len) + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + (*skb)->tail - (data + match_offset + match_len)); + + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); + + /* update skb info */ + if (newlen > (*skb)->len) { + DEBUGP("ip_nat_mangle_udp_packet: Extending packet by " + "%u to %u bytes\n", newlen - (*skb)->len, newlen); + skb_put(*skb, newlen - (*skb)->len); + } else { + DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from " + "%u to %u bytes\n", (*skb)->len, newlen); + skb_trim(*skb, newlen); + } + + /* update the length of the UDP and IP packets to the new values*/ + udph->len = htons((*skb)->len - iph->ihl*4); + iph->tot_len = htons(newlen); + + /* fix udp checksum if udp checksum was previously calculated */ + if ((*skb)->csum != 0) { + (*skb)->csum = csum_partial((char *)udph + + sizeof(struct udphdr), + newudplen - sizeof(struct udphdr), + 0); + + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, + newudplen, IPPROTO_UDP, + csum_partial((char *)udph, + sizeof(struct udphdr), + (*skb)->csum)); + } + + ip_send_check(iph); + + return 1; +} /* Adjust one found SACK option including checksum correction */ static void diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 8eb33381126f..825fc43dd28a 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -359,5 +359,6 @@ EXPORT_SYMBOL(ip_nat_helper_register); EXPORT_SYMBOL(ip_nat_helper_unregister); EXPORT_SYMBOL(ip_nat_cheat_check); EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); +EXPORT_SYMBOL(ip_nat_mangle_udp_packet); EXPORT_SYMBOL(ip_nat_used_tuple); MODULE_LICENSE("GPL"); -- cgit v1.2.3