Skip to content

Commit

Permalink
[CIFS] fix bad handling of EAGAIN error on kernel_recvmsg in cifs_dem…
Browse files Browse the repository at this point in the history
…ultiplex_thread

When kernel_recvmsg returns -EAGAIN or -ERESTARTSYS, then
cifs_demultiplex_thread sleeps for a bit and then tries the read again.
When it does this, it's not zeroing out the length and that throws off
the value of total_read. Fix it to zero out the length.

Can cause memory corruption:
If kernel_recvmsg returns an error and total_read is a large enough
value, then we'll end up going through the loop again. total_read will
be a bogus value, as will (pdu_length-total_read). When this happens we
end up calling kernel_recvmsg with a bogus value (possibly larger than
the current iov_len).

At that point, memcpy_toiovec can overrun iov. 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
here.

Many thanks to Ulrich Obergfell for pointing this out.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
  • Loading branch information
Steve French committed Oct 17, 2007
1 parent adddd49 commit c18c732
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 2 deletions.
3 changes: 2 additions & 1 deletion fs/cifs/CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ opened, read and written as if they were files). When 1st tree
connect fails (e.g. due to signing negotiation failure) fix
leak that causes cifsd not to stop and rmmod to fail to cleanup
cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on
bigendian architectures.
bigendian architectures. Fix possible memory corruption when
EAGAIN returned on kern_recvmsg.

Version 1.50
------------
Expand Down
6 changes: 5 additions & 1 deletion fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
msleep(1); /* minimum sleep to prevent looping
allowing socket to clear and app threads to set
tcpStatus CifsNeedReconnect if server hung */
continue;
if (pdu_length < 4)
goto incomplete_rcv;
else
continue;
} else if (length <= 0) {
if (server->tcpStatus == CifsNew) {
cFYI(1, ("tcp session abend after SMBnegprot"));
Expand Down Expand Up @@ -543,6 +546,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",
Expand Down

0 comments on commit c18c732

Please sign in to comment.