From: Jeremy Allison Date: Tue, 7 Jul 2015 07:15:39 +0000 (+0200) Subject: CVE-2015-5370: s3:rpc_server: ensure that the message ordering doesn't violate the... X-Git-Tag: samba-4.2.10~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0239bfa562ee303c4ac204375b3c66ca287f6cb0;p=thirdparty%2Fsamba.git CVE-2015-5370: s3:rpc_server: ensure that the message ordering doesn't violate the spec The first pdu is always a BIND. REQUEST pdus are only allowed once the authentication is finished. A simple anonymous authentication is finished after the BIND. Real authentication may need additional ALTER or AUTH3 exchanges. Pair-Programmed-With: Stefan Metzmacher BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher Reviewed-by: Günther Deschner --- diff --git a/source3/rpc_server/rpc_handles.c b/source3/rpc_server/rpc_handles.c index 4e2edc6db96..62b545c55c9 100644 --- a/source3/rpc_server/rpc_handles.c +++ b/source3/rpc_server/rpc_handles.c @@ -69,6 +69,7 @@ int make_base_pipes_struct(TALLOC_CTX *mem_ctx, p->msg_ctx = msg_ctx; p->transport = transport; p->endian = endian; + p->allow_bind = true; p->remote_address = tsocket_address_copy(remote_address, p); if (p->remote_address == NULL) { diff --git a/source3/rpc_server/rpc_pipes.h b/source3/rpc_server/rpc_pipes.h index 14b870532c8..d44ee92bd5c 100644 --- a/source3/rpc_server/rpc_pipes.h +++ b/source3/rpc_server/rpc_pipes.h @@ -130,6 +130,13 @@ struct pipes_struct { bool pipe_bound; + /* + * States we can be in. + */ + bool allow_alter; + bool allow_bind; + bool allow_auth3; + /* * Set the DCERPC_FAULT to return. */ diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 96bf212b705..3b36a2a6213 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -282,6 +282,9 @@ static bool setup_bind_nak(struct pipes_struct *p, struct ncacn_packet *pkt) p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE; p->auth.auth_type = DCERPC_AUTH_TYPE_NONE; p->pipe_bound = False; + p->allow_bind = false; + p->allow_alter = false; + p->allow_auth3 = false; return True; } @@ -636,11 +639,11 @@ static bool api_pipe_bind_req(struct pipes_struct *p, DATA_BLOB auth_blob = data_blob_null; const struct ndr_interface_table *table; - /* No rebinds on a bound pipe - use alter context. */ - if (p->pipe_bound) { - DEBUG(2,("Rejecting bind request on bound rpc connection\n")); + if (!p->allow_bind) { + DEBUG(2,("Pipe not in allow bind state\n")); return setup_bind_nak(p, pkt); } + p->allow_bind = false; if (pkt->u.bind.num_contexts == 0) { DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n")); @@ -722,7 +725,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p, bind_ack_ctx.reason.value = 0; bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0]; } else { - p->pipe_bound = False; /* Rejection reason: abstract syntax not supported */ bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX; @@ -751,7 +753,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p, } else { p->auth.auth_type = DCERPC_AUTH_TYPE_NONE; p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE; - p->pipe_bound = True; } ZERO_STRUCT(u.bind_ack); @@ -838,6 +839,22 @@ static bool api_pipe_bind_req(struct pipes_struct *p, p->out_data.current_pdu_sent = 0; TALLOC_FREE(auth_blob.data); + + if (bind_ack_ctx.result == 0) { + p->allow_alter = true; + p->allow_auth3 = true; + if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) { + status = pipe_auth_verify_final(p); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("pipe_auth_verify_final failed: %s\n", + nt_errstr(status))); + goto err_exit; + } + } + } else { + goto err_exit; + } + return True; err_exit: @@ -860,6 +877,11 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); + if (!p->allow_auth3) { + DEBUG(1, ("Pipe not in allow auth3 state.\n")); + goto err; + } + /* We can only finish if the pipe is unbound for now */ if (p->pipe_bound) { DEBUG(0, (__location__ ": Pipe already bound, " @@ -934,6 +956,10 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt) err: p->pipe_bound = false; + p->allow_bind = false; + p->allow_alter = false; + p->allow_auth3 = false; + TALLOC_FREE(p->auth.auth_ctx); return false; } @@ -957,6 +983,11 @@ static bool api_pipe_alter_context(struct pipes_struct *p, DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__)); + if (!p->allow_alter) { + DEBUG(1, ("Pipe not in allow alter state.\n")); + goto err_exit; + } + if (pkt->u.bind.assoc_group_id != 0) { assoc_gid = pkt->u.bind.assoc_group_id; } else { @@ -982,7 +1013,6 @@ static bool api_pipe_alter_context(struct pipes_struct *p, bind_ack_ctx.reason.value = 0; bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0]; } else { - p->pipe_bound = False; /* Rejection reason: abstract syntax not supported */ bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT; bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX; @@ -1383,6 +1413,10 @@ void set_incoming_fault(struct pipes_struct *p) p->in_data.pdu.length = 0; p->fault_state = DCERPC_FAULT_CANT_PERFORM; + p->allow_alter = false; + p->allow_auth3 = false; + p->pipe_bound = false; + DEBUG(10, ("Setting fault state\n")); }