From 935e48d7d540054f791deb6c999b6f06e8f017e2 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 15 May 2020 15:19:45 +0200 Subject: [PATCH] winbindd: Fix a use-after-free when winbind clients exit Bug: https://bugzilla.samba.org/show_bug.cgi?id=14382 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Volker Lendecke Signed-off-by: Stefan Metzmacher Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Tue May 19 10:45:06 UTC 2020 on sn-devel-184 (cherry picked from commit 68380ebaa60c64311cc1081f700d571abbf69f4f) --- source3/winbindd/winbindd_dual.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 8188ed097df..73715b4b57d 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -202,7 +202,32 @@ struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->child = child; - state->request = request; + + /* + * We have to make a copy of "request", because our caller + * might drop us via talloc_free(). + * + * The talloc_move() magic in wb_child_request_cleanup() keeps + * all the requests, but if we are sitting deep within + * writev_send() down to the client, we have given it the + * pointer to "request". As our caller lost interest, it will + * just free "request", while writev_send still references it. + */ + + state->request = talloc_memdup(state, request, sizeof(*request)); + if (tevent_req_nomem(state->request, req)) { + return tevent_req_post(req, ev); + } + + if (request->extra_data.data != NULL) { + state->request->extra_data.data = talloc_memdup( + state->request, + request->extra_data.data, + request->extra_len); + if (tevent_req_nomem(state->request->extra_data.data, req)) { + return tevent_req_post(req, ev); + } + } subreq = tevent_queue_wait_send(state, ev, child->queue); if (tevent_req_nomem(subreq, req)) { @@ -330,6 +355,7 @@ static void wb_child_request_cleanup(struct tevent_req *req, subreq = talloc_move(state->child->queue, &state->subreq); talloc_move(subreq, &state->queue_subreq); + talloc_move(subreq, &state->request); tevent_req_set_callback(subreq, wb_child_request_orphaned, state->child); -- 2.20.1