patch-2.1.89 linux/net/core/iovec.c

Next file: linux/net/core/neighbour.c
Previous file: linux/net/core/dst.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.88/linux/net/core/iovec.c linux/net/core/iovec.c
@@ -38,9 +38,8 @@
 
 int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
 {
-	int err=0;
-	int len=0;
-	int ct;
+	int size = m->msg_iovlen * sizeof(struct iovec);
+	int err, ct;
 	
 	if(m->msg_namelen)
 	{
@@ -48,7 +47,7 @@
 		{
 			err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
 			if(err<0)
-				return err;
+				goto out;
 		}
 		
 		m->msg_name = address;
@@ -57,24 +56,26 @@
 
 	if (m->msg_iovlen > UIO_FASTIOV)
 	{
-		iov = kmalloc(m->msg_iovlen*sizeof(struct iovec), GFP_KERNEL);
+		err = -ENOMEM;
+		iov = kmalloc(size, GFP_KERNEL);
 		if (!iov)
-			return -ENOMEM;
+			goto out;
 	}
 	
-	err = copy_from_user(iov, m->msg_iov, sizeof(struct iovec)*m->msg_iovlen);
-	if (err)
-	{
-		if (m->msg_iovlen > UIO_FASTIOV)
-			kfree(iov);
-		return -EFAULT;
-	}
+	if (copy_from_user(iov, m->msg_iov, size))
+		goto out_free;
+	m->msg_iov=iov;
 
-	for(ct=0;ct<m->msg_iovlen;ct++)
-		len+=iov[ct].iov_len;
+	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++)
+		err += iov[ct].iov_len;
+out:
+	return err;
 
-	m->msg_iov=iov;
-	return len;
+out_free:
+	err = -EFAULT;
+	if (m->msg_iovlen > UIO_FASTIOV)
+		kfree(iov);
+	goto out;
 }
 
 /*
@@ -83,15 +84,15 @@
  
 int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
 {
-	int err; 
+	int err = -EFAULT; 
+
 	while(len>0)
 	{
 		if(iov->iov_len)
 		{
-			int copy = min(iov->iov_len,len);
-			err = copy_to_user(iov->iov_base,kdata,copy);
-			if (err) 
-			    return err;
+			int copy = min(iov->iov_len, len);
+			if (copy_to_user(iov->iov_base, kdata, copy))
+				goto out;
 			kdata+=copy;
 			len-=copy;
 			iov->iov_len-=copy;
@@ -99,7 +100,9 @@
 		}
 		iov++;
 	}
-	return 0; 
+	err = 0;
+out:
+	return err; 
 }
 
 /*
@@ -108,17 +111,15 @@
  
 int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
 {
-	int err; 
+	int err = -EFAULT; 
+
 	while(len>0)
 	{
 		if(iov->iov_len)
 		{
-			int copy=min(len,iov->iov_len);
-			err = copy_from_user(kdata, iov->iov_base, copy);
-			if (err)
-			{
-				return -EFAULT;
-			}
+			int copy = min(len, iov->iov_len);
+			if (copy_from_user(kdata, iov->iov_base, copy))
+				goto out;
 			len-=copy;
 			kdata+=copy;
 			iov->iov_base+=copy;
@@ -126,7 +127,9 @@
 		}
 		iov++;
 	}
-	return 0; 
+	err = 0;
+out:
+	return err; 
 }
 
 
@@ -137,28 +140,23 @@
 int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
 			int len)
 {
-	int err; 
+	int err = -EFAULT;
+
 	while(offset>0)
 	{
 		if (offset > iov->iov_len)
 		{
 			offset -= iov->iov_len;
-
 		}
 		else
 		{
-			u8 *base;
-			int copy;
+			u8 *base = iov->iov_base + offset;
+			int copy = min(len, iov->iov_len - offset);
 
-			base = iov->iov_base + offset;
-			copy = min(len, iov->iov_len - offset);
 			offset = 0;
 
-			err = copy_from_user(kdata, base, copy);
-			if (err)
-			{
-				return -EFAULT;
-			}
+			if (copy_from_user(kdata, base, copy))
+				goto out;
 			len-=copy;
 			kdata+=copy;
 		}
@@ -167,17 +165,17 @@
 
 	while (len>0)
 	{
-		int copy=min(len, iov->iov_len);
-		err = copy_from_user(kdata, iov->iov_base, copy);
-		if (err)
-		{
-			return -EFAULT;
-		}
+		int copy = min(len, iov->iov_len);
+
+		if (copy_from_user(kdata, iov->iov_base, copy))
+			goto out;
 		len-=copy;
 		kdata+=copy;
 		iov++;
 	}
-	return 0;
+	err = 0;
+out:
+	return err;
 }
 
 /*
@@ -200,25 +198,28 @@
 	do {
 		int copy = iov->iov_len - offset;
 
-		if (copy >= 0) {
+		if (copy > 0) {
 			u8 *base = iov->iov_base + offset;
 
 			/* Normal case (single iov component) is fastly detected */
 			if (len <= copy) {
 				*csump = csum_and_copy_from_user(base, kdata, 
 								 len, *csump, &err);
-				return err;
+				goto out;
 			}
 
 			partial_cnt = copy % 4;
 			if (partial_cnt) {
 				copy -= partial_cnt;
-				err |= copy_from_user(kdata+copy, base+copy, partial_cnt);
+				if (copy_from_user(kdata + copy, base + copy,
+						partial_cnt))
+					goto out_fault;
 			}
 
-			*csump = csum_and_copy_from_user(base, kdata, 
-							 copy, *csump, &err);
-
+			*csump = csum_and_copy_from_user(base, kdata, copy,
+							 *csump, &err);
+			if (err)
+				goto out;
 			len   -= copy + partial_cnt;
 			kdata += copy + partial_cnt;
 			iov++;
@@ -230,7 +231,7 @@
 
 	csum = *csump;
 
-	while (len>0)
+	while (len > 0)
 	{
 		u8 *base = iov->iov_base;
 		unsigned int copy = min(len, iov->iov_len);
@@ -242,23 +243,26 @@
 
 			/* iov component is too short ... */
 			if (par_len > copy) {
-				err |= copy_from_user(kdata, base, copy);
+				if (copy_from_user(kdata, base, copy))
+					goto out_fault;
+				kdata += copy;
 				base += copy;
 				partial_cnt += copy;
-				kdata += copy;
 				len -= copy;
 				iov++;
 				if (len)
 					continue;
-				*csump = csum_partial(kdata-partial_cnt, partial_cnt, csum);
-				return err;
+				*csump = csum_partial(kdata - partial_cnt,
+							 partial_cnt, csum);
+				goto out;
 			}
-			err |= copy_from_user(kdata, base, par_len);
-			csum = csum_partial(kdata-partial_cnt, 4, csum);
+			if (copy_from_user(kdata, base, par_len))
+				goto out_fault;
+			csum = csum_partial(kdata - partial_cnt, 4, csum);
+			kdata += par_len;
 			base += par_len;
 			copy -= par_len;
 			len -= par_len;
-			kdata += par_len;
 			partial_cnt = 0;
 		}
 
@@ -268,18 +272,31 @@
 			if (partial_cnt)
 			{
 				copy -= partial_cnt;
-				err |= copy_from_user(kdata+copy, base + copy, partial_cnt);
+				if (copy_from_user(kdata + copy, base + copy,
+				 		partial_cnt))
+					goto out_fault;
 			}
 		}
 
-		if (copy == 0)
+		/* Why do we want to break?? There may be more to copy ... */
+		if (copy == 0) {
+if (len > partial_cnt)
+printk("csum_iovec: early break? len=%d, partial=%d\n", len, partial_cnt);
 			break;
+		}
 
 		csum = csum_and_copy_from_user(base, kdata, copy, csum, &err);
+		if (err)
+			goto out;
 		len   -= copy + partial_cnt;
 		kdata += copy + partial_cnt;
 		iov++;
 	}
         *csump = csum;
+out:
 	return err;
+
+out_fault:
+	err = -EFAULT;
+	goto out;
 }

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