From 7fd2421a2c33230047fb6f9b8757ad6396d8ad12 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Wed, 1 Jul 2026 08:38:30 +0200 Subject: [PATCH] libkmipclient: Detect possible length overflow situations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A deeply nested or pathologically large KMIP node tree crafted by a malicious server can wrap the length calculation around to a small value. Detect this and return an error in this case. Assisted-by: IBM Bob:2.0.0 Signed-off-by: Ingo Franzki Reviewed-by: Finn Callies Signed-off-by: Jan Höppner --- libkmipclient/ttlv.c | 5 ++++- libkmipclient/utils.c | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/libkmipclient/ttlv.c b/libkmipclient/ttlv.c index 7d1dacde..42b72e0b 100644 --- a/libkmipclient/ttlv.c +++ b/libkmipclient/ttlv.c @@ -282,7 +282,7 @@ out: static int kmip_node_get_length(struct kmip_node *node, size_t *length) { struct kmip_node *element; - size_t len; + size_t len, prev_len; int rc; if (node == NULL || length == NULL) @@ -297,10 +297,13 @@ static int kmip_node_get_length(struct kmip_node *node, size_t *length) if (rc != 0) return rc; + prev_len = *length; *length += KMIP_TTLV_HEADER_LENGTH + len; if ((len % KMIP_TTLV_BLOCK_LENGTH) != 0) *length += KMIP_TTLV_BLOCK_LENGTH - (len % KMIP_TTLV_BLOCK_LENGTH); + if (*length < prev_len) + return -EOVERFLOW; element = element->next; } diff --git a/libkmipclient/utils.c b/libkmipclient/utils.c index fcbeeec7..30b58aa5 100644 --- a/libkmipclient/utils.c +++ b/libkmipclient/utils.c @@ -225,14 +225,18 @@ int kmip_parse_bignum(const char *str, bool has_prefix, BIGNUM **bn) int kmip_format_bignum(const BIGNUM *bn, bool prefix, char **str) { unsigned char *buf; - uint32_t len; + uint32_t len, prev_len; int rc; len = kmip_encode_bignum_length(bn); /* BIG INTEGERS must be a multiple of 8 bytes long */ - if ((len % KMIP_BIG_INTEGER_BLOCK_LENGTH) != 0) + if ((len % KMIP_BIG_INTEGER_BLOCK_LENGTH) != 0) { + prev_len = len; len += KMIP_BIG_INTEGER_BLOCK_LENGTH - (len % KMIP_BIG_INTEGER_BLOCK_LENGTH); + if (len < prev_len) + return -EOVERFLOW; + } buf = malloc(len); if (buf == NULL) @@ -407,10 +411,10 @@ int kmip_parse_mask(enum kmip_tag tag, const char *str, char separator, return rc; } -static int kmip_append_string(char **str, int *str_len, char separator, +static int kmip_append_string(char **str, size_t *str_len, char separator, const char *append) { - int new_len; + size_t new_len; char *tmp; if (str == NULL || str_len == NULL) @@ -427,6 +431,9 @@ static int kmip_append_string(char **str, int *str_len, char separator, if (append != NULL) new_len += strlen(append); + if (new_len < *str_len) + return -EOVERFLOW; + tmp = realloc(*str, new_len); if (tmp == NULL) return -ENOMEM; @@ -451,8 +458,9 @@ int kmip_format_mask(enum kmip_tag tag, int32_t value, char separator, char **str) { const struct kmip_enum *info; - int rc = 0, i, s_len = 0; char *s = NULL, *tmp; + size_t s_len = 0; + int rc = 0, i; info = kmip_enum_info_by_tag(tag); if (info == NULL || value == 0)