winbindd: Fix a use-after-free when winbind clients exit
authorVolker Lendecke <vl@samba.org>
Fri, 15 May 2020 13:19:45 +0000 (15:19 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 19 May 2020 10:45:06 +0000 (10:45 +0000)
Bug: https://bugzilla.samba.org/show_bug.cgi?id=14382

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Tue May 19 10:45:06 UTC 2020 on sn-devel-184

source3/winbindd/winbindd_dual.c

index 8ad2485324ea93fa1b0921fce2902348c17ad10c..47efe988d6520e70c311df8592637edb360d636f 100644 (file)
@@ -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);