]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
Fix for CVE-2009-2906.
authorJeremy Allison <jra@samba.org>
Wed, 30 Sep 2009 12:27:26 +0000 (14:27 +0200)
committerKarolin Seeger <kseeger@samba.org>
Thu, 1 Oct 2009 12:26:58 +0000 (14:26 +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 5f1f1c47623f846909481073d56bc909d13e5e37)

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

index 56d9461527d58013dc22c57da3162ce7cc953cc7..327f21290677a3506f45914428ba1aa2d2b614de 100644 (file)
@@ -715,6 +715,7 @@ struct pending_message_list {
        struct timeval request_time; /* When was this first issued? */
        struct timeval end_time; /* When does this time out? */
        bool encrypted;
+       bool processed;
        DATA_BLOB buf;
        DATA_BLOB private_data;
 };
index 365c97292bf0afec19a1e60df3453cc2abad8035..446b868de2f651fd5421e14f2e9ce5c9962b5526 100644 (file)
@@ -438,6 +438,7 @@ static bool push_queued_message(struct smb_request *req,
        msg->request_time = request_time;
        msg->end_time = end_time;
        msg->encrypted = req->encrypted;
+       msg->processed = false;
 
        if (private_data) {
                msg->private_data = data_blob_talloc(msg, private_data,
@@ -493,6 +494,16 @@ void schedule_deferred_open_smb_message(uint16 mid)
                DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
                        (unsigned int)msg_mid ));
                if (mid == msg_mid) {
+
+                       if (pml->processed) {
+                               /* A processed message should not be
+                                * rescheduled. */
+                               DEBUG(0,("schedule_deferred_open_smb_message: LOGIC ERROR "
+                                       "message mid %u was already processed\n",
+                                       (unsigned int)msg_mid ));
+                               continue;
+                       }
+
                        DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
                                mid ));
                        pml->end_time.tv_sec = 0;
@@ -507,7 +518,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)
@@ -515,7 +526,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;
                }
        }
@@ -784,6 +795,10 @@ static NTSTATUS receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
                        /* 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 NT_STATUS_OK;
                }
        }
@@ -1428,7 +1443,6 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
 
                if (!change_to_user(conn,session_tag)) {
                        reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
-                       remove_deferred_open_smb_message(req->mid);
                        return conn;
                }
 
@@ -1493,6 +1507,7 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
 
 static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool encrypted)
 {
+       struct pending_message_list *pml = NULL;
        uint8 type = CVAL(inbuf,smb_com);
        connection_struct *conn;
        struct smb_request *req;
@@ -1508,6 +1523,13 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool enc
 
        conn = switch_message(type, req, size);
 
+       /* If this was a deferred message and it's still there and
+        * was processed, remove it. */
+       pml = get_open_deferred_message(req->mid);
+       if (pml && pml->processed) {
+               remove_deferred_open_smb_message(req->mid);
+       }
+
        if (req->unread_bytes) {
                /* writeX failed. drain socket. */
                if (drain_socket(smbd_server_fd(), req->unread_bytes) !=