Fix for CVE-2009-2906. v3-0-test
authorJeremy Allison <jra@samba.org>
Wed, 30 Sep 2009 12:21:56 +0000 (14:21 +0200)
committerKarolin Seeger <kseeger@samba.org>
Thu, 1 Oct 2009 12:25:02 +0000 (14:25 +0200)
Summary:
Specially crafted SMB requests on
authenticated SMB connections can send smbd
into a 100% CPU loop, causing a DoS on the
Samba server.
(cherry picked from commit dff54f716bdd76e3d167dc96bba6e168ef58cadd)

source/include/smb.h
source/smbd/process.c

index 7484efd1925f3d39aaa0b8f18845cc3d11346eb7..e512add4be2dbd2d727652a49bdfb42fa6024dac 100644 (file)
@@ -759,6 +759,7 @@ struct pending_message_list {
        struct pending_message_list *next, *prev;
        struct timeval request_time; /* When was this first issued? */
        struct timeval end_time; /* When does this time out? */
+       bool processed;
        DATA_BLOB buf;
        DATA_BLOB private_data;
 };
index cf2988699b80c635a6d157fe1828e45832a5f17d..e861e16e0e27f0cd59b9847ef2bf352e4bac7696 100644 (file)
@@ -93,6 +93,7 @@ static BOOL push_queued_message(char *buf, int msg_len,
 
        msg->request_time = request_time;
        msg->end_time = end_time;
+       msg->processed = false;
 
        if (private_data) {
                msg->private_data = data_blob_talloc(msg, private_data,
@@ -162,7 +163,7 @@ void schedule_deferred_open_smb_message(uint16 mid)
 }
 
 /****************************************************************************
- Return true if this mid is on the deferred queue.
+ Return true if this mid is on the deferred queue and was not yet processed.
 ****************************************************************************/
 
 BOOL open_was_deferred(uint16 mid)
@@ -170,7 +171,7 @@ BOOL open_was_deferred(uint16 mid)
        struct pending_message_list *pml;
 
        for (pml = deferred_open_queue; pml; pml = pml->next) {
-               if (SVAL(pml->buf.data,smb_mid) == mid) {
+               if (SVAL(pml->buf.data,smb_mid) == mid && !pml->processed) {
                        return True;
                }
        }
@@ -409,6 +410,10 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
                        /* We leave this message on the queue so the open code can
                           know this is a retry. */
                        DEBUG(5,("receive_message_or_smb: returning deferred open smb message.\n"));
+
+                       /* Mark the message as processed so this is not
+                        * re-processed in error. */
+                       msg->processed = true;
                        return True;
                }
        }
@@ -967,8 +972,6 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
                        }
 
                        if (!change_to_user(conn,session_tag)) {
-                               remove_deferred_open_smb_message(
-                                       SVAL(inbuf, smb_mid));
                                return(ERROR_NT(NT_STATUS_DOS(ERRSRV,ERRbaduid)));
                        }
 
@@ -1017,9 +1020,11 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
 
 static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
 {
+       struct pending_message_list *pml = NULL;
        int type = CVAL(inbuf,smb_com);
        int outsize = 0;
        int msg_type = CVAL(inbuf,0);
+       uint16_t mid = SVAL(inbuf, smb_mid);
 
        chain_size = 0;
        file_chain_reset();
@@ -1032,6 +1037,13 @@ static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize)
 
        outsize = switch_message(type,inbuf,outbuf,size,bufsize);
 
+       /* If this was a deferred message and it's still there and
+        * was processed, remove it. */
+       pml = get_open_deferred_message(mid);
+       if (pml && pml->processed) {
+               remove_deferred_open_smb_message(mid);
+       }
+
        outsize += chain_size;
 
        if(outsize > 4)