From 8a6b90d401e3c8d4d04ade36020bfc5c31c9603e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 1 Oct 2009 14:32:36 +0200 Subject: Fix for CVE-2009-2906. 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 | 1 + source3/smbd/process.c | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index 3c3ced6baf..cee95a9b17 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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; }; diff --git a/source3/smbd/process.c b/source3/smbd/process.c index ccb7f9dce3..fbaa9dee29 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -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; } -- cgit