diff options
author | Andreas Schneider <asn@samba.org> | 2019-12-16 15:50:17 +0100 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2019-12-20 07:35:41 +0000 |
commit | f11e207e01c52566c47e350ff240fe95392de0c3 (patch) | |
tree | 41db2ac35dcf7b265e5c54adece51b2268c142c6 | |
parent | 0bd479140c18ab79479ced4f25f366744c3afe18 (diff) | |
download | samba-f11e207e01c52566c47e350ff240fe95392de0c3.tar.gz |
librpc: Fix string length checking in ndr_pull_charset_to_null()
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14219
Pair-Programmed-With: Guenther Deschner <gd@samba.org>
Signed-off-by: Guenther Deschner <gd@samba.org>
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r-- | librpc/ndr/ndr_string.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/librpc/ndr/ndr_string.c b/librpc/ndr/ndr_string.c index eb0af57a6ab..25f211b2ad3 100644 --- a/librpc/ndr/ndr_string.c +++ b/librpc/ndr/ndr_string.c @@ -560,6 +560,47 @@ _PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size) return i+1; } +/** + * @brief Get the string length including the null terminator if available. + * + * This checks the string length based on the elements. The returned number + * includes the terminating null byte(s) if found. + * + * @param[in] _var The string the calculate the length for. + * + * @param[in] length The length of the buffer passed by _var. + * + * @param[in] element_size The element_size of a string char in bytes. + * + * @return The length of the strings or 0. + */ +static uint32_t ndr_string_n_length(const void *_var, + size_t length, + uint32_t element_size) +{ + size_t i = 0; + uint8_t zero[4] = {0,0,0,0}; + const char *var = (const char *)_var; + int cmp; + + if (element_size > 4) { + return 0; + } + + for (i = 0; i < length; i++, var += element_size) { + cmp = memcmp(var, zero, element_size); + if (cmp == 0) { + break; + } + } + + if (i == length) { + return length; + } + + return i + 1; +} + _PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size) { uint32_t i; @@ -629,8 +670,12 @@ _PUBLIC_ enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, int nd NDR_PULL_NEED_BYTES(ndr, length*byte_mul); - str_len = ndr_string_length(ndr->data+ndr->offset, byte_mul); - str_len = MIN(str_len, length); /* overrun protection */ + str_len = ndr_string_n_length(ndr->data+ndr->offset, length, byte_mul); + if (str_len == 0) { + return ndr_pull_error(ndr, NDR_ERR_LENGTH, + "Invalid length"); + } + if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX, ndr->data+ndr->offset, str_len*byte_mul, discard_const_p(void *, var), |