From facc110c79b9ec4e3b0509ad6b00e1fd464d3a33 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Jul 2011 17:57:56 +0200 Subject: s3:smb2cli_base: fix memory hierachy in smb2cli_req_recv() 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 | 52 +++++++++++++++++++++----------- source3/libsmb/smb2cli_base.h | 1 - source3/libsmb/smb2cli_query_directory.c | 9 +++--- source3/libsmb/smb2cli_read.c | 9 +++--- 4 files changed, 44 insertions(+), 27 deletions(-) diff --git a/source3/libsmb/smb2cli_base.c b/source3/libsmb/smb2cli_base.c index 37ac44dd07..1b5a8a6798 100644 --- a/source3/libsmb/smb2cli_base.c +++ b/source3/libsmb/smb2cli_base.c @@ -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) { - /* 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; } diff --git a/source3/libsmb/smb2cli_base.h b/source3/libsmb/smb2cli_base.h index 09a6b7faaa..9c49a8c8d3 100644 --- a/source3/libsmb/smb2cli_base.h +++ b/source3/libsmb/smb2cli_base.h @@ -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 diff --git a/source3/libsmb/smb2cli_query_directory.c b/source3/libsmb/smb2cli_query_directory.c index fc6c0b79a0..554b267927 100644 --- a/source3/libsmb/smb2cli_query_directory.c +++ b/source3/libsmb/smb2cli_query_directory.c @@ -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; diff --git a/source3/libsmb/smb2cli_read.c b/source3/libsmb/smb2cli_read.c index 79224e517a..c348c9937c 100644 --- a/source3/libsmb/smb2cli_read.c +++ b/source3/libsmb/smb2cli_read.c @@ -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; -- cgit