1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00

r2180: added RPC flags "padcheck" which enables checking of all received pad

bytes to make sure they are zero. Non-zero values usually indicate one
of two things:

 - the server is leaking data through sending uninitialised memory
 - we have mistaken a real field in the IDL for padding

to differentiate between the two you really need to run with
"print,padcheck" and look carefully at whether the non-zero pad bytes
are random or appear to be deliberate.
This commit is contained in:
Andrew Tridgell 2004-09-02 10:45:58 +00:00 committed by Gerald (Jerry) Carter
parent 25f85efd75
commit 7fdb778f81
5 changed files with 70 additions and 16 deletions

View File

@ -42,7 +42,7 @@ struct ndr_token_list {
*/
struct ndr_pull {
uint32_t flags; /* LIBNDR_FLAG_* */
char *data;
uint8_t *data;
uint32_t data_size;
uint32_t offset;
@ -62,7 +62,7 @@ struct ndr_pull_save {
/* structure passed to functions that generate NDR formatted data */
struct ndr_push {
uint32_t flags; /* LIBNDR_FLAG_* */
char *data;
uint8_t *data;
uint32_t alloc_size;
uint32_t offset;
@ -112,6 +112,9 @@ struct ndr_print {
/* used to force a section of IDL to be little-endian */
#define LIBNDR_FLAG_LITTLE_ENDIAN (1<<17)
/* used to check if alignment padding is zero */
#define LIBNDR_FLAG_PAD_CHECK (1<<18)
/* useful macro for debugging */
#define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p)
@ -161,6 +164,9 @@ enum ndr_err_code {
#define NDR_PULL_ALIGN(ndr, n) do { \
if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \
if (ndr->flags & LIBNDR_FLAG_PAD_CHECK) { \
ndr_check_padding(ndr, n); \
} \
ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \
} \
if (ndr->offset >= ndr->data_size) { \

View File

@ -28,6 +28,31 @@
#define NDR_SSVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSSVAL(ndr->data,ofs,v); } else SSVAL(ndr->data,ofs,v); } while (0)
#define NDR_SIVAL(ndr, ofs, v) do { if (NDR_BE(ndr)) { RSIVAL(ndr->data,ofs,v); } else SIVAL(ndr->data,ofs,v); } while (0)
/*
check for data leaks from the server by looking for non-zero pad bytes
these could also indicate that real structure elements have been
mistaken for padding in the IDL
*/
void ndr_check_padding(struct ndr_pull *ndr, size_t n)
{
size_t ofs2 = (ndr->offset + (n-1)) & ~(n-1);
int i;
for (i=ndr->offset;i<ofs2;i++) {
if (ndr->data[i] != 0) {
break;
}
}
if (i<ofs2) {
DEBUG(0,("WARNING: Non-zero padding to %d: ", n));
for (i=ndr->offset;i<ofs2;i++) {
DEBUG(0,("%02x ", ndr->data[i]));
}
DEBUG(0,("\n"));
}
}
/*
parse a uint8
*/

View File

@ -102,16 +102,33 @@ void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
}
}
/*
setup for a ndr pull, also setting up any flags from the binding string
*/
static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
{
struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
if (ndr == NULL) return ndr;
if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
}
return ndr;
}
/*
parse a data blob into a dcerpc_packet structure. This handles both
input and output packets
*/
static NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
struct dcerpc_packet *pkt)
{
struct ndr_pull *ndr;
ndr = ndr_pull_init_blob(blob, mem_ctx);
ndr = ndr_pull_init_flags(p, blob, mem_ctx);
if (!ndr) {
return NT_STATUS_NO_MEMORY;
}
@ -137,10 +154,10 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
/* non-signed packets are simpler */
if (!p->security_state.auth_info || !p->security_state.generic_state) {
return dcerpc_pull(blob, mem_ctx, pkt);
return dcerpc_pull(p, blob, mem_ctx, pkt);
}
ndr = ndr_pull_init_blob(blob, mem_ctx);
ndr = ndr_pull_init_flags(p, blob, mem_ctx);
if (!ndr) {
return NT_STATUS_NO_MEMORY;
}
@ -172,7 +189,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
pkt->u.response.stub_and_verifier.length -= auth_blob.length;
/* pull the auth structure */
ndr = ndr_pull_init_blob(&auth_blob, mem_ctx);
ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
if (!ndr) {
return NT_STATUS_NO_MEMORY;
}
@ -439,7 +456,7 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
}
/* unmarshall the NDR */
status = dcerpc_pull(&blob, mem_ctx, &pkt);
status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -513,7 +530,7 @@ NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
}
/* unmarshall the NDR */
status = dcerpc_pull(&blob, mem_ctx, &pkt);
status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -855,7 +872,8 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
for that to the NDR we initially generated. If they don't match then we know
we must have a bug in either the pull or push side of our code
*/
static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
TALLOC_CTX *mem_ctx,
DATA_BLOB blob,
size_t struct_size,
NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
@ -872,7 +890,7 @@ static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
return NT_STATUS_NO_MEMORY;
}
pull = ndr_pull_init_blob(&blob, mem_ctx);
pull = ndr_pull_init_flags(p, &blob, mem_ctx);
if (!pull) {
return NT_STATUS_NO_MEMORY;
}
@ -918,7 +936,8 @@ static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
initially generated. If they don't match then we know we must have a
bug in either the pull or push side of our code
*/
static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
TALLOC_CTX *mem_ctx,
void *struct_ptr,
size_t struct_size,
NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
@ -950,7 +969,7 @@ static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
blob = ndr_push_blob(push);
pull = ndr_pull_init_blob(&blob, mem_ctx);
pull = ndr_pull_init_flags(p, &blob, mem_ctx);
if (!pull) {
return NT_STATUS_NO_MEMORY;
}
@ -1032,7 +1051,7 @@ struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
request = ndr_push_blob(push);
if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size,
status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
ndr_push, ndr_pull);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
@ -1086,7 +1105,7 @@ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
talloc_free(req);
/* prepare for ndr_pull_* */
pull = ndr_pull_init_blob(&response, ndr.mem_ctx);
pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
if (!pull) {
return NT_STATUS_NO_MEMORY;
}
@ -1105,7 +1124,7 @@ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
}
if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
status = dcerpc_ndr_validate_out(ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
ndr.ndr_push, ndr.ndr_pull);
if (!NT_STATUS_IS_OK(status)) {
return status;

View File

@ -101,6 +101,9 @@ struct dcerpc_pipe {
#define DCERPC_AUTH_OPTIONS (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL_ANY)
/* check incoming pad bytes */
#define DCERPC_DEBUG_PAD_CHECK (1<<12)
/*
this is used to find pointers to calls
*/

View File

@ -277,6 +277,7 @@ static const struct {
{"seal", DCERPC_SEAL},
{"validate", DCERPC_DEBUG_VALIDATE_BOTH},
{"print", DCERPC_DEBUG_PRINT_BOTH},
{"padcheck", DCERPC_DEBUG_PAD_CHECK},
{"bigendian", DCERPC_PUSH_BIGENDIAN}
};