]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2015-5370: s4:rpc_server: correctly maintain dcesrv_connection->max_{recv,xmit...
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:08 +0000 (04:10 +0200)
These values are controlled by the client but only in a range between
2048 and 5840 (including these values in 8 byte steps).
recv and xmit result always in same min value.

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/common/reply.c
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h

index 5c02e052349f840ea8a48318c93f87197cd0f711..322138c75e697f6fa418414d89d4fa672fa6bed6 100644 (file)
@@ -183,7 +183,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
 
        /* we can write a full max_recv_frag size, minus the dcerpc
           request header size */
-       chunk_size = call->conn->cli_max_recv_frag;
+       chunk_size = call->conn->max_xmit_frag;
        chunk_size -= DCERPC_REQUEST_LENGTH;
        if (call->conn->auth_state.auth_info &&
            call->conn->auth_state.gensec_security) {
index 0fc7955a4ae1e4ece92353c82762e8c3d037ee86..6df9f77bb1178417c45f5560e2e5e705c19e78d0 100644 (file)
@@ -408,6 +408,8 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
        p->msg_ctx = msg_ctx;
        p->server_id = server_id;
        p->state_flags = state_flags;
+       p->max_recv_frag = 5840;
+       p->max_xmit_frag = 5840;
 
        *_p = p;
        return NT_STATUS_OK;
@@ -633,6 +635,24 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        uint32_t context_id;
        const struct dcesrv_interface *iface;
        uint32_t extra_flags = 0;
+       uint16_t max_req = 0;
+       uint16_t max_rep = 0;
+
+       /* 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);
+       /*
+        * The values are between 2048 and 5840 tested against Windows 2012R2
+        * via ncacn_ip_tcp on port 135.
+        */
+       max_req = MAX(2048, max_req);
+       max_rep = MIN(max_req, call->conn->max_recv_frag);
+       /* They are truncated to an 8 byte boundary. */
+       max_rep &= 0xFFF8;
+
+       /* max_recv_frag and max_xmit_frag result always in the same value! */
+       call->conn->max_recv_frag = max_rep;
+       call->conn->max_xmit_frag = max_rep;
 
        /*
          if provided, check the assoc_group is valid
@@ -722,10 +742,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
                }
        }
 
-       if (call->conn->cli_max_recv_frag == 0) {
-               call->conn->cli_max_recv_frag = MIN(0x2000, call->pkt.u.bind.max_recv_frag);
-       }
-
        if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
            (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
                call->context->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
@@ -749,8 +765,8 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        pkt.call_id = call->pkt.call_id;
        pkt.ptype = DCERPC_PKT_BIND_ACK;
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
-       pkt.u.bind_ack.max_xmit_frag = call->conn->cli_max_recv_frag;
-       pkt.u.bind_ack.max_recv_frag = 0x2000;
+       pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag;
+       pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
 
        /*
          make it possible for iface->bind() to specify the assoc_group_id
@@ -932,8 +948,8 @@ static NTSTATUS dcesrv_alter_resp(struct dcesrv_call_state *call,
                }
        }
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
-       pkt.u.alter_resp.max_xmit_frag = 0x2000;
-       pkt.u.alter_resp.max_recv_frag = 0x2000;
+       pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
+       pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
        if (result == 0) {
                pkt.u.alter_resp.assoc_group_id = call->context->assoc_group->id;
        } else {
index bc1b8a9745f42993999b561fb316247c6d52b24c..081c3e735ec2ea6a93a5487c15c01f1f300dd982 100644 (file)
@@ -204,7 +204,8 @@ struct dcesrv_connection {
        struct dcesrv_call_state *call_list;
 
        /* the maximum size the client wants to receive */
-       uint32_t cli_max_recv_frag;
+       uint16_t max_recv_frag;
+       uint16_t max_xmit_frag;
 
        DATA_BLOB partial_input;