[kernel] r16834 - in dists/lenny-security/linux-2.6/debian: . patches/bugfix/all patches/series

Dann Frazier dannf at alioth.debian.org
Mon Jan 17 20:22:39 UTC 2011


Author: dannf
Date: Mon Jan 17 20:22:36 2011
New Revision: 16834

Log:
IB/uverbs: Handle large number of entries in poll CQ (CVE-2010-4649)

Added:
   dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ib-uverbs-handle-large-number-of-entries-in-poll-CQ.patch
Modified:
   dists/lenny-security/linux-2.6/debian/changelog
   dists/lenny-security/linux-2.6/debian/patches/series/26lenny2

Modified: dists/lenny-security/linux-2.6/debian/changelog
==============================================================================
--- dists/lenny-security/linux-2.6/debian/changelog	Mon Jan 17 20:14:20 2011	(r16833)
+++ dists/lenny-security/linux-2.6/debian/changelog	Mon Jan 17 20:22:36 2011	(r16834)
@@ -22,6 +22,7 @@
   * sctp: a race between ICMP protocol unreachable and connect() (CVE-2010-4526)
   * sound: Prevent buffer overflow in OSS load_mixer_volumes (CVE-2010-4527)
   * CAN: Use inode instead of kernel address for /proc file (CVE-2010-4565)
+  * IB/uverbs: Handle large number of entries in poll CQ (CVE-2010-4649)
 
   [ Moritz Muehlenhoff ]
   * blkback/blktap/netback: Fix CVE-2010-3699 	

Added: dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ib-uverbs-handle-large-number-of-entries-in-poll-CQ.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/lenny-security/linux-2.6/debian/patches/bugfix/all/ib-uverbs-handle-large-number-of-entries-in-poll-CQ.patch	Mon Jan 17 20:22:36 2011	(r16834)
@@ -0,0 +1,158 @@
+commit 6c4ff74fe922494252bb112aa86359b9559cef10
+Author: Dan Carpenter <error27 at gmail.com>
+Date:   Wed Oct 13 09:13:12 2010 +0000
+
+    IB/uverbs: Handle large number of entries in poll CQ
+    
+    In ib_uverbs_poll_cq() code there is a potential integer overflow if
+    userspace passes in a large cmd.ne.  The calls to kmalloc() would
+    allocate smaller buffers than intended, leading to memory corruption.
+    There iss also an information leak if resp wasn't all used.
+    Unprivileged userspace may call this function, although only if an
+    RDMA device that uses this function is present.
+    
+    Fix this by copying CQ entries one at a time, which avoids the
+    allocation entirely, and also by moving this copying into a function
+    that makes sure to initialize all memory copied to userspace.
+    
+    Special thanks to Jason Gunthorpe <jgunthorpe at obsidianresearch.com>
+    for his help and advice.
+    
+    Cc: <stable at kernel.org>
+    Signed-off-by: Dan Carpenter <error27 at gmail.com>
+    
+    [ Monkey around with things a bit to avoid bad code generation by gcc
+      when designated initializers are used.  - Roland ]
+    
+    Signed-off-by: Roland Dreier <rolandd at cisco.com>
+    [dannf: backported to Debian's 2.6.26]
+
+diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
+index 2c3bff5..6c788a1 100644
+--- a/drivers/infiniband/core/uverbs_cmd.c
++++ b/drivers/infiniband/core/uverbs_cmd.c
+@@ -877,68 +877,81 @@ out:
+ 	return ret ? ret : in_len;
+ }
+ 
++static int copy_wc_to_user(void __user *dest, struct ib_wc *wc)
++{
++	struct ib_uverbs_wc tmp;
++
++	tmp.wr_id		= wc->wr_id;
++	tmp.status		= wc->status;
++	tmp.opcode		= wc->opcode;
++	tmp.vendor_err		= wc->vendor_err;
++	tmp.byte_len		= wc->byte_len;
++	tmp.imm_data		= (__u32 __force) wc->imm_data;
++	tmp.qp_num		= wc->qp->qp_num;
++	tmp.src_qp		= wc->src_qp;
++	tmp.wc_flags		= wc->wc_flags;
++	tmp.pkey_index		= wc->pkey_index;
++	tmp.slid		= wc->slid;
++	tmp.sl			= wc->sl;
++	tmp.dlid_path_bits	= wc->dlid_path_bits;
++	tmp.port_num		= wc->port_num;
++	tmp.reserved		= 0;
++
++	if (copy_to_user(dest, &tmp, sizeof tmp))
++		return -EFAULT;
++
++	return 0;
++}
++
+ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
+ 			  const char __user *buf, int in_len,
+ 			  int out_len)
+ {
+ 	struct ib_uverbs_poll_cq       cmd;
+-	struct ib_uverbs_poll_cq_resp *resp;
++	struct ib_uverbs_poll_cq_resp  resp;
++	u8 __user                     *header_ptr;
++	u8 __user                     *data_ptr;
+ 	struct ib_cq                  *cq;
+-	struct ib_wc                  *wc;
+-	int                            ret = 0;
+-	int                            i;
+-	int                            rsize;
++	struct ib_wc                   wc;
++	int                            ret;
+ 
+ 	if (copy_from_user(&cmd, buf, sizeof cmd))
+ 		return -EFAULT;
+ 
+-	wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
+-	if (!wc)
+-		return -ENOMEM;
+-
+-	rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
+-	resp = kmalloc(rsize, GFP_KERNEL);
+-	if (!resp) {
+-		ret = -ENOMEM;
+-		goto out_wc;
+-	}
+-
+ 	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+-	if (!cq) {
+-		ret = -EINVAL;
+-		goto out;
+-	}
++	if (!cq)
++		return -EINVAL;
+ 
+-	resp->count = ib_poll_cq(cq, cmd.ne, wc);
++	/* we copy a struct ib_uverbs_poll_cq_resp to user space */
++	header_ptr = (void __user *)(unsigned long) cmd.response;
++	data_ptr = header_ptr + sizeof resp;
+ 
+-	put_cq_read(cq);
++	memset(&resp, 0, sizeof resp);
++	while (resp.count < cmd.ne) {
++		ret = ib_poll_cq(cq, 1, &wc);
++		if (ret < 0)
++			goto out_put;
++		if (!ret)
++			break;
++
++		ret = copy_wc_to_user(data_ptr, &wc);
++		if (ret)
++			goto out_put;
+ 
+-	for (i = 0; i < resp->count; i++) {
+-		resp->wc[i].wr_id 	   = wc[i].wr_id;
+-		resp->wc[i].status 	   = wc[i].status;
+-		resp->wc[i].opcode 	   = wc[i].opcode;
+-		resp->wc[i].vendor_err 	   = wc[i].vendor_err;
+-		resp->wc[i].byte_len 	   = wc[i].byte_len;
+-		resp->wc[i].imm_data 	   = (__u32 __force) wc[i].imm_data;
+-		resp->wc[i].qp_num 	   = wc[i].qp->qp_num;
+-		resp->wc[i].src_qp 	   = wc[i].src_qp;
+-		resp->wc[i].wc_flags 	   = wc[i].wc_flags;
+-		resp->wc[i].pkey_index 	   = wc[i].pkey_index;
+-		resp->wc[i].slid 	   = wc[i].slid;
+-		resp->wc[i].sl 		   = wc[i].sl;
+-		resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
+-		resp->wc[i].port_num 	   = wc[i].port_num;
++		data_ptr += sizeof(struct ib_uverbs_wc);
++		++resp.count;
+ 	}
+ 
+-	if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
++	if (copy_to_user(header_ptr, &resp, sizeof resp)) {
+ 		ret = -EFAULT;
++		goto out_put;
++	}
+ 
+-out:
+-	kfree(resp);
++	ret = in_len;
+ 
+-out_wc:
+-	kfree(wc);
+-	return ret ? ret : in_len;
++out_put:
++	put_cq_read(cq);
++	return ret;
+ }
+ 
+ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,

Modified: dists/lenny-security/linux-2.6/debian/patches/series/26lenny2
==============================================================================
--- dists/lenny-security/linux-2.6/debian/patches/series/26lenny2	Mon Jan 17 20:14:20 2011	(r16833)
+++ dists/lenny-security/linux-2.6/debian/patches/series/26lenny2	Mon Jan 17 20:22:36 2011	(r16834)
@@ -19,3 +19,4 @@
 + bugfix/all/sctp-fix-race-between-ICMP-protocol-unreachable-and-connect.patch
 + bugfix/all/sound-prevent-buffer-overflow-in-OSS-load_mixer_volumes.patch
 + bugfix/all/can-use-inode-instead-of-kernel-address-for-proc-file.patch
++ bugfix/all/ib-uverbs-handle-large-number-of-entries-in-poll-CQ.patch



More information about the Kernel-svn-changes mailing list