From: Jeremy Allison Date: Fri, 28 Feb 2020 23:55:36 +0000 (-0800) Subject: s3: VFS: vfs_glusterfs. Protect vfs_gluster_pwrite_done() from accessing a freed... X-Git-Tag: ldb-2.2.0~1496 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=67910c751c9f5ce8cdd1e57b34e51e5b7163838b;p=thirdparty%2Fsamba.git s3: VFS: vfs_glusterfs. Protect vfs_gluster_pwrite_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_gluster_pwrite_done(), just throw away the result if state->req == NULL. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14301 Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke --- diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 52c33725b8d..4e978f168d6 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -967,6 +967,15 @@ static void vfs_gluster_pwrite_do(void *private_data) static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_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; } @@ -981,6 +990,17 @@ static void vfs_gluster_pwrite_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("gluster pwrite request abandoned in flight\n"); + TALLOC_FREE(state); + return; + } if (ret != 0) { if (ret != EAGAIN) { tevent_req_error(req, ret);