patch-2.1.79 linux/net/ipv4/raw.c

Next file: linux/net/ipv4/route.c
Previous file: linux/net/ipv4/ipmr.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.78/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.32 1997/10/24 17:16:00 kuznet Exp $
+ * Version:	$Id: raw.c,v 1.33 1997/12/27 20:41:15 kuznet Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -255,13 +255,24 @@
 {
 	struct ipcm_cookie ipc;
 	struct rawfakehdr rfh;
-	struct rtable *rt;
+	struct rtable *rt = NULL;
 	int free = 0;
 	u32 daddr;
 	u8  tos;
 	int err;
 
-	if (len>65535)
+	/* This check is ONLY to check for arithmetic overflow
+	   on integer(!) len. Not more! Real check will be made
+	   in ip_build_xmit --ANK
+
+	   BTW socket.c -> af_*.c -> ... make multiple
+	   invalid conversions size_t -> int. We MUST repair it f.e.
+	   by replacing all of them with size_t and revise all
+	   the places sort of len += sizeof(struct iphdr)
+	   If len was ULONG_MAX-10 it would be cathastrophe  --ANK
+	 */
+
+	if (len < 0 || len > 0xFFFF)
 		return -EMSGSIZE;
 
 	/*
@@ -308,10 +319,6 @@
 		int tmp = ip_cmsg_send(msg, &ipc);
 		if (tmp)
 			return tmp;
-		if (ipc.opt && sk->ip_hdrincl) {
-			kfree(ipc.opt);
-			return -EINVAL;
-		}
 		if (ipc.opt)
 			free=1;
 	}
@@ -321,10 +328,19 @@
 
 	if (!ipc.opt)
 		ipc.opt = sk->opt;
-	if (ipc.opt && ipc.opt->srr) {
-		if (!daddr)
-			return -EINVAL;
-		daddr = ipc.opt->faddr;
+
+	if (ipc.opt) {
+		err = -EINVAL;
+		/* Linux does not mangle headers on raw sockets,
+		 * so that IP options + IP_HDRINCL is non-sense.
+		 */
+		if (sk->ip_hdrincl)
+			goto done;
+		if (ipc.opt->srr) {
+			if (!daddr)
+				goto done;
+			daddr = ipc.opt->faddr;
+		}
 	}
 	tos = RT_TOS(sk->ip_tos) | (sk->localroute || (msg->msg_flags&MSG_DONTROUTE));
 
@@ -337,30 +353,21 @@
 
 	err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif);
 
-	if (err) {
-		if (free) kfree(ipc.opt);
-		return err;
-	}
+	if (err)
+		goto done;
 
-	if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) {
-		if (free) kfree(ipc.opt);
-		ip_rt_put(rt);
-		return -EACCES;
-	}
+	err = -EACCES;
+	if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast)
+		goto done;
 
 	rfh.iov = msg->msg_iov;
 	rfh.saddr = rt->rt_src;
 	if (!ipc.addr)
 		ipc.addr = rt->rt_dst;
-	if(sk->ip_hdrincl)
-		err=ip_build_xmit(sk, raw_getrawfrag, &rfh, len, &ipc, rt, msg->msg_flags);
-	else {
-		if (len>65535-sizeof(struct iphdr))
-			err = -EMSGSIZE;
-		else
-			err=ip_build_xmit(sk, raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags);
-	}
+	err=ip_build_xmit(sk, sk->ip_hdrincl ? raw_getrawfrag : raw_getfrag,
+			  &rfh, len, &ipc, rt, msg->msg_flags);
 
+done:
 	if (free)
 		kfree(ipc.opt);
 	ip_rt_put(rt);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov