From de1b2b0d07ef32ff8b9ab4fbf2bec51b227256ec Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 11 Jul 2025 06:02:13 +0200 Subject: [PATCH] libndr: add support for unions to ndr_pull_struct_blob_noalloc() and ndr_push_struct_into_fixed_blob() The union switch value is stored by ndr_token_store() which uses talloc to manage ndr.switch_list. Preallocate a ndr_token array and ndr_token_list on the stack of size ndr_token_list.fixed_alloc_count and optionally use that in ndr_token_store(). Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher --- librpc/ndr/libndr.h | 1 + librpc/ndr/ndr.c | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h index 344f08b20a1..7ee706c6085 100644 --- a/librpc/ndr/libndr.h +++ b/librpc/ndr/libndr.h @@ -44,6 +44,7 @@ struct ndr_token; struct ndr_token_list { struct ndr_token *tokens; uint32_t count; + uint32_t fixed_alloc_count; }; struct ndr_compression_state; diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c index 082bacc2fa6..fc08b6661f8 100644 --- a/librpc/ndr/ndr.c +++ b/librpc/ndr/ndr.c @@ -48,6 +48,11 @@ */ #define NDR_TOKEN_MAX_LIST_SIZE 65535 +/* + * An arbitrary limit used by the fixed-size pull/push functions + */ +#define NDR_FIXED_SIZE_MARSHALL_MAX_TOKENS 10 + size_t ndr_token_max_list_size(void) { return NDR_TOKEN_MAX_LIST_SIZE; }; @@ -1081,6 +1086,12 @@ _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx, const void *key, uint32_t value) { + if (list->fixed_alloc_count != 0) { + if (list->count >= list->fixed_alloc_count) { + return NDR_ERR_RANGE; + } + goto store; + } if (list->tokens == NULL) { list->tokens = talloc_array(mem_ctx, struct ndr_token, 10); if (list->tokens == NULL) { @@ -1115,6 +1126,7 @@ _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx, list->tokens = new_tokens; } } +store: list->tokens[list->count].key = key; list->tokens[list->count].value = value; list->count++; @@ -1511,10 +1523,16 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf, * This allows us to keep the safety of the PIDL-generated * code without the talloc() overhead. */ + struct ndr_token tokens[NDR_FIXED_SIZE_MARSHALL_MAX_TOKENS]; + struct ndr_token_list switch_list = { + .tokens = tokens, + .fixed_alloc_count = ARRAY_SIZE(tokens), + }; struct ndr_pull ndr = { .data = discard_const_p(uint8_t, buf), .data_size = buflen, .current_mem_ctx = (void *)-1, + .switch_list = switch_list, }; NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p)); @@ -1632,10 +1650,16 @@ _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob( DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn) { + struct ndr_token tokens[NDR_FIXED_SIZE_MARSHALL_MAX_TOKENS]; + struct ndr_token_list switch_list = { + .tokens = tokens, + .fixed_alloc_count = ARRAY_SIZE(tokens), + }; struct ndr_push ndr = { .data = blob->data, .alloc_size = blob->length, - .fixed_buf_size = true + .fixed_buf_size = true, + .switch_list = switch_list, }; NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p)); -- 2.47.2