Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 442

kernel-2.6.18-238.el5.src.rpm

From: Jeff Layton <jlayton@redhat.com>
Subject: [RHEL5 PATCH] BZ#336501: fix memory corruption due to bad error 	handling in cifs_demultiplex_thread 
Date: Thu, 18 Oct 2007 07:32:48 -0400
Bugzilla: 336501
Message-Id: <200710181132.l9IBWmJx005381@dantu.rdu.redhat.com>
Changelog: [cifs] fix memory corruption due to bad error handling


cifs_demultiplex_thread uses kernel_recvmsg to read responses from the
server. When that fucntion returns -EAGAIN or -ERESTARTSYS,
cifs_demultiplex_thread sleeps for a bit and then tries the read again.
When this occurs it does not zero out the length before calling
"continue". That causes it to add the error value (a negative number)
to the amount of data that's already been read.

Depending on the size of the buffer and the amount of data already read,
this can cause cifs_demultiplex_thread to do an extra iteration in the
for loop. The total_read variable will be a bogus value, as will
(pdu_length-total_read). When this happens we end up calling
kernel_recvmsg with a bogus size param (likely larger than the current
iov_len).

At that point, memcpy_toiovec can overrun the iovec. It will start walking
up the stack, casting other things that are there to struct iovecs
(since it assumes that it's been passed an array of them). Any pointer
on the stack at an address above the kvec is a candidate for corruption.

This patch fixes it to zero out the length after getting the error in
this situation.

Steve French has accepted a similar patch into his git tree and intends
to push this for stable upstream point releases as well. Ordinarily, I'd
shy away from proposing a patch that's had zero soak time, but this one
seems to be obviously correct and the consequences when this bug hits
can be catastrophic (one large customer in particular has experienced
several panics that seem to be due to this issue).

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 9009d59..abcabb4 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -589,6 +589,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                               allowing socket to clear and app 
 					      threads to set tcpStatus
 					      CifsNeedReconnect if server hung*/
+				length = 0;
 				continue;
 			} else if (length <= 0) {
 				cERROR(1,("Received no data, expecting %d",