Fix for CVE-2009-2906.
authorJeremy Allison <jra@samba.org>
Thu, 1 Oct 2009 12:32:36 +0000 (14:32 +0200)
committerKarolin Seeger <kseeger@samba.org>
Thu, 1 Oct 2009 12:32:36 +0000 (14:32 +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.

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

index 3c3ced6baf713785d495132487134844df912b57..cee95a9b170bfffb2d6368dbfa1ee8438fa493ed 100644 (file)
@@ -727,6 +727,7 @@ struct pending_message_list {
        struct smb_perfcount_data pcd;
        uint32_t seqnum;
        bool encrypted;
+       bool processed;
        DATA_BLOB buf;
        DATA_BLOB private_data;
 };
index ccb7f9dce3e25013c22b763473fabe5447a81708..fbaa9dee290491016be52e8f0d6d805da8e09355 100644 (file)
@@ -417,6 +417,7 @@ static void smbd_deferred_open_timer(struct event_context *ev,
        struct pending_message_list *msg = talloc_get_type(private_data,
                                           struct pending_message_list);
        TALLOC_CTX *mem_ctx = talloc_tos();
+       uint16_t mid = SVAL(msg->buf.data,smb_mid);
        uint8_t *inbuf;
 
        inbuf = (uint8_t *)talloc_memdup(mem_ctx, msg->buf.data,
@@ -429,11 +430,21 @@ static void smbd_deferred_open_timer(struct event_context *ev,
        /* We leave this message on the queue so the open code can
           know this is a retry. */
        DEBUG(5,("smbd_deferred_open_timer: trigger mid %u.\n",
-               (unsigned int)SVAL(msg->buf.data,smb_mid)));
+               (unsigned int)mid ));
+
+       /* Mark the message as processed so this is not
+        * re-processed in error. */
+       msg->processed = true;
 
        process_smb(smbd_server_conn, inbuf,
                    msg->buf.length, 0,
                    msg->seqnum, msg->encrypted, &msg->pcd);
+
+       /* If it's still there and was processed, remove it. */
+       msg = get_open_deferred_message(mid);
+       if (msg && msg->processed) {
+               remove_deferred_open_smb_message(mid);
+       }
 }
 
 /****************************************************************************
@@ -466,6 +477,7 @@ static bool push_queued_message(struct smb_request *req,
        msg->request_time = request_time;
        msg->seqnum = req->seqnum;
        msg->encrypted = req->encrypted;
+       msg->processed = false;
        SMB_PERFCOUNT_DEFER_OP(&req->pcd, &msg->pcd);
 
        if (private_data) {
@@ -507,7 +519,7 @@ void remove_deferred_open_smb_message(uint16 mid)
 
        for (pml = deferred_open_queue; pml; pml = pml->next) {
                if (mid == SVAL(pml->buf.data,smb_mid)) {
-                       DEBUG(10,("remove_sharing_violation_open_smb_message: "
+                       DEBUG(10,("remove_deferred_open_smb_message: "
                                  "deleting mid %u len %u\n",
                                  (unsigned int)mid,
                                  (unsigned int)pml->buf.length ));
@@ -537,6 +549,15 @@ void schedule_deferred_open_smb_message(uint16 mid)
                if (mid == msg_mid) {
                        struct timed_event *te;
 
+                       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",
+                                       msg_mid ));
+                               continue;
+                       }
+
                        DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
                                mid ));
 
@@ -563,7 +584,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)
@@ -571,7 +592,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;
                }
        }
@@ -1309,7 +1330,6 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
                        DEBUG(0, ("Error: Could not change to user. Removing "
                            "deferred open, mid=%d.\n", req->mid));
                        reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
-                       remove_deferred_open_smb_message(req->mid);
                        return conn;
                }