From dff54f716bdd76e3d167dc96bba6e168ef58cadd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 30 Sep 2009 14:21:56 +0200 Subject: [PATCH] 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. --- source/include/smb.h | 1 + source/smbd/process.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index 7484efd..e512add 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -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; }; diff --git a/source/smbd/process.c b/source/smbd/process.c index cf29886..e861e16 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -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) -- 1.6.0.2