1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

CVE-2015-5370: s4:rpc_server: verify the protocol headers before processing pdus

On protocol errors we should send BIND_NAK or FAULT and mark the
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>
This commit is contained in:
Stefan Metzmacher 2015-06-26 08:10:46 +02:00
parent caa1e75661
commit c0d74ca7af

View File

@ -452,6 +452,18 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call,
}
}
static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call,
const char *reason)
{
if (call->conn->terminate != NULL) {
return;
}
call->terminate_reason = talloc_strdup(call, reason);
if (call->terminate_reason == NULL) {
call->terminate_reason = __location__;
}
}
/*
return a dcerpc bind_nak
@ -464,6 +476,12 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
NTSTATUS status;
static const uint8_t _pad[3] = { 0, };
/*
* We add the call to the pending_call_list
* in order to defer the termination.
*/
dcesrv_call_disconnect_after(call, "dcesrv_bind_nak");
/* setup a bind_nak */
dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
pkt.auth_length = 0;
@ -501,6 +519,19 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
return NT_STATUS_OK;
}
static NTSTATUS dcesrv_fault_disconnect(struct dcesrv_call_state *call,
uint32_t fault_code)
{
/*
* We add the call to the pending_call_list
* in order to defer the termination.
*/
dcesrv_call_disconnect_after(call, "dcesrv_fault_disconnect");
return dcesrv_fault_with_flags(call, fault_code,
DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
}
static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
{
DLIST_REMOVE(c->conn->contexts, c);
@ -641,6 +672,23 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
const char *ep_prefix = "";
const char *endpoint = NULL;
status = dcerpc_verify_ncacn_packet_header(&call->pkt,
DCERPC_PKT_BIND,
call->pkt.u.bind.auth_info.length,
0, /* required flags */
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST |
DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
0x08 | /* this is not defined, but should be ignored */
DCERPC_PFC_FLAG_CONC_MPX |
DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
DCERPC_PFC_FLAG_MAYBE |
DCERPC_PFC_FLAG_OBJECT_UUID);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_bind_nak(call,
DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED);
}
/* max_recv_frag and max_xmit_frag result always in the same value! */
max_req = MIN(call->pkt.u.bind.max_xmit_frag,
call->pkt.u.bind.max_recv_frag);
@ -864,6 +912,24 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
*/
static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
{
NTSTATUS status;
status = dcerpc_verify_ncacn_packet_header(&call->pkt,
DCERPC_PKT_AUTH3,
call->pkt.u.auth3.auth_info.length,
0, /* required flags */
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST |
DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
0x08 | /* this is not defined, but should be ignored */
DCERPC_PFC_FLAG_CONC_MPX |
DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
DCERPC_PFC_FLAG_MAYBE |
DCERPC_PFC_FLAG_OBJECT_UUID);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
}
/* handle the auth3 in the auth code */
if (!dcesrv_auth_auth3(call)) {
return dcesrv_fault(call, DCERPC_FAULT_OTHER);
@ -1033,6 +1099,22 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
NTSTATUS status;
uint32_t context_id;
status = dcerpc_verify_ncacn_packet_header(&call->pkt,
DCERPC_PKT_ALTER,
call->pkt.u.alter.auth_info.length,
0, /* required flags */
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST |
DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
0x08 | /* this is not defined, but should be ignored */
DCERPC_PFC_FLAG_CONC_MPX |
DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
DCERPC_PFC_FLAG_MAYBE |
DCERPC_PFC_FLAG_OBJECT_UUID);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
}
/* handle any authentication that is being requested */
if (!dcesrv_auth_alter(call)) {
/* TODO: work out the right reject code */
@ -1310,9 +1392,27 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
/* we have to check the signing here, before combining the
pdus */
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
!dcesrv_auth_request(call, &blob)) {
return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
status = dcerpc_verify_ncacn_packet_header(&call->pkt,
DCERPC_PKT_REQUEST,
call->pkt.u.request.stub_and_verifier.length,
0, /* required_flags */
DCERPC_PFC_FLAG_FIRST |
DCERPC_PFC_FLAG_LAST |
DCERPC_PFC_FLAG_PENDING_CANCEL |
0x08 | /* this is not defined, but should be ignored */
DCERPC_PFC_FLAG_CONC_MPX |
DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
DCERPC_PFC_FLAG_MAYBE |
DCERPC_PFC_FLAG_OBJECT_UUID);
if (!NT_STATUS_IS_OK(status)) {
return dcesrv_fault_disconnect(call,
DCERPC_NCA_S_PROTO_ERROR);
}
if (!dcesrv_auth_request(call, &blob)) {
return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
}
}
/* see if this is a continued packet */