From: Stefan Metzmacher Date: Fri, 26 Jun 2015 06:10:46 +0000 (+0200) Subject: CVE-2015-5370: s4:rpc_server: add infrastructure to terminate a connection after... X-Git-Tag: samba-4.2.10~58 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=409b8fd6bcdd1c5d3405c03ececec2eee60ed67f;p=thirdparty%2Fsamba.git CVE-2015-5370: s4:rpc_server: add infrastructure to terminate a connection after a response 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 Reviewed-by: Günther Deschner --- diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index b7a80bef180..1b5a92489b0 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -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; diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index 081c3e735ec..e1172c2c291 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -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