patch-2.1.130 linux/net/ipv4/ip_masq.c
Next file: linux/net/socket.c
Previous file: linux/mm/vmscan.c
Back to the patch index
Back to the overall index
- Lines: 234
- Date:
Fri Nov 20 17:40:07 1998
- Orig file:
v2.1.129/linux/net/ipv4/ip_masq.c
- Orig date:
Sun Nov 8 14:03:14 1998
diff -u --recursive --new-file v2.1.129/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 1994 Pauline Middelink
*
- * $Id: ip_masq.c,v 1.27 1998/11/07 14:59:24 davem Exp $
+ * $Id: ip_masq.c,v 1.28 1998/11/21 00:33:30 davem Exp $
*
*
* See ip_fw.c for original log
@@ -43,6 +43,7 @@
* Juan Jose Ciarlante : u-space context => locks reworked
* Juan Jose Ciarlante : fixed stupid SMP locking bug
* Juan Jose Ciarlante : fixed "tap"ing in demasq path by copy-on-w
+ * Juan Jose Ciarlante : make masq_proto_doff() robust against fake sized/corrupted packets
*
*/
@@ -337,6 +338,9 @@
#define PORT_MASQ_MUL 10
#endif
+/*
+ * At the moment, hardcore in sync with masq_proto_num
+ */
atomic_t ip_masq_free_ports[3] = {
ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* UDP */
ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* TCP */
@@ -960,15 +964,40 @@
return NULL;
}
-static __inline__ unsigned proto_doff(unsigned proto, char *th)
+/*
+ * Get transport protocol data offset, check against size
+ */
+static __inline__ int proto_doff(unsigned proto, char *th, unsigned size)
{
+ int ret = -1;
switch (proto) {
+ case IPPROTO_ICMP:
+ if (size >= sizeof(struct icmphdr))
+ ret = sizeof(struct icmphdr);
+ break;
case IPPROTO_UDP:
- return sizeof(struct udphdr);
+ if (size >= sizeof(struct udphdr))
+ ret = sizeof(struct udphdr);
+ break;
case IPPROTO_TCP:
- return ((struct tcphdr*)th)->doff << 2;
+ /*
+ * Is this case, this check _also_ avoids
+ * touching an invalid pointer if
+ * size is invalid
+ */
+ if (size >= sizeof(struct tcphdr)) {
+ ret = ((struct tcphdr*)th)->doff << 2;
+ if (ret > size) {
+ ret = -1 ;
+ }
+ }
+
+ break;
}
- return 0;
+ if (ret < 0)
+ IP_MASQ_DEBUG(0, "mess proto_doff for proto=%d, size =%d\n",
+ proto, size);
+ return ret;
}
int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr)
@@ -980,19 +1009,26 @@
int size;
/*
- * Magic "doff" csum semantics
- * !0: saved payload csum IS valid, doff is correct
- * 0: csum not valid
+ * doff holds transport protocol data offset
+ * csum holds its checksum
+ * csum_ok says if csum is valid
*/
- unsigned doff = 0;
+ int doff = 0;
int csum = 0;
+ int csum_ok = 0;
/*
* We can only masquerade protocols with ports... and hack some ICMPs
*/
h.raw = (char*) iph + iph->ihl * 4;
+ size = ntohs(iph->tot_len) - (iph->ihl * 4);
+ doff = proto_doff(iph->protocol, h.raw, size);
+ if (doff < 0) {
+ IP_MASQ_DEBUG(0, "O-pkt invalid packet data size\n");
+ return -1;
+ }
switch (iph->protocol) {
case IPPROTO_ICMP:
return(ip_fw_masq_icmp(skb_p, maddr));
@@ -1002,22 +1038,21 @@
break;
case IPPROTO_TCP:
/* Make sure packet is in the masq range */
- size = ntohs(iph->tot_len) - (iph->ihl * 4);
IP_MASQ_DEBUG(3, "O-pkt: %s size=%d\n",
masq_proto_name(iph->protocol),
size);
+#ifdef CONFIG_IP_MASQ_DEBUG
+ if (ip_masq_get_debug_level() > 3) {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+#endif
/* Check that the checksum is OK */
switch (skb->ip_summed)
{
case CHECKSUM_NONE:
{
- int datasz;
- doff = proto_doff(iph->protocol, h.raw);
- datasz = size - doff;
- if (datasz < 0)
- return -1;
- csum = csum_partial(h.raw + doff, datasz, 0);
+ csum = csum_partial(h.raw + doff, size - doff, 0);
IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n",
masq_proto_name(iph->protocol),
csum);
@@ -1138,7 +1173,7 @@
*/
if (ms->app)
- doff = 0;
+ csum_ok = 0;
/*
* Attempt ip_masq_app call.
@@ -1153,6 +1188,7 @@
iph = skb->nh.iph;
h.raw = (char*) iph + iph->ihl *4;
size = skb->len - (h.raw - skb->nh.raw);
+ /* doff should have not changed */
}
/*
@@ -1163,8 +1199,7 @@
* Transport's payload partial csum
*/
- if (!doff) {
- doff = proto_doff(iph->protocol, h.raw);
+ if (!csum_ok) {
csum = csum_partial(h.raw + doff, size - doff, 0);
}
skb->csum = csum;
@@ -1715,8 +1750,9 @@
union ip_masq_tphdr h;
struct ip_masq *ms;
unsigned short size;
- unsigned doff = 0;
+ int doff = 0;
int csum = 0;
+ int csum_ok = 0;
__u32 maddr;
/*
@@ -1732,9 +1768,20 @@
return 0;
}
- maddr = iph->daddr;
h.raw = (char*) iph + iph->ihl * 4;
+ /*
+ * IP payload size
+ */
+ size = ntohs(iph->tot_len) - (iph->ihl * 4);
+
+ doff = proto_doff(iph->protocol, h.raw, size);
+ if (doff < 0) {
+ IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n");
+ return -1;
+ }
+
+ maddr = iph->daddr;
switch (iph->protocol) {
case IPPROTO_ICMP:
return(ip_fw_demasq_icmp(skb_p));
@@ -1754,16 +1801,20 @@
return 0;
/* Check that the checksum is OK */
- size = ntohs(iph->tot_len) - (iph->ihl * 4);
if ((iph->protocol == IPPROTO_UDP) && (h.uh->check == 0))
/* No UDP checksum */
break;
+#ifdef CONFIG_IP_MASQ_DEBUG
+ if (ip_masq_get_debug_level() > 3) {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+#endif
switch (skb->ip_summed)
{
case CHECKSUM_NONE:
- doff = proto_doff(iph->protocol, h.raw);
csum = csum_partial(h.raw + doff, size - doff, 0);
+ csum_ok++;
skb->csum = csum_partial(h.raw , doff, csum);
case CHECKSUM_HW:
@@ -1851,7 +1902,7 @@
*/
if (ms->app)
- doff = 0;
+ csum_ok = 0;
/*
* Attempt ip_masq_app call.
@@ -1878,8 +1929,7 @@
* Transport's payload partial csum
*/
- if (!doff) {
- doff = proto_doff(iph->protocol, h.raw);
+ if (!csum_ok) {
csum = csum_partial(h.raw + doff, size - doff, 0);
}
skb->csum = csum;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov