CVE-2013-4408:s3:Ensure we always check call_id when validating an RPC reply.
authorJeremy Allison <jra@samba.org>
Thu, 17 Oct 2013 21:44:35 +0000 (14:44 -0700)
committerKarolin Seeger <kseeger@samba.org>
Mon, 9 Dec 2013 06:05:46 +0000 (07:05 +0100)
Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/rpc_client/cli_pipe.c

index 0769d6dbe6bcfae97511d60e59c99ef579a6c915..87c3e8ff0b2a8cb8dd6ce953f8282fa328b15873 100644 (file)
@@ -386,6 +386,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
                                                struct ncacn_packet *pkt,
                                                DATA_BLOB *pdu,
                                                uint8_t expected_pkt_type,
+                                               uint32_t call_id,
                                                DATA_BLOB *rdata,
                                                DATA_BLOB *reply_pdu)
 {
@@ -484,7 +485,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
                          "from %s!\n",
                          (unsigned int)pkt->ptype,
                          rpccli_pipe_txt(talloc_tos(), cli)));
-               return NT_STATUS_INVALID_INFO_CLASS;
+               return NT_STATUS_RPC_PROTOCOL_ERROR;
        }
 
        if (pkt->ptype != expected_pkt_type) {
@@ -492,7 +493,15 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
                          "RPC packet type - %u, not %u\n",
                          rpccli_pipe_txt(talloc_tos(), cli),
                          pkt->ptype, expected_pkt_type));
-               return NT_STATUS_INVALID_INFO_CLASS;
+               return NT_STATUS_RPC_PROTOCOL_ERROR;
+       }
+
+       if (pkt->call_id != call_id) {
+               DEBUG(3, (__location__ ": Connection to %s got an unexpected "
+                         "RPC call_id - %u, not %u\n",
+                         rpccli_pipe_txt(talloc_tos(), cli),
+                         pkt->call_id, call_id));
+               return NT_STATUS_RPC_PROTOCOL_ERROR;
        }
 
        /* Do this just before return - we don't want to modify any rpc header
@@ -698,6 +707,7 @@ struct rpc_api_pipe_state {
        struct tevent_context *ev;
        struct rpc_pipe_client *cli;
        uint8_t expected_pkt_type;
+       uint32_t call_id;
 
        DATA_BLOB incoming_frag;
        struct ncacn_packet *pkt;
@@ -716,7 +726,8 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
                                            struct tevent_context *ev,
                                            struct rpc_pipe_client *cli,
                                            DATA_BLOB *data, /* Outgoing PDU */
-                                           uint8_t expected_pkt_type)
+                                           uint8_t expected_pkt_type,
+                                           uint32_t call_id)
 {
        struct tevent_req *req, *subreq;
        struct rpc_api_pipe_state *state;
@@ -730,6 +741,7 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
        state->ev = ev;
        state->cli = cli;
        state->expected_pkt_type = expected_pkt_type;
+       state->call_id = call_id;
        state->endianess = DCERPC_DREP_LE;
 
        /*
@@ -878,6 +890,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
                                                state->cli, state->pkt,
                                                &state->incoming_frag,
                                                state->expected_pkt_type,
+                                               state->call_id,
                                                &rdata,
                                                &state->reply_pdu);
 
@@ -1177,7 +1190,8 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
        if (is_last_frag) {
                subreq = rpc_api_pipe_send(state, ev, state->cli,
                                           &state->rpc_out,
-                                          DCERPC_PKT_RESPONSE);
+                                          DCERPC_PKT_RESPONSE,
+                                          state->call_id);
                if (subreq == NULL) {
                        goto fail;
                }
@@ -1313,7 +1327,8 @@ static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
        if (is_last_frag) {
                subreq = rpc_api_pipe_send(state, state->ev, state->cli,
                                           &state->rpc_out,
-                                          DCERPC_PKT_RESPONSE);
+                                          DCERPC_PKT_RESPONSE,
+                                          state->call_id);
                if (tevent_req_nomem(subreq, req)) {
                        return;
                }
@@ -1553,7 +1568,7 @@ struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
-                                  DCERPC_PKT_BIND_ACK);
+                                  DCERPC_PKT_BIND_ACK, state->rpc_call_id);
        if (subreq == NULL) {
                goto fail;
        }
@@ -1714,7 +1729,8 @@ static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
        }
 
        subreq = rpc_api_pipe_send(state, state->ev, state->cli,
-                                  &state->rpc_out, DCERPC_PKT_ALTER_RESP);
+                                  &state->rpc_out, DCERPC_PKT_ALTER_RESP,
+                                  state->rpc_call_id);
        if (subreq == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -1746,7 +1762,8 @@ static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
        }
 
        subreq = rpc_api_pipe_send(state, state->ev, state->cli,
-                                  &state->rpc_out, DCERPC_PKT_AUTH3);
+                                  &state->rpc_out, DCERPC_PKT_AUTH3,
+                                  state->rpc_call_id);
        if (subreq == NULL) {
                return NT_STATUS_NO_MEMORY;
        }