mirror of
https://github.com/samba-team/samba.git
synced 2025-10-22 07:33:16 +03:00
r21835: fixed a rpc server bug where we failed to remove a call from one
linked list when moving it to another. This could cause a valgrind
error under the RPC-SCANNER test.
(This used to be commit 9ba8c00851
)
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
4f0c0997ce
commit
dfb04271eb
@@ -400,6 +400,43 @@ static void dcesrv_init_hdr(struct ncacn_packet *pkt)
|
|||||||
pkt->drep[3] = 0;
|
pkt->drep[3] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
move a call from an existing linked list to the specified list. This
|
||||||
|
prevents bugs where we forget to remove the call from a previous
|
||||||
|
list when moving it.
|
||||||
|
*/
|
||||||
|
static void dcesrv_call_set_list(struct dcesrv_call_state *call,
|
||||||
|
enum dcesrv_call_list list)
|
||||||
|
{
|
||||||
|
switch (call->list) {
|
||||||
|
case DCESRV_LIST_NONE:
|
||||||
|
break;
|
||||||
|
case DCESRV_LIST_CALL_LIST:
|
||||||
|
DLIST_REMOVE(call->conn->call_list, call);
|
||||||
|
break;
|
||||||
|
case DCESRV_LIST_FRAGMENTED_CALL_LIST:
|
||||||
|
DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
|
||||||
|
break;
|
||||||
|
case DCESRV_LIST_PENDING_CALL_LIST:
|
||||||
|
DLIST_REMOVE(call->conn->pending_call_list, call);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
call->list = list;
|
||||||
|
switch (list) {
|
||||||
|
case DCESRV_LIST_NONE:
|
||||||
|
break;
|
||||||
|
case DCESRV_LIST_CALL_LIST:
|
||||||
|
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
|
||||||
|
break;
|
||||||
|
case DCESRV_LIST_FRAGMENTED_CALL_LIST:
|
||||||
|
DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
|
||||||
|
break;
|
||||||
|
case DCESRV_LIST_PENDING_CALL_LIST:
|
||||||
|
DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
return a dcerpc fault
|
return a dcerpc fault
|
||||||
*/
|
*/
|
||||||
@@ -433,7 +470,7 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code
|
|||||||
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
||||||
|
|
||||||
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
||||||
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
|
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
|
||||||
|
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
@@ -472,7 +509,7 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
|
|||||||
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
||||||
|
|
||||||
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
||||||
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
|
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
|
||||||
|
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
@@ -612,7 +649,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
|
|||||||
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
||||||
|
|
||||||
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
||||||
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
|
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
|
||||||
|
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
@@ -750,7 +787,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
|
|||||||
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
dcerpc_set_frag_length(&rep->blob, rep->blob.length);
|
||||||
|
|
||||||
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
|
||||||
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
|
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
|
||||||
|
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
@@ -814,7 +851,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* add the call to the pending list */
|
/* add the call to the pending list */
|
||||||
DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
|
dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
|
||||||
|
|
||||||
if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
|
if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
@@ -905,8 +942,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
|
|||||||
} while (stub.length != 0);
|
} while (stub.length != 0);
|
||||||
|
|
||||||
/* move the call from the pending to the finished calls list */
|
/* move the call from the pending to the finished calls list */
|
||||||
DLIST_REMOVE(call->conn->pending_call_list, call);
|
dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
|
||||||
DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
|
|
||||||
|
|
||||||
if (call->conn->call_list && call->conn->call_list->replies) {
|
if (call->conn->call_list && call->conn->call_list->replies) {
|
||||||
if (call->conn->transport.report_output_data) {
|
if (call->conn->transport.report_output_data) {
|
||||||
@@ -967,6 +1003,15 @@ static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t off
|
|||||||
data_blob_free(&blob);
|
data_blob_free(&blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
remove the call from the right list when freed
|
||||||
|
*/
|
||||||
|
static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
|
||||||
|
{
|
||||||
|
dcesrv_call_set_list(call, DCESRV_LIST_NONE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
process some input to a dcerpc endpoint server.
|
process some input to a dcerpc endpoint server.
|
||||||
*/
|
*/
|
||||||
@@ -987,6 +1032,9 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
|
|||||||
call->msg_ctx = dce_conn->msg_ctx;
|
call->msg_ctx = dce_conn->msg_ctx;
|
||||||
call->state_flags = call->conn->state_flags;
|
call->state_flags = call->conn->state_flags;
|
||||||
call->time = timeval_current();
|
call->time = timeval_current();
|
||||||
|
call->list = DCESRV_LIST_NONE;
|
||||||
|
|
||||||
|
talloc_set_destructor(call, dcesrv_call_dequeue);
|
||||||
|
|
||||||
blob = dce_conn->partial_input;
|
blob = dce_conn->partial_input;
|
||||||
blob.length = dcerpc_get_frag_length(&blob);
|
blob.length = dcerpc_get_frag_length(&blob);
|
||||||
@@ -1071,13 +1119,12 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
|
|||||||
just put it on the incoming_fragmented_call_list and wait for the rest */
|
just put it on the incoming_fragmented_call_list and wait for the rest */
|
||||||
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
|
if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
|
||||||
!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
|
!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
|
||||||
DLIST_ADD_END(dce_conn->incoming_fragmented_call_list, call,
|
dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
|
||||||
struct dcesrv_call_state *);
|
|
||||||
return NT_STATUS_OK;
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This removes any fragments we may have had stashed away */
|
/* This removes any fragments we may have had stashed away */
|
||||||
DLIST_REMOVE(dce_conn->incoming_fragmented_call_list, call);
|
dcesrv_call_set_list(call, DCESRV_LIST_NONE);
|
||||||
|
|
||||||
switch (call->pkt.ptype) {
|
switch (call->pkt.ptype) {
|
||||||
case DCERPC_PKT_BIND:
|
case DCERPC_PKT_BIND:
|
||||||
@@ -1184,7 +1231,7 @@ _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
|
|||||||
|
|
||||||
if (call->replies == NULL) {
|
if (call->replies == NULL) {
|
||||||
/* we're done with the whole call */
|
/* we're done with the whole call */
|
||||||
DLIST_REMOVE(dce_conn->call_list, call);
|
dcesrv_call_set_list(call, DCESRV_LIST_NONE);
|
||||||
talloc_free(call);
|
talloc_free(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -71,6 +71,13 @@ struct dcesrv_interface {
|
|||||||
const void *private;
|
const void *private;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dcesrv_call_list {
|
||||||
|
DCESRV_LIST_NONE,
|
||||||
|
DCESRV_LIST_CALL_LIST,
|
||||||
|
DCESRV_LIST_FRAGMENTED_CALL_LIST,
|
||||||
|
DCESRV_LIST_PENDING_CALL_LIST
|
||||||
|
};
|
||||||
|
|
||||||
/* the state of an ongoing dcerpc call */
|
/* the state of an ongoing dcerpc call */
|
||||||
struct dcesrv_call_state {
|
struct dcesrv_call_state {
|
||||||
struct dcesrv_call_state *next, *prev;
|
struct dcesrv_call_state *next, *prev;
|
||||||
@@ -78,6 +85,11 @@ struct dcesrv_call_state {
|
|||||||
struct dcesrv_connection_context *context;
|
struct dcesrv_connection_context *context;
|
||||||
struct ncacn_packet pkt;
|
struct ncacn_packet pkt;
|
||||||
|
|
||||||
|
/*
|
||||||
|
which list this request is in, if any
|
||||||
|
*/
|
||||||
|
enum dcesrv_call_list list;
|
||||||
|
|
||||||
/* the backend can mark the call
|
/* the backend can mark the call
|
||||||
* with DCESRV_CALL_STATE_FLAG_ASYNC
|
* with DCESRV_CALL_STATE_FLAG_ASYNC
|
||||||
* that will cause the frontend to not touch r->out
|
* that will cause the frontend to not touch r->out
|
||||||
|
Reference in New Issue
Block a user