[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Mon Mar 9 19:35:02 UTC 2020


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 <slow at 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 <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Mon Mar  9 19:34:27 UTC 2020 on sn-devel-184

commit f94cd10a211e2eae966ba4bd26921556bbe513fc
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit acb0b01761330864a23932f643f7ad4e3d374634
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 95cfcda13fe9a70b9955a7c44173d619eacb34c1
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 0e894f3e48285415f72cf7a68e26f1802fe8045d
Author: Ralph Boehme <slow at 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 <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at 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



More information about the samba-cvs mailing list