summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-07-08 17:57:56 +0200
committerStefan Metzmacher <metze@samba.org>2011-07-09 12:40:28 +0200
commitfacc110c79b9ec4e3b0509ad6b00e1fd464d3a33 (patch)
tree76b9b1fccccbf85e376d775dd08760279415e0fd /source3/libsmb
parent504d092aa7d83304373b001cbe68c65a62a824bb (diff)
downloadsamba-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/libsmb')
-rw-r--r--source3/libsmb/smb2cli_base.c52
-rw-r--r--source3/libsmb/smb2cli_base.h1
-rw-r--r--source3/libsmb/smb2cli_query_directory.c9
-rw-r--r--source3/libsmb/smb2cli_read.c9
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;