CVE-2015-5370: s4:rpc_server: add infrastructure to terminate a connection after...
authorStefan Metzmacher <metze@samba.org>
Fri, 26 Jun 2015 06:10:46 +0000 (08:10 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 12 Apr 2016 17:25:30 +0000 (19:25 +0200)
BIND_NAK or FAULT may mark a connection as to be terminated.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h

index 97bad0e6db372682c8c21354415c2341b12db384..03adc9d5fa1627a5d04492c5e97595fc6944ae6c 100644 (file)
@@ -1637,6 +1637,7 @@ struct dcesrv_sock_reply_state {
 };
 
 static void dcesrv_sock_reply_done(struct tevent_req *subreq);
+static void dcesrv_call_terminate_step1(struct tevent_req *subreq);
 
 static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
 {
@@ -1663,7 +1664,7 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
 
                DLIST_REMOVE(call->replies, rep);
 
-               if (call->replies == NULL) {
+               if (call->replies == NULL && call->terminate_reason == NULL) {
                        substate->call = call;
                }
 
@@ -1683,6 +1684,20 @@ static void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
                                        substate);
        }
 
+       if (call->terminate_reason != NULL) {
+               struct tevent_req *subreq;
+
+               subreq = tevent_queue_wait_send(call,
+                                               dce_conn->event_ctx,
+                                               dce_conn->send_queue);
+               if (!subreq) {
+                       dcesrv_terminate_connection(dce_conn, __location__);
+                       return;
+               }
+               tevent_req_set_callback(subreq, dcesrv_call_terminate_step1,
+                                       call);
+       }
+
        DLIST_REMOVE(call->conn->call_list, call);
        call->list = DCESRV_LIST_NONE;
 }
@@ -1710,8 +1725,51 @@ static void dcesrv_sock_reply_done(struct tevent_req *subreq)
        }
 }
 
+static void dcesrv_call_terminate_step2(struct tevent_req *subreq);
+
+static void dcesrv_call_terminate_step1(struct tevent_req *subreq)
+{
+       struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
+                                               struct dcesrv_call_state);
+       bool ok;
+       struct timeval tv;
+
+       /* make sure we stop send queue before removing subreq */
+       tevent_queue_stop(call->conn->send_queue);
+
+       ok = tevent_queue_wait_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ok) {
+               dcesrv_terminate_connection(call->conn, __location__);
+               return;
+       }
+
+       /* disconnect after 200 usecs */
+       tv = timeval_current_ofs_usec(200);
+       subreq = tevent_wakeup_send(call, call->conn->event_ctx, tv);
+       if (subreq == NULL) {
+               dcesrv_terminate_connection(call->conn, __location__);
+               return;
+       }
+       tevent_req_set_callback(subreq, dcesrv_call_terminate_step2,
+                               call);
+}
+
+static void dcesrv_call_terminate_step2(struct tevent_req *subreq)
+{
+       struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
+                                               struct dcesrv_call_state);
+       bool ok;
 
+       ok = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ok) {
+               dcesrv_terminate_connection(call->conn, __location__);
+               return;
+       }
 
+       dcesrv_terminate_connection(call->conn, call->terminate_reason);
+}
 
 struct dcesrv_socket_context {
        const struct dcesrv_endpoint *endpoint;
index 3d1f5deecb625cf0925b6935f1d26b85c1ac4c7b..ad19612de0b302d47c5628a3712cd29f1f1fe407 100644 (file)
@@ -135,6 +135,9 @@ struct dcesrv_call_state {
 
        /* this is used by the boilerplate code to generate DCERPC faults */
        uint32_t fault_code;
+
+       /* the reason why we terminate the connection after sending a response */
+       const char *terminate_reason;
 };
 
 #define DCESRV_HANDLE_ANY 255