The branch, master has been updated via 0ae4f368c6c smbd: reuse close_free_pending_aio() in close_directory() via f94cd10a211 smbd: call tevent_req_nterror() for directories when cleaning up pending aio via acb0b017613 smbd: move pending aio cleanup to a helper function via 95cfcda13fe vfs_default: Protect vfs_getxattrat_done() from accessing a freed req pointer via 0e894f3e482 vfs_default: pass in state as the callback data to the subreq from 54c21a99e6c winexe: add configure option to control whether to build it (default: auto)
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 0ae4f368c6c8d2c8c7aa34069007a984055df0da Author: Ralph Boehme <s...@samba.org> Date: Mon Mar 9 11:18:23 2020 +0100 smbd: reuse close_free_pending_aio() in close_directory() A directory fsp can have outstanding aio requests as well. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Mon Mar 9 19:34:27 UTC 2020 on sn-devel-184 commit f94cd10a211e2eae966ba4bd26921556bbe513fc Author: Ralph Boehme <s...@samba.org> Date: Mon Mar 9 11:31:00 2020 +0100 smbd: call tevent_req_nterror() for directories when cleaning up pending aio smbd_smb2_query_directory_recv() calls tevent_req_is_nterror() which requires a NTSTATUS error code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit acb0b01761330864a23932f643f7ad4e3d374634 Author: Ralph Boehme <s...@samba.org> Date: Mon Mar 9 11:16:37 2020 +0100 smbd: move pending aio cleanup to a helper function We'll be reusing this from close_directory() in the next commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 95cfcda13fe9a70b9955a7c44173d619eacb34c1 Author: Ralph Boehme <s...@samba.org> Date: Mon Mar 9 11:54:37 2020 +0100 vfs_default: Protect vfs_getxattrat_done() from accessing a freed req pointer If the fsp is forced closed by a SHUTDOWN_CLOSE whilst the request is in flight (share forced closed by smbcontrol), then we set state->req = NULL in the state destructor. The existing state destructor prevents the state memory from being freed, so when the thread completes and calls vfs_getxattrat_done(), just throw away the result if state->req == NULL. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 0e894f3e48285415f72cf7a68e26f1802fe8045d Author: Ralph Boehme <s...@samba.org> Date: Mon Mar 9 11:54:28 2020 +0100 vfs_default: pass in state as the callback data to the subreq Find the req we're finishing off by looking inside the state. In a shutdown close the caller calls talloc_free(req), so we can't access it directly as callback data. The next commit will NULL out the state->req pointer when a caller calls talloc_free(req), and the request is still in flight. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: source3/modules/vfs_default.c | 28 ++++++-- source3/smbd/close.c | 152 ++++++++++++++++++++---------------------- 2 files changed, 94 insertions(+), 86 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index fac7fa30ab7..cf24e66e048 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -3289,6 +3289,15 @@ struct vfswrap_getxattrat_state { static int vfswrap_getxattrat_state_destructor( struct vfswrap_getxattrat_state *state) { + /* + * This destructor only gets called if the request is still + * in flight, which is why we deny it by returning -1. We + * also set the req pointer to NULL so the _done function + * can detect the caller doesn't want the result anymore. + * + * Forcing the fsp closed by a SHUTDOWN_CLOSE can cause this. + */ + state->req = NULL; return -1; } @@ -3408,7 +3417,7 @@ static struct tevent_req *vfswrap_getxattrat_send( if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, vfswrap_getxattrat_done, req); + tevent_req_set_callback(subreq, vfswrap_getxattrat_done, state); talloc_set_destructor(state, vfswrap_getxattrat_state_destructor); @@ -3503,10 +3512,9 @@ end_profile: static void vfswrap_getxattrat_done(struct tevent_req *subreq) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct vfswrap_getxattrat_state *state = tevent_req_data( - req, struct vfswrap_getxattrat_state); + struct vfswrap_getxattrat_state *state = tevent_req_callback_data( + subreq, struct vfswrap_getxattrat_state); + struct tevent_req *req = state->req; int ret; bool ok; @@ -3520,6 +3528,16 @@ static void vfswrap_getxattrat_done(struct tevent_req *subreq) TALLOC_FREE(subreq); SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes); talloc_set_destructor(state, NULL); + if (req == NULL) { + /* + * We were shutdown closed in flight. No one wants the result, + * and state has been reparented to the NULL context, so just + * free it so we don't leak memory. + */ + DBG_NOTICE("getxattr request abandoned in flight\n"); + TALLOC_FREE(state); + return; + } if (ret != 0) { if (ret != EAGAIN) { tevent_req_error(req, ret); diff --git a/source3/smbd/close.c b/source3/smbd/close.c index c7be0c8d447..73f9c75762d 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -31,6 +31,7 @@ #include "auth.h" #include "messages.h" #include "../librpc/gen_ndr/open_files.h" +#include "lib/util/tevent_ntstatus.h" /**************************************************************************** Run a file if it is a magic script. @@ -635,6 +636,74 @@ static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2) return s2; } +static void close_free_pending_aio(struct files_struct *fsp, + enum file_close_type close_type) +{ + unsigned num_requests = fsp->num_aio_requests; + + if (num_requests == 0) { + return; + } + + if (close_type != SHUTDOWN_CLOSE) { + /* + * reply_close and the smb2 close must have + * taken care of this. No other callers of + * close_file should ever have created async + * I/O. + * + * We need to panic here because if we close() + * the fd while we have outstanding async I/O + * requests, in the worst case we could end up + * writing to the wrong file. + */ + DBG_ERR("fsp->num_aio_requests=%u\n", num_requests); + smb_panic("can not close with outstanding aio requests"); + return; + } + + /* + * For shutdown close, just drop the async requests + * including a potential close request pending for + * this fsp. Drop the close request first, the + * destructor for the aio_requests would execute it. + */ + TALLOC_FREE(fsp->deferred_close); + + while (fsp->num_aio_requests != 0) { + /* + * Previously we just called talloc_free() + * on the outstanding request, but this + * caused crashes (before the async callback + * functions were fixed not to reference req + * directly) and also leaves the SMB2 request + * outstanding on the processing queue. + * + * Using tevent_req_[nt]error() instead + * causes the outstanding SMB1/2/3 request to + * return with NT_STATUS_INVALID_HANDLE + * and removes it from the processing queue. + * + * The callback function called from this + * calls talloc_free(req). The destructor will remove + * itself from the fsp and the aio_requests array. + */ + if (fsp->is_directory) { + tevent_req_nterror(fsp->aio_requests[0], + NT_STATUS_INVALID_HANDLE); + } else { + tevent_req_error(fsp->aio_requests[0], EBADF); + } + + /* Paranoia to ensure we don't spin. */ + num_requests--; + if (fsp->num_aio_requests != num_requests) { + smb_panic("cannot cancel outstanding aio " + "requests"); + } + } +} + /**************************************************************************** Close a file. @@ -651,63 +720,7 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp, connection_struct *conn = fsp->conn; bool is_durable = false; - if (fsp->num_aio_requests != 0) { - unsigned num_requests = fsp->num_aio_requests; - - if (close_type != SHUTDOWN_CLOSE) { - /* - * reply_close and the smb2 close must have - * taken care of this. No other callers of - * close_file should ever have created async - * I/O. - * - * We need to panic here because if we close() - * the fd while we have outstanding async I/O - * requests, in the worst case we could end up - * writing to the wrong file. - */ - DEBUG(0, ("fsp->num_aio_requests=%u\n", - fsp->num_aio_requests)); - smb_panic("can not close with outstanding aio " - "requests"); - } - - /* - * For shutdown close, just drop the async requests - * including a potential close request pending for - * this fsp. Drop the close request first, the - * destructor for the aio_requests would execute it. - */ - TALLOC_FREE(fsp->deferred_close); - - while (fsp->num_aio_requests != 0) { - /* - * Previously we just called talloc_free() - * on the outstanding request, but this - * caused crashes (before the async callback - * functions were fixed not to reference req - * directly) and also leaves the SMB2 request - * outstanding on the processing queue. - * - * Using tevent_req_error() instead - * causes the outstanding SMB1/2/3 request to - * return with NT_STATUS_INVALID_HANDLE - * and removes it from the processing queue. - * - * The callback function called from this - * calls talloc_free(req). The destructor will remove - * itself from the fsp and the aio_requests array. - */ - tevent_req_error(fsp->aio_requests[0], EBADF); - - /* Paranoia to ensure we don't spin. */ - num_requests--; - if (fsp->num_aio_requests != num_requests) { - smb_panic("cannot cancel outstanding aio " - "requests"); - } - } - } + close_free_pending_aio(fsp, close_type); while (talloc_array_length(fsp->blocked_smb1_lock_reqs) != 0) { smbd_smb1_brl_finish_by_req( @@ -1152,30 +1165,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, notify_status = NT_STATUS_OK; } - if (fsp->num_aio_requests != 0) { - if (close_type != SHUTDOWN_CLOSE) { - /* - * We panic here because if we close() the fd while we - * have outstanding async I/O requests, an async IO - * request might use the fd. For directories the fd is - * read-only, so this is not as bad as with files, but - * still, better safe then sorry. - */ - DBG_ERR("fsp->num_aio_requests=%u\n", - fsp->num_aio_requests); - smb_panic("close with outstanding aio requests"); - return NT_STATUS_INTERNAL_ERROR; - } - - while (fsp->num_aio_requests != 0) { - /* - * The destructor of the req will remove itself from the - * fsp. Don't use TALLOC_FREE here, this will overwrite - * what the destructor just wrote into aio_requests[0]. - */ - talloc_free(fsp->aio_requests[0]); - } - } + close_free_pending_aio(fsp, close_type); /* * NT can set delete_on_close of the last open -- Samba Shared Repository