libkmipclient: Detect possible length overflow situations

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 <ifranzki@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2026-07-01 08:38:30 +02:00
committed by Jan Höppner
parent 66581d57f3
commit 7fd2421a2c
2 changed files with 17 additions and 6 deletions

View File

@@ -282,7 +282,7 @@ out:
static int kmip_node_get_length(struct kmip_node *node, size_t *length) static int kmip_node_get_length(struct kmip_node *node, size_t *length)
{ {
struct kmip_node *element; struct kmip_node *element;
size_t len; size_t len, prev_len;
int rc; int rc;
if (node == NULL || length == NULL) 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) if (rc != 0)
return rc; return rc;
prev_len = *length;
*length += KMIP_TTLV_HEADER_LENGTH + len; *length += KMIP_TTLV_HEADER_LENGTH + len;
if ((len % KMIP_TTLV_BLOCK_LENGTH) != 0) if ((len % KMIP_TTLV_BLOCK_LENGTH) != 0)
*length += KMIP_TTLV_BLOCK_LENGTH - *length += KMIP_TTLV_BLOCK_LENGTH -
(len % KMIP_TTLV_BLOCK_LENGTH); (len % KMIP_TTLV_BLOCK_LENGTH);
if (*length < prev_len)
return -EOVERFLOW;
element = element->next; element = element->next;
} }

View File

@@ -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) int kmip_format_bignum(const BIGNUM *bn, bool prefix, char **str)
{ {
unsigned char *buf; unsigned char *buf;
uint32_t len; uint32_t len, prev_len;
int rc; int rc;
len = kmip_encode_bignum_length(bn); len = kmip_encode_bignum_length(bn);
/* BIG INTEGERS must be a multiple of 8 bytes long */ /* 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 -
(len % KMIP_BIG_INTEGER_BLOCK_LENGTH); (len % KMIP_BIG_INTEGER_BLOCK_LENGTH);
if (len < prev_len)
return -EOVERFLOW;
}
buf = malloc(len); buf = malloc(len);
if (buf == NULL) if (buf == NULL)
@@ -407,10 +411,10 @@ int kmip_parse_mask(enum kmip_tag tag, const char *str, char separator,
return rc; 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) const char *append)
{ {
int new_len; size_t new_len;
char *tmp; char *tmp;
if (str == NULL || str_len == NULL) 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) if (append != NULL)
new_len += strlen(append); new_len += strlen(append);
if (new_len < *str_len)
return -EOVERFLOW;
tmp = realloc(*str, new_len); tmp = realloc(*str, new_len);
if (tmp == NULL) if (tmp == NULL)
return -ENOMEM; return -ENOMEM;
@@ -451,8 +458,9 @@ int kmip_format_mask(enum kmip_tag tag, int32_t value, char separator,
char **str) char **str)
{ {
const struct kmip_enum *info; const struct kmip_enum *info;
int rc = 0, i, s_len = 0;
char *s = NULL, *tmp; char *s = NULL, *tmp;
size_t s_len = 0;
int rc = 0, i;
info = kmip_enum_info_by_tag(tag); info = kmip_enum_info_by_tag(tag);
if (info == NULL || value == 0) if (info == NULL || value == 0)