CVE-2008-1105-receive_smb_raw-overflow [plain text]
Fix for CVE-2008-1105.
Also includes c537b4376db8eb17904d2cf5fa3ec1fa32548742, which is a
regression introduced by the previous fix:
Fix bug reported by David Eisner <deisner@gmail.com>. When
allocating cli buffers for large read/write - make sure we take
account of the large read/write SMB headers as well as the
buffer space.
Index: samba/source/client/client.c
===================================================================
--- samba/source/client/client.c.orig
+++ samba/source/client/client.c
@@ -3626,7 +3626,7 @@ static void readline_callback(void)
session keepalives and then drop them here.
*/
if (FD_ISSET(cli->fd,&fds)) {
- if (!receive_smb(cli->fd,cli->inbuf,0)) {
+ if (!receive_smb(cli->fd,cli->inbuf,cli->bufsize,0)) {
DEBUG(0, ("Read from server failed, maybe it closed the "
"connection\n"));
return;
Index: samba/source/client/smbctool.c
===================================================================
--- samba/source/client/smbctool.c.orig
+++ samba/source/client/smbctool.c
@@ -3304,7 +3304,7 @@ static void readline_callback(void)
session keepalives and then drop them here.
*/
if (FD_ISSET(cli->fd,&fds)) {
- receive_smb(cli->fd,cli->inbuf,0);
+ receive_smb(cli->fd,cli->inbuf,cli->bufsize,0);
goto again;
}
Index: samba/source/lib/util_sock.c
===================================================================
--- samba/source/lib/util_sock.c.orig
+++ samba/source/lib/util_sock.c
@@ -654,14 +654,13 @@ ssize_t read_smb_length(int fd, char *in
}
/****************************************************************************
- Read an smb from a fd. Note that the buffer *MUST* be of size
- BUFFER_SIZE+SAFETY_MARGIN.
+ Read an smb from a fd.
The timeout is in milliseconds.
This function will return on receipt of a session keepalive packet.
Doesn't check the MAC on signed packets.
****************************************************************************/
-BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
+BOOL receive_smb_raw(int fd, char *buffer, size_t buflen, unsigned int timeout)
{
ssize_t len,ret;
@@ -682,25 +681,18 @@ BOOL receive_smb_raw(int fd, char *buffe
return False;
}
- /*
- * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
- * of header. Don't print the error if this fits.... JRA.
- */
-
- if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+ if (len > buflen) {
DEBUG(0,("Invalid packet length! (%lu bytes).\n",(unsigned long)len));
- if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
- /*
- * Correct fix. smb_read_error may have already been
- * set. Only set it here if not already set. Global
- * variables still suck :-). JRA.
- */
+ /*
+ * smb_read_error may have already been
+ * set. Only set it here if not already set. Global
+ * variables still suck :-). JRA.
+ */
- if (smb_read_error == 0)
- smb_read_error = READ_ERROR;
- return False;
- }
+ if (smb_read_error == 0)
+ smb_read_error = READ_ERROR;
+ return False;
}
if(len > 0) {
@@ -730,9 +722,9 @@ BOOL receive_smb_raw(int fd, char *buffe
Checks the MAC on signed packets.
****************************************************************************/
-BOOL receive_smb(int fd, char *buffer, unsigned int timeout)
+BOOL receive_smb(int fd, char *buffer, size_t buflen, unsigned int timeout)
{
- if (!receive_smb_raw(fd, buffer, timeout)) {
+ if (!receive_smb_raw(fd, buffer, buflen, timeout)) {
return False;
}
Index: samba/source/libsmb/clientgen.c
===================================================================
--- samba/source/libsmb/clientgen.c.orig
+++ samba/source/libsmb/clientgen.c
@@ -44,8 +44,7 @@ int cli_set_port(struct cli_state *cli,
}
/****************************************************************************
- Read an smb from a fd ignoring all keepalive packets. Note that the buffer
- *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN.
+ Read an smb from a fd ignoring all keepalive packets.
The timeout is in milliseconds
This is exactly the same as receive_smb except that it never returns
@@ -54,12 +53,12 @@ int cli_set_port(struct cli_state *cli,
should never go into a blocking read.
****************************************************************************/
-static BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
+static BOOL client_receive_smb(int fd,char *buffer, size_t bufsize, unsigned int timeout)
{
BOOL ret;
for(;;) {
- ret = receive_smb_raw(fd, buffer, timeout);
+ ret = receive_smb_raw(fd, buffer, bufsize, timeout);
if (!ret) {
DEBUG(10,("client_receive_smb failed\n"));
@@ -88,7 +87,7 @@ BOOL cli_receive_smb(struct cli_state *c
return False;
again:
- ret = client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
+ ret = client_receive_smb(cli->fd,cli->inbuf, cli->bufsize, cli->timeout);
if (ret) {
/* it might be an oplock break request */
Index: samba/source/smbd/process.c
===================================================================
--- samba/source/smbd/process.c.orig
+++ samba/source/smbd/process.c
@@ -521,7 +521,8 @@ static BOOL receive_message_or_smb(char
goto again;
}
- return receive_smb(smbd_server_fd(), buffer, 0);
+ return receive_smb(smbd_server_fd(), buffer,
+ BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE, 0);
}
/*
Index: samba/source/utils/smbfilter.c
===================================================================
--- samba/source/utils/smbfilter.c.orig
+++ samba/source/utils/smbfilter.c
@@ -140,7 +140,7 @@ static void filter_child(int c, struct i
if (num <= 0) continue;
if (c != -1 && FD_ISSET(c, &fds)) {
- if (!receive_smb(c, packet, 0)) {
+ if (!receive_smb(c, packet, BUFFER_SIZE, 0)) {
d_printf("client closed connection\n");
exit(0);
}
@@ -151,7 +151,7 @@ static void filter_child(int c, struct i
}
}
if (s != -1 && FD_ISSET(s, &fds)) {
- if (!receive_smb(s, packet, 0)) {
+ if (!receive_smb(s, packet, BUFFER_SIZE, 0)) {
d_printf("server closed connection\n");
exit(0);
}
Index: samba/source/libsmb/cliconnect.c
===================================================================
--- samba/source/libsmb/cliconnect.c.orig
+++ samba/source/libsmb/cliconnect.c
@@ -1323,9 +1323,9 @@ BOOL cli_negprot(struct cli_state *cli)
if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
- cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
- cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
- cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
+ cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
+ cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
+ cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
}
} else if (cli->protocol >= PROTOCOL_LANMAN1) {