The Samba-Bugzilla – Attachment 9619 Details for
Bug 10344
SessionLogoff on a signed connection with an outstanding notify request crashes smbd.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP-part2
look (text/plain), 11.89 KB, created by
Jeremy Allison
on 2014-01-28 01:16:17 UTC
(
hide
)
Description:
WIP-part2
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2014-01-28 01:16:17 UTC
Size:
11.89 KB
patch
obsolete
>From 356c038f2425a4ccc72c3cd3049bd3f47a23de9d Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 13 Jan 2014 14:12:18 -0800 >Subject: [PATCH 1/3] s3: SMB2 sessionsetup - factor code out into a function > remove_outstanding_session_refs(). > >We will be reusing this. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 38 ++++++++++++++++++++++---------------- > 1 file changed, 22 insertions(+), 16 deletions(-) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index edef0cc..e63a244 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -455,10 +455,30 @@ static int pp_self_ref_destructor(struct smbd_smb2_session_setup_state **pp_stat > return 0; > } > >-static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) >+static void remove_outstanding_session_refs(struct smbd_smb2_request *smb2req) > { > struct smbd_smb2_request *preq; > >+ for (preq = smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >+ if (preq == smb2req) { >+ /* Don't remove the session from the current >+ request in flight. */ >+ continue; >+ } >+ if (preq->session == smb2req->session) { >+ preq->session = NULL; >+ /* >+ * If we no longer have a session we can't >+ * sign or encrypt replies. >+ */ >+ preq->do_signing = false; >+ preq->do_encryption = false; >+ } >+ } >+} >+ >+static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) >+{ > /* > * If state->session is not NULL, > * we move the session from the session table to the request on failure >@@ -479,21 +499,7 @@ static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_set > * to it. > */ > >- for (preq = state->smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >- if (preq == state->smb2req) { >- continue; >- } >- if (preq->session == state->smb2req->session) { >- preq->session = NULL; >- /* >- * If we no longer have a session we can't >- * sign or encrypt replies. >- */ >- preq->do_signing = false; >- preq->do_encryption = false; >- } >- } >- >+ remove_outstanding_session_refs(state->smb2req); > return 0; > } > >-- >1.8.5.3 > > >From 25c69ff58ab4a64ebccbde484e3fb24d1832c490 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 13 Jan 2014 14:31:31 -0800 >Subject: [PATCH 2/3] s3: SMB2 sessionsetup - add > cancel_outstanding_session_requests(). > >Walks the outstanding requests on this session (not including >the current request being processed) and call cancel on the >first one we haven't already cancelled. Returns true if there >were any requests cancelled, false if not. Stores the cancelled >request in an array. > >Not yet used. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 76 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 76 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index e63a244..8c249aa 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -794,6 +794,82 @@ static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req, > return status; > } > >+/******************************************************** >+ Walk the outstanding requests on this session (not including >+ the current request being processed) and call cancel on >+ the first request that has not yet been cancelled. Store the >+ cancelled message-id. Returns true if a request was cancelled, >+ false otherwise. >+********************************************************/ >+ >+struct already_cancelled { >+ uint64_t *already_cancelled_array; >+ unsigned int num_already_cancelled; >+}; >+ >+static bool cancel_outstanding_session_requests(const struct smbd_smb2_request *smb2req, >+ struct already_cancelled *pc) >+{ >+ struct smbd_smb2_request *preq; >+ >+ if (smb2req->session == NULL) { >+ return false; >+ } >+ for (preq = smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >+ const uint8_t *outhdr; >+ uint64_t message_id; >+ unsigned i; >+ >+ if (preq == smb2req) { >+ /* Can't cancel current request. */ >+ continue; >+ } >+ if (preq->session != smb2req->session) { >+ /* Request on different session. */ >+ continue; >+ } >+ >+ if (preq->compound_related) { >+ /* >+ * Never cancel anything in a compound >+ * request. Way too hard to deal with >+ * the result. >+ */ >+ continue; >+ } >+ outhdr = SMBD_SMB2_OUT_HDR_PTR(preq); >+ message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID); >+ for (i = 0; i < pc->num_already_cancelled; i++) { >+ if (message_id == pc->already_cancelled_array[i]) { >+ break; >+ } >+ } >+ if (i < pc->num_already_cancelled) { >+ /* We've called tevent_req_cancel >+ on this request before. */ >+ continue; >+ } >+ >+ tevent_req_cancel(preq->subreq); >+ >+ /* Add the newly cancelled message-id to the array. */ >+ pc->already_cancelled_array = talloc_realloc(pc, >+ pc->already_cancelled_array, >+ uint64_t, >+ pc->num_already_cancelled + 1); >+ if (pc->already_cancelled_array == NULL) { >+ /* Fatal error. */ >+ smb_panic("talloc fail\n"); >+ /* NOTREACHED. */ >+ return false; >+ } >+ pc->already_cancelled_array[pc->num_already_cancelled] = message_id; >+ pc->num_already_cancelled++; >+ return true; >+ } >+ return false; >+} >+ > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.8.5.3 > > >From 0bb64206e7cdd44d587e29d7b7a2b06b70be6a25 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 27 Jan 2014 15:19:35 -0800 >Subject: [PATCH 3/3] Make smbd_smb2_request_process_logoff() async. > >Add smbd_smb2_logoff_send()/smbd_smb2_logoff_recv()/smbd_smb2_request_logoff_done() >and make smbd_smb2_logoff_send() re-entrant. First call to smbd_smb2_logoff_send() >calls tevent_req_cancel() on any outstanding requests on this session >then re-schedules itself to be processed after the canceled requests >finish. It waits 30 seconds, re-scheduling itself until all events >have been canceled. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 170 +++++++++++++++++++++++++++++++++++++----- > 1 file changed, 150 insertions(+), 20 deletions(-) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 8c249aa..125b2cc 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -870,44 +870,174 @@ static bool cancel_outstanding_session_requests(const struct smbd_smb2_request * > return false; > } > >+static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct smbd_smb2_request *smb2req); >+static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req); >+static void smbd_smb2_request_logoff_done(struct tevent_req *subreq); >+ > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >- DATA_BLOB outbody; >+ struct tevent_req *subreq = NULL; > > status = smbd_smb2_request_verify_sizes(req, 0x04); > if (!NT_STATUS_IS_OK(status)) { > return smbd_smb2_request_error(req, status); > } > >+ subreq = smbd_smb2_logoff_send(req, req->sconn->ev_ctx, req); >+ if (subreq == NULL) { >+ return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); >+ } >+ tevent_req_set_callback(subreq, smbd_smb2_request_logoff_done, req); >+ return smbd_smb2_request_pending_queue(req, subreq, 500); >+} >+ >+static void smbd_smb2_request_logoff_done(struct tevent_req *subreq) >+{ >+ struct smbd_smb2_request *smb2req = >+ tevent_req_callback_data(subreq, >+ struct smbd_smb2_request); >+ DATA_BLOB outbody; >+ NTSTATUS status; >+ NTSTATUS error; >+ >+ status = smbd_smb2_logoff_recv(subreq); >+ TALLOC_FREE(subreq); >+ if (!NT_STATUS_IS_OK(status)) { >+ error = smbd_smb2_request_error(smb2req, status); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+ return; >+ } >+ >+ outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x04); >+ if (outbody.data == NULL) { >+ error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+ return; >+ } >+ >+ SSVAL(outbody.data, 0x00, 0x04); /* struct size */ >+ SSVAL(outbody.data, 0x02, 0); /* reserved */ >+ >+ error = smbd_smb2_request_done(smb2req, outbody, NULL); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+} >+ >+struct smbd_smb2_logout_state { >+ struct already_cancelled *acp; >+ struct timeval end_logout; >+}; >+ >+static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct smbd_smb2_request *smb2req) >+{ >+ NTSTATUS status; >+ struct tevent_req *req; >+ struct smbd_smb2_logout_state *state; >+ >+ req = smb2req->subreq; >+ if (req == NULL) { >+ /* New logoff call. */ >+ req = tevent_req_create(mem_ctx, &state, >+ struct smbd_smb2_logout_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ >+ state->acp = talloc_zero(state, struct already_cancelled); >+ if (state->acp) { >+ return NULL; >+ } >+ >+ /* Don't wait more than 30 seconds for cancel. >+ So remember time now + 30 seconds. If we are >+ re-scheduled after this the cancel requests >+ took too long and we exit. */ >+ state->end_logout = tevent_timeval_current_ofs(30, 0); >+ } else { >+ /* Re-entrant logoff call - we are being rescheduled >+ after we're requested other requests are canceled. */ >+ struct timeval curr = tevent_timeval_current(); >+ state = tevent_req_data(req, struct smbd_smb2_logout_state); >+ >+ if (tevent_timeval_compare(&state->end_logout, &curr) >= 0) { >+ /* Ran out of time - terminate. */ >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(NT_STATUS_DRIVER_CANCEL_TIMEOUT)); >+ return NULL; >+ } >+ } >+ > /* >- * TODO: cancel all outstanding requests on the session >+ * Try and cancel a request. If we succeed, reschedule ourselves. > */ >- status = smbXsrv_session_logoff(req->session); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0, ("smbd_smb2_request_process_logoff: " >- "smbXsrv_session_logoff() failed: %s\n", >- nt_errstr(status))); >- /* >- * If we hit this case, there is something completely >- * wrong, so we better disconnect the transport connection. >- */ >- return status; >+ if (cancel_outstanding_session_requests(smb2req, state->acp)) { >+ struct tevent_immediate *im = tevent_create_immediate(smb2req); >+ if (!im) { >+ return NULL; >+ } >+ /* Try again later. */ >+ tevent_schedule_immediate(im, >+ smb2req->sconn->ev_ctx, >+ smbd_smb2_request_dispatch_immediate, >+ smb2req); >+ return req; >+ } >+ >+ /* >+ * When we get here, we are actually going to tear >+ * down the sesssion pointer. >+ */ >+ status = smbXsrv_session_logoff(smb2req->session); >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("smbXsrv_session_logoff() failed: %s\n", >+ nt_errstr(status))); >+ return tevent_req_post(req, ev); > } > > /* > * we may need to sign the response, so we need to keep > * the session until the response is sent to the wire. > */ >- talloc_steal(req, req->session); >+ talloc_steal(smb2req, smb2req->session); > >- outbody = data_blob_talloc(req->out.vector, NULL, 0x04); >- if (outbody.data == NULL) { >- return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); >- } >+ /* >+ * The return from smbXsrv_session_logoff() >+ * leaves all outstanding pointers to >+ * smb2req->session not on this request in an >+ * undefined state, ensure we don't try and >+ * access any req->session pointers once >+ * we return. >+ */ >+ remove_outstanding_session_refs(smb2req); > >- SSVAL(outbody.data, 0x00, 0x04); /* struct size */ >- SSVAL(outbody.data, 0x02, 0); /* reserved */ >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ >+static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req) >+{ >+ NTSTATUS status; > >- return smbd_smb2_request_done(req, outbody, NULL); >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ tevent_req_received(req); >+ return NT_STATUS_OK; > } >-- >1.8.5.3 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 10344
:
9547
|
9619
|
9620
|
9736
|
9761
|
9770
|
9772
|
9773
|
9780
|
9815
|
9816
|
9817
|
9818