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",