]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
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>
Wed, 30 Mar 2016 02:10:09 +0000 (04:10 +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 b7a80bef18029e48067c9f9cc1b8e1709eecc0b1..1b5a92489b0816bca59af99b29a5fa3b1e0221d6 100644 (file)
@@ -1628,6 +1628,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)
 {
@@ -1654,7 +1655,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;
                }
 
@@ -1674,6 +1675,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;
 }
@@ -1701,8 +1716,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 081c3e735ec2ea6a93a5487c15c01f1f300dd982..e1172c2c2917614002cc219edb2332f6ee59be91 100644 (file)
@@ -130,6 +130,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