s3:smb2cli_base: fix memory hierachy in smb2cli_req_recv()
authorStefan Metzmacher <metze@samba.org>
Fri, 8 Jul 2011 15:57:56 +0000 (17:57 +0200)
committerStefan Metzmacher <metze@samba.org>
Sat, 9 Jul 2011 10:40:28 +0000 (12:40 +0200)
We need to use talloc_reference() if there're more than one
response, but we use it in a way that the caller can't
call talloc_free() or talloc_unlink() on it.

metze

source3/libsmb/smb2cli_base.c
source3/libsmb/smb2cli_base.h
source3/libsmb/smb2cli_query_directory.c
source3/libsmb/smb2cli_read.c

index 37ac44dd07d4a69cebb191aca3f83d20484c9574..1b5a8a6798977e5477c4fe1978fd3148ee8070a2 100644 (file)
@@ -37,7 +37,7 @@ struct smb2cli_req_state {
        uint8_t hdr[64];
        uint8_t pad[7]; /* padding space for compounding */
 
-       uint8_t *inbuf;
+       /* always an array of 3 talloc elements */
        struct iovec *recv_iov;
 };
 
@@ -160,6 +160,12 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
        state->ev = ev;
        state->cli = cli;
 
+       state->recv_iov = talloc_zero_array(state, struct iovec, 3);
+       if (state->recv_iov == NULL) {
+               TALLOC_FREE(req);
+               return NULL;
+       }
+
        state->fixed = fixed;
        state->fixed_len = fixed_len;
        state->dyn = dyn;
@@ -439,6 +445,7 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
        struct cli_state *cli =
                tevent_req_callback_data(subreq,
                struct cli_state);
+       TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_req *req;
        struct iovec *iov;
        int i, num_iov;
@@ -447,7 +454,7 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
        ssize_t received;
        int err;
 
-       received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err);
+       received = read_smb_recv(subreq, frame, &inbuf, &err);
        TALLOC_FREE(subreq);
        if (received == -1) {
                if (cli->fd != -1) {
@@ -458,13 +465,14 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
                goto fail;
        }
 
-       status = smb2cli_inbuf_parse_compound(inbuf, talloc_tos(),
+       status = smb2cli_inbuf_parse_compound(inbuf, frame,
                                              &iov, &num_iov);
        if (!NT_STATUS_IS_OK(status)) {
                goto fail;
        }
 
        for (i=1; i<num_iov; i+=3) {
+               uint8_t *inbuf_ref = NULL;
                struct iovec *cur = &iov[i];
                uint8_t *inhdr = (uint8_t *)cur[0].iov_base;
                struct smb2cli_req_state *state;
@@ -479,13 +487,25 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
                }
                smb2cli_req_unset_pending(req);
                state = tevent_req_data(req, struct smb2cli_req_state);
-               if (i+3 >= num_iov) {
-                       /* last in chain */
-                       state->inbuf = inbuf;
+
+               /*
+                * Note: here we use talloc_reference() in a way
+                *       that does not expose it to the caller.
+                */
+               inbuf_ref = talloc_reference(state->recv_iov, inbuf);
+               if (tevent_req_nomem(inbuf_ref, req)) {
+                       continue;
                }
-               state->recv_iov = cur;
+
+               /* copy the related buffers */
+               state->recv_iov[0] = cur[0];
+               state->recv_iov[1] = cur[1];
+               state->recv_iov[2] = cur[2];
+
                tevent_req_done(req);
        }
+
+       TALLOC_FREE(frame);
        return;
  fail:
        /*
@@ -498,6 +518,8 @@ static void smb2cli_inbuf_received(struct tevent_req *subreq)
                smb2cli_req_unset_pending(req);
                tevent_req_nterror(req, status);
        }
+
+       TALLOC_FREE(frame);
 }
 
 NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
@@ -511,23 +533,17 @@ NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
+
+       status = NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
+
        if (body_size != 0) {
                if (body_size != SVAL(state->recv_iov[1].iov_base, 0)) {
                        return NT_STATUS_INVALID_NETWORK_RESPONSE;
                }
        }
-       talloc_steal(req, state->inbuf);
        if (piov != NULL) {
-               *piov = state->recv_iov;
+               *piov = talloc_move(mem_ctx, &state->recv_iov);
        }
 
-       return NT_STATUS(IVAL(state->recv_iov[0].iov_base, SMB2_HDR_STATUS));
-}
-
-uint8_t *smb2cli_req_inbuf(struct tevent_req *req)
-{
-       struct smb2cli_req_state *state = tevent_req_data(
-               req, struct smb2cli_req_state);
-
-       return state->inbuf;
+       return status;
 }
index 09a6b7faaa908ec91df6d20c81f07219ff5d16eb..9c49a8c8d343ac6d3cbefbe031b5e0d4bd3bf469 100644 (file)
@@ -42,6 +42,5 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
                                    uint16_t dyn_len);
 NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
                          struct iovec **piov, int body_size);
-uint8_t *smb2cli_req_inbuf(struct tevent_req *req);
 
 #endif
index fc6c0b79a06eaa44e3edad6924de612a33025a3e..554b26792734309f041c37c470b670d2da848e41 100644 (file)
@@ -27,7 +27,7 @@
 
 struct smb2cli_query_directory_state {
        uint8_t fixed[32];
-       uint8_t *inbuf;
+       struct iovec *recv_iov;
        uint8_t *data;
        uint32_t data_length;
 };
@@ -97,7 +97,7 @@ static void smb2cli_query_directory_done(struct tevent_req *subreq)
        struct iovec *iov;
        uint16_t data_offset;
 
-       status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 9);
+       status = smb2cli_req_recv(subreq, state, &iov, 9);
        if (tevent_req_nterror(req, status)) {
                return;
        }
@@ -110,7 +110,8 @@ static void smb2cli_query_directory_done(struct tevent_req *subreq)
                tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
                return;
        }
-       state->inbuf = smb2cli_req_inbuf(subreq);
+
+       state->recv_iov = iov;
        state->data = (uint8_t *)iov[2].iov_base;
        tevent_req_done(req);
 }
@@ -128,7 +129,7 @@ NTSTATUS smb2cli_query_directory_recv(struct tevent_req *req,
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
-       talloc_steal(mem_ctx, state->inbuf);
+       talloc_steal(mem_ctx, state->recv_iov);
        *data_length = state->data_length;
        *data = state->data;
        return NT_STATUS_OK;
index 79224e517a45a72fb4c0b596481bdbc958c515ca..c348c9937c5bae02aff31e1e9de8ee3e6dc2d541 100644 (file)
@@ -27,7 +27,7 @@
 
 struct smb2cli_read_state {
        uint8_t fixed[48];
-       uint8_t *inbuf;
+       struct iovec *recv_iov;
        uint8_t *data;
        uint32_t data_length;
 };
@@ -85,7 +85,7 @@ static void smb2cli_read_done(struct tevent_req *subreq)
        struct iovec *iov;
        uint8_t data_offset;
 
-       status = smb2cli_req_recv(subreq, talloc_tos(), &iov, 17);
+       status = smb2cli_req_recv(subreq, state, &iov, 17);
        if (tevent_req_nterror(req, status)) {
                return;
        }
@@ -98,7 +98,8 @@ static void smb2cli_read_done(struct tevent_req *subreq)
                tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
                return;
        }
-       state->inbuf = smb2cli_req_inbuf(subreq);
+
+       state->recv_iov = iov;
        state->data = (uint8_t *)iov[2].iov_base;
        tevent_req_done(req);
 }
@@ -114,7 +115,7 @@ NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
-       talloc_steal(mem_ctx, state->inbuf);
+       talloc_steal(mem_ctx, state->recv_iov);
        *data_length = state->data_length;
        *data = state->data;
        return NT_STATUS_OK;