summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-09-02 10:45:58 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:58:29 -0500
commit4d390df586ff1b4ba4b5bbfbde3c6393c6f5c829 (patch)
tree4f298868ff860da16f31069e8282fced7eb9f80a
parent01f704e5ecbf371e60640c45c7e9d3f66a5a9fe0 (diff)
downloadsamba-4d390df586ff1b4ba4b5bbfbde3c6393c6f5c829.tar.gz
samba-4d390df586ff1b4ba4b5bbfbde3c6393c6f5c829.tar.bz2
samba-4d390df586ff1b4ba4b5bbfbde3c6393c6f5c829.zip
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 used to be commit 7fdb778f81f14aaab75ab204431e4342a462957a)
-rw-r--r--source4/librpc/ndr/libndr.h10
-rw-r--r--source4/librpc/ndr/ndr_basic.c25
-rw-r--r--source4/librpc/rpc/dcerpc.c47
-rw-r--r--source4/librpc/rpc/dcerpc.h3
-rw-r--r--source4/librpc/rpc/dcerpc_util.c1
5 files changed, 70 insertions, 16 deletions
diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h
index cea7290577..9940dc2c05 100644
--- a/source4/librpc/ndr/libndr.h
+++ b/source4/librpc/ndr/libndr.h
@@ -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) { \
diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c
index 7f36f7e4ba..d015cc5e48 100644
--- a/source4/librpc/ndr/ndr_basic.c
+++ b/source4/librpc/ndr/ndr_basic.c
@@ -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
*/
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index ae56213919..ec22696419 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -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;
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 91899a9fec..1443e10927 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -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
*/
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index 5a3b875c01..c04937353c 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -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}
};