From 243192561fe59a99450308901f0ff2be9a39489b Mon Sep 17 00:00:00 2001 From: Alexander Sosedkin Date: Wed, 12 Feb 2025 13:17:17 +0100 Subject: [PATCH] Backport the fix for CVE-2024-12133 Resolves: RHEL-78580 --- libtasn1-4.20-CVE-2024-12133.patch | 280 +++++++++++++++++++++++++++++ libtasn1.spec | 9 +- 2 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 libtasn1-4.20-CVE-2024-12133.patch diff --git a/libtasn1-4.20-CVE-2024-12133.patch b/libtasn1-4.20-CVE-2024-12133.patch new file mode 100644 index 0000000..498a61a --- /dev/null +++ b/libtasn1-4.20-CVE-2024-12133.patch @@ -0,0 +1,280 @@ +From 4082ca2220b5ba910b546afddf7780fc4a51f75a Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Sat, 19 Oct 2024 02:47:04 +0900 +Subject: [PATCH 1/2] asn1_der_decoding2: optimize _asn1_find_up call with node + cache + +If we are parsing a sequence or set and the current node is a direct +child of it, there is no need to traverse the list back to the +leftmost one as we have a node cache. + +Signed-off-by: Daiki Ueno +Signed-off-by: Simon Josefsson +--- + lib/decoding.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/lib/decoding.c b/lib/decoding.c +index d2f6dea..1e0fcb3 100644 +--- a/lib/decoding.c ++++ b/lib/decoding.c +@@ -1570,7 +1570,14 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, + move = UP; + } + if (move == UP) +- p = _asn1_find_up (p); ++ { ++ /* If we are parsing a sequence or set and p is a direct ++ child of it, no need to traverse the list back to the leftmost node. */ ++ if (tcache.tail == p) ++ p = tcache.head; ++ else ++ p = _asn1_find_up (p); ++ } + } + + _asn1_delete_not_used (*element); +-- +2.47.1 + + +From 869a97aa259dffa2620dabcad84e1c22545ffc3d Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Fri, 8 Nov 2024 16:05:32 +0900 +Subject: [PATCH 2/2] asn1_find_node: optimize "?NUMBER" node lookup with + indexing + +To avoid linear search of named nodes, this adds a array of child +nodes to their parent nodes as a cache. + +Signed-off-by: Daiki Ueno +Signed-off-by: Simon Josefsson +--- + lib/element.c | 64 +++++++++++++++++++++++++++++++++++++++--------- + lib/element.h | 10 ++++++++ + lib/int.h | 8 ++++++ + lib/parser_aux.c | 10 ++++++++ + lib/structure.c | 13 ++++++++++ + 5 files changed, 93 insertions(+), 12 deletions(-) + +diff --git a/lib/element.c b/lib/element.c +index 850bef4..528df41 100644 +--- a/lib/element.c ++++ b/lib/element.c +@@ -33,6 +33,8 @@ + #include "structure.h" + #include "c-ctype.h" + #include "element.h" ++#include ++#include "intprops.h" + + void + _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) +@@ -129,6 +131,41 @@ _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, + return ASN1_SUCCESS; + } + ++int ++_asn1_node_array_set (struct asn1_node_array_st *array, size_t position, ++ asn1_node node) ++{ ++ if (position >= array->size) ++ { ++ size_t new_size = position, i; ++ asn1_node *new_nodes; ++ ++ if (INT_MULTIPLY_OVERFLOW (new_size, 2)) ++ return ASN1_GENERIC_ERROR; ++ new_size *= 2; ++ ++ if (INT_ADD_OVERFLOW (new_size, 1)) ++ return ASN1_GENERIC_ERROR; ++ new_size += 1; ++ ++ if (INT_MULTIPLY_OVERFLOW (new_size, sizeof (*new_nodes))) ++ return ASN1_GENERIC_ERROR; ++ ++ new_nodes = realloc (array->nodes, new_size * sizeof (*new_nodes)); ++ if (!new_nodes) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ for (i = array->size; i < new_size; i++) ++ new_nodes[i] = NULL; ++ ++ array->nodes = new_nodes; ++ array->size = new_size; ++ } ++ ++ array->nodes[position] = node; ++ return ASN1_SUCCESS; ++} ++ + /* Appends a new element into the sequence (or set) defined by this + * node. The new element will have a name of '?number', where number + * is a monotonically increased serial number. +@@ -145,6 +182,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) + asn1_node p, p2; + char temp[LTOSTR_MAX_SIZE+1]; + long n; ++ int result; + + if (!node || !(node->down)) + return ASN1_GENERIC_ERROR; +@@ -176,22 +214,24 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) + pcache->tail = p2; + } + +- if (p->name[0] == 0) +- _asn1_str_cpy (temp, sizeof (temp), "?1"); +- else ++ n = 0; ++ if (p->name[0] != 0) + { +- n = strtol (p->name + 1, NULL, 0); +- n++; +- temp[0] = '?'; +- if (n < 0) +- return ASN1_GENERIC_ERROR; +- /* assuming non-negative n, we have enough space in buffer */ +- _asn1_ltostr (n, temp + 1); +- if (strlen(temp) >= LTOSTR_MAX_SIZE) +- return ASN1_GENERIC_ERROR; ++ n = strtol (p->name + 1, NULL, 10); ++ if (n <= 0 || n >= LONG_MAX - 1) ++ return ASN1_GENERIC_ERROR; + } ++ /* assuming non-negative n, we have enough space in buffer */ ++ temp[0] = '?'; ++ _asn1_ltostr (n + 1, temp + 1); ++ if (strlen(temp) >= LTOSTR_MAX_SIZE) ++ return ASN1_GENERIC_ERROR; + _asn1_set_name (p2, temp); + /* p2->type |= CONST_OPTION; */ ++ result = _asn1_node_array_set (&node->numbered_children, n, p2); ++ if (result != ASN1_SUCCESS) ++ return result; ++ p2->parent = node; + + return ASN1_SUCCESS; + } +diff --git a/lib/element.h b/lib/element.h +index 732054e..b84e3a2 100644 +--- a/lib/element.h ++++ b/lib/element.h +@@ -37,4 +37,14 @@ int _asn1_convert_integer (const unsigned char *value, + + void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size); + ++static inline asn1_node_const ++_asn1_node_array_get (const struct asn1_node_array_st *array, size_t position) ++{ ++ return position < array->size ? array->nodes[position] : NULL; ++} ++ ++int ++_asn1_node_array_set (struct asn1_node_array_st *array, size_t position, ++ asn1_node node); ++ + #endif +diff --git a/lib/int.h b/lib/int.h +index 4f2d98d..41b12b0 100644 +--- a/lib/int.h ++++ b/lib/int.h +@@ -31,6 +31,12 @@ + + #define ASN1_SMALL_VALUE_SIZE 16 + ++struct asn1_node_array_st ++{ ++ asn1_node *nodes; ++ size_t size; ++}; ++ + /* This structure is also in libtasn1.h, but then contains less + fields. You cannot make any modifications to these first fields + without breaking ABI. */ +@@ -47,6 +53,8 @@ struct asn1_node_st + asn1_node left; /* Pointer to the next list element */ + /* private fields: */ + unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */ ++ asn1_node parent; /* Pointer to the parent node */ ++ struct asn1_node_array_st numbered_children; /* Array of unnamed child nodes for caching */ + + /* values used during decoding/coding */ + int tmp_ival; +diff --git a/lib/parser_aux.c b/lib/parser_aux.c +index 415905a..4281cc9 100644 +--- a/lib/parser_aux.c ++++ b/lib/parser_aux.c +@@ -126,6 +126,7 @@ asn1_find_node (asn1_node_const pointer, const char *name) + const char *n_start; + unsigned int nsize; + unsigned int nhash; ++ const struct asn1_node_array_st *numbered_children; + + if (pointer == NULL) + return NULL; +@@ -209,6 +210,7 @@ asn1_find_node (asn1_node_const pointer, const char *name) + if (p->down == NULL) + return NULL; + ++ numbered_children = &p->numbered_children; + p = p->down; + if (p == NULL) + return NULL; +@@ -222,6 +224,12 @@ asn1_find_node (asn1_node_const pointer, const char *name) + } + else + { /* no "?LAST" */ ++ if (n[0] == '?' && c_isdigit (n[1])) ++ { ++ long position = strtol (n + 1, NULL, 10); ++ if (position > 0 && position < LONG_MAX) ++ p = _asn1_node_array_get (numbered_children, position - 1); ++ } + while (p) + { + if (p->name_hash == nhash && !strcmp (p->name, n)) +@@ -509,6 +517,8 @@ _asn1_remove_node (asn1_node node, unsigned int flags) + if (node->value != node->small_value) + free (node->value); + } ++ ++ free (node->numbered_children.nodes); + free (node); + } + +diff --git a/lib/structure.c b/lib/structure.c +index 9c95b9e..32692ad 100644 +--- a/lib/structure.c ++++ b/lib/structure.c +@@ -31,6 +31,9 @@ + #include + #include "parser_aux.h" + #include ++#include "c-ctype.h" ++#include "element.h" ++#include + + + extern char _asn1_identifierMissing[]; +@@ -391,6 +394,16 @@ asn1_delete_element (asn1_node structure, const char *element_name) + if (source_node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + ++ if (source_node->parent ++ && source_node->name[0] == '?' ++ && c_isdigit (source_node->name[1])) ++ { ++ long position = strtol (source_node->name + 1, NULL, 10); ++ if (position > 0 && position < LONG_MAX) ++ _asn1_node_array_set (&source_node->parent->numbered_children, ++ position - 1, NULL); ++ } ++ + p2 = source_node->right; + p3 = _asn1_find_left (source_node); + if (!p3) +-- +2.47.1 + diff --git a/libtasn1.spec b/libtasn1.spec index 1068052..07088e6 100644 --- a/libtasn1.spec +++ b/libtasn1.spec @@ -1,7 +1,7 @@ Summary: The ASN.1 library used in GNUTLS Name: libtasn1 Version: 4.16.0 -Release: 8%{?dist} +Release: 9%{?dist} # The libtasn1 library is LGPLv2+, utilities are GPLv3+ License: GPLv3+ and LGPLv2+ @@ -12,6 +12,7 @@ Source2: gpgkey-1F42418905D8206AA754CCDC29EE58B996865171.gpg Patch1: libtasn1-3.4-rpath.patch Patch200: libtasn1-4.16-coverity.patch Patch300: libtasn1-4.19-CVE-2021-46848.patch +Patch301: libtasn1-4.20-CVE-2024-12133.patch BuildRequires: gnupg2 BuildRequires: gcc @@ -59,6 +60,7 @@ gpgv2 --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0} %patch1 -p1 -b .rpath %patch200 -p1 -b .coverity %patch300 -p1 -b .CVE-2021-46848 +%patch301 -p1 -b .CVE-2024-12133 %build autoreconf -v -f --install @@ -97,7 +99,10 @@ make check %changelog -* Wed Nov 30 2022 Simo Sorce - 4.16.0-9 +* Wed Feb 12 2025 Alexander Sosedkin - 4.16.0-9 +- Backport the fix for CVE-2024-12133 (RHEL-78580) + +* Wed Nov 30 2022 Simo Sorce - 4.16.0-8 - Resolves: rhbz#2140602 * Mon Aug 09 2021 Mohan Boddu - 4.16.0-7