From: Andrew Bartlett Date: Fri, 21 May 2021 22:17:49 +0000 (+1200) Subject: pidl: Avoid leaving array_length NDR tokens around X-Git-Tag: tevent-0.11.0~689 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7d4f93cfdee0a2005be11880f8dd31f55149369;p=thirdparty%2Fsamba.git pidl: Avoid leaving array_length NDR tokens around In many cases these can and should be consumed as soon as they are used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14710 Signed-off-by: Andrew Bartlett Reviewed-by: Douglas Bagnall --- diff --git a/librpc/ABI/ndr-2.0.0.sigs b/librpc/ABI/ndr-2.0.0.sigs index 017b9b3500d..dbd65360eb8 100644 --- a/librpc/ABI/ndr-2.0.0.sigs +++ b/librpc/ABI/ndr-2.0.0.sigs @@ -16,10 +16,10 @@ _ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const _ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...) ndr_align_size: size_t (uint32_t, size_t) ndr_charset_length: uint32_t (const void *, charset_t) -ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t) ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t) ndr_check_padding: void (struct ndr_pull *, size_t) ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t) +ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t) ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t) ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *) ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *) @@ -249,6 +249,7 @@ ndr_size_string_array: size_t (const char **, uint32_t, int) ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t) ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t) ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int) +ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *) ndr_string_array_size: size_t (struct ndr_push *, const char *) ndr_string_length: uint32_t (const void *, uint32_t) ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *) diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h index 156f70216c2..58b04e98371 100644 --- a/librpc/ndr/libndr.h +++ b/librpc/ndr/libndr.h @@ -659,7 +659,9 @@ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32 enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size); enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p); enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length); +enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length); enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, const void *p, uint32_t length); +enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length); enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count); enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count); enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val); diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c index f5502b7c705..eaeb3b0e094 100644 --- a/librpc/ndr/ndr.c +++ b/librpc/ndr/ndr.c @@ -1143,12 +1143,21 @@ _PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void } /* - check the stored array length field + * check the stored array length field and remove from the stored list + * (the array_size NDR token list). We try to remove when possible to + * avoid the list growing towards the bounds check + */ +_PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length) +{ + return ndr_token_retrieve(&ndr->array_length_list, p, length); +} +/* + check the stored array length field, removing it from the list */ -_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, const void *p, uint32_t length) +_PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length) { uint32_t stored; - NDR_CHECK(ndr_token_peek(&ndr->array_length_list, p, &stored)); + NDR_CHECK(ndr_steal_array_length(ndr, p, &stored)); if (stored != length) { return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "Bad array length - got %u expected %u\n", diff --git a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm index 011fd3fa0c4..5927e973c32 100644 --- a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm +++ b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm @@ -387,8 +387,12 @@ sub ParseArrayPullGetLength($$$$$$;$) } my $array_length = "length_$e->{NAME}_$l->{LEVEL_INDEX}"; - - $self->pidl("NDR_CHECK(ndr_get_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", &$array_length));"); + if ($l->{IS_VARYING} and (defined($l->{LENGTH_IS}) or not $l->{IS_ZERO_TERMINATED})) { + $self->pidl("NDR_CHECK(ndr_get_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", &$array_length));"); + } else { + # This will be the last use of the array_length token + $self->pidl("NDR_CHECK(ndr_steal_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", &$array_length));"); + } if (my $range = has_property($e, "range")) { my ($low, $high) = parse_range($range); @@ -451,7 +455,8 @@ sub ParseArrayPullHeader($$$$$$) check_null_pointer($e, $env, sub { $self->defer(shift); }, "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for length_is()\");"), check_fully_dereferenced($e, $env)); - $self->defer("NDR_CHECK(ndr_check_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));"); + # This will be deferred until after the last ndr_get_array_length() + $self->defer("NDR_CHECK(ndr_check_steal_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));"); $self->defer_deindent; $self->defer("}"); }