diff options
author | Stefan Metzmacher <metze@samba.org> | 2011-07-08 17:57:56 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2011-07-09 12:40:28 +0200 |
commit | facc110c79b9ec4e3b0509ad6b00e1fd464d3a33 (patch) | |
tree | 76b9b1fccccbf85e376d775dd08760279415e0fd /source3 | |
parent | 504d092aa7d83304373b001cbe68c65a62a824bb (diff) | |
download | samba-facc110c79b9ec4e3b0509ad6b00e1fd464d3a33.tar.gz samba-facc110c79b9ec4e3b0509ad6b00e1fd464d3a33.tar.bz2 samba-facc110c79b9ec4e3b0509ad6b00e1fd464d3a33.zip |
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
Diffstat (limited to 'source3')
-rw-r--r-- | source3/libsmb/smb2cli_base.c | 52 | ||||
-rw-r--r-- | source3/libsmb/smb2cli_base.h | 1 | ||||
-rw-r--r-- | source3/libsmb/smb2cli_query_directory.c | 9 | ||||
-rw-r--r-- | 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; 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; } 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; |