Control: found -1 4.19.0-1

On 2025-02-07 Salvatore Bonaccorso <car...@debian.org> wrote:
[...]
> CVE-2024-12133[0]:
> | Potential DoS in handling of numerous SEQUENCE OF or SET OF elements


> If you fix the vulnerability please also make sure to include the
> CVE (Common Vulnerabilities & Exposures) id in your changelog entry.

> For further information see:

> [0] https://security-tracker.debian.org/tracker/CVE-2024-12133
>     https://www.cve.org/CVERecord?id=CVE-2024-12133
> [1] https://gitlab.com/gnutls/libtasn1/-/issues/52
> [2] https://lists.gnu.org/archive/html/help-libtasn1/2025-02/msg00001.html
> [3] 
> https://gitlab.com/gnutls/libtasn1/-/commit/4082ca2220b5ba910b546afddf7780fc4a51f75a
> [4] 
> https://gitlab.com/gnutls/libtasn1/-/commit/869a97aa259dffa2620dabcad84e1c22545ffc3d
[...]

Hello Salvatore,

This seems to be straightforward to fix by applying the two patches. The
certtool test on the upstream bug report showed the expected speedup
with 4.19.0 + the 2 patches.

cu Andreas
-- 
`What a good friend you are to him, Dr. Maturin. His other friends are
so grateful to you.'
`I sew his ears on from time to time, sure'
diff --git a/debian/changelog b/debian/changelog
index c233af8..476bb40 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+libtasn1-6 (4.19.0-2+deb12u1) bookworm-security; urgency=high
+
+  * Fix CVE-2024-12133 potential DoS in handling of numerous SEQUENCE OF
+    or SET OF elements. Closes: #1095406
+
+ -- Andreas Metzler <ametz...@debian.org>  Sat, 08 Feb 2025 13:23:13 +0100
+
 libtasn1-6 (4.19.0-2) unstable; urgency=low
 
   * Upload to unstable.
diff --git a/debian/patches/0001-asn1_der_decoding2-optimize-_asn1_find_up-call-with-.patch b/debian/patches/0001-asn1_der_decoding2-optimize-_asn1_find_up-call-with-.patch
new file mode 100644
index 0000000..35782b3
--- /dev/null
+++ b/debian/patches/0001-asn1_der_decoding2-optimize-_asn1_find_up-call-with-.patch
@@ -0,0 +1,47 @@
+From 4082ca2220b5ba910b546afddf7780fc4a51f75a Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <u...@gnu.org>
+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 <u...@gnu.org>
+Signed-off-by: Simon Josefsson <si...@josefsson.org>
+---
+ 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
+@@ -1566,15 +1566,22 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len,
+ 	{
+ 	  if (p->right)
+ 	    p = p->right;
+ 	  else
+ 	    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);
+ 
+   if ((ider_len < 0) ||
+       (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0)))
+     {
+-- 
+2.47.2
+
diff --git a/debian/patches/0002-asn1_find_node-optimize-NUMBER-node-lookup-with-inde.patch b/debian/patches/0002-asn1_find_node-optimize-NUMBER-node-lookup-with-inde.patch
new file mode 100644
index 0000000..60bab76
--- /dev/null
+++ b/debian/patches/0002-asn1_find_node-optimize-NUMBER-node-lookup-with-inde.patch
@@ -0,0 +1,269 @@
+From 869a97aa259dffa2620dabcad84e1c22545ffc3d Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <u...@gnu.org>
+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 <u...@gnu.org>
+Signed-off-by: Simon Josefsson <si...@josefsson.org>
+---
+ lib/element.c    | 56 ++++++++++++++++++++++++++++++++++++++++++------
+ lib/element.h    | 10 +++++++++
+ lib/int.h        |  8 +++++++
+ lib/parser_aux.c | 10 +++++++++
+ lib/structure.c  | 13 +++++++++++
+ 5 files changed, 90 insertions(+), 7 deletions(-)
+
+--- a/lib/element.c
++++ b/lib/element.c
+@@ -30,10 +30,12 @@
+ #include "parser_aux.h"
+ #include <gstr.h>
+ #include "structure.h"
+ #include "c-ctype.h"
+ #include "element.h"
++#include <limits.h>
++#include "intprops.h"
+ 
+ void
+ _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
+ {
+   asn1_node_const p;
+@@ -126,10 +128,45 @@ _asn1_convert_integer (const unsigned ch
+ #endif
+ 
+   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.
+  *
+  * The last element in the list may be provided in @pcache, to avoid
+@@ -142,10 +179,11 @@ int
+ _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;
+ 
+   p = node->down;
+@@ -174,21 +212,25 @@ _asn1_append_sequence_set (asn1_node nod
+     {
+       pcache->head = node;
+       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] = '?';
+-      _asn1_ltostr (n, temp + 1);
++      n = strtol (p->name + 1, NULL, 10);
++      if (n <= 0 || n >= LONG_MAX - 1)
++	return ASN1_GENERIC_ERROR;
+     }
++  temp[0] = '?';
++  _asn1_ltostr (n + 1, temp + 1);
+   _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;
+ }
+ 
+ 
+--- a/lib/element.h
++++ b/lib/element.h
+@@ -37,6 +37,16 @@ int _asn1_convert_integer (const unsigne
+ 			   int value_out_size, int *len);
+ 
+ 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
+--- a/lib/int.h
++++ b/lib/int.h
+@@ -37,10 +37,16 @@
+ 
+ # include <libtasn1.h>
+ 
+ # 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.  */
+ struct asn1_node_st
+ {
+@@ -53,10 +59,12 @@ struct asn1_node_st
+   asn1_node down;		/* Pointer to the son node */
+   asn1_node right;		/* Pointer to the brother node */
+   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;
+   unsigned start;		/* the start of the DER sequence - if decoded */
+   unsigned end;			/* the end of the DER sequence - if decoded */
+--- a/lib/parser_aux.c
++++ b/lib/parser_aux.c
+@@ -123,10 +123,11 @@ asn1_find_node (asn1_node_const pointer,
+   asn1_node_const p;
+   char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
+   const char *n_start;
+   unsigned int nsize;
+   unsigned int nhash;
++  const struct asn1_node_array_st *numbered_children;
+ 
+   if (pointer == NULL)
+     return NULL;
+ 
+   if (name == NULL)
+@@ -206,10 +207,11 @@ asn1_find_node (asn1_node_const pointer,
+ 	}
+ 
+       if (p->down == NULL)
+ 	return NULL;
+ 
++      numbered_children = &p->numbered_children;
+       p = p->down;
+       if (p == NULL)
+ 	return NULL;
+ 
+       /* The identifier "?LAST" indicates the last element
+@@ -219,10 +221,16 @@ asn1_find_node (asn1_node_const pointer,
+ 	  while (p->right)
+ 	    p = p->right;
+ 	}
+       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))
+ 		break;
+ 	      else
+@@ -506,10 +514,12 @@ _asn1_remove_node (asn1_node node, unsig
+ 	}
+ 
+       if (node->value != node->small_value)
+ 	free (node->value);
+     }
++
++  free (node->numbered_children.nodes);
+   free (node);
+ }
+ 
+ /******************************************************************/
+ /* Function : _asn1_find_up                                       */
+--- a/lib/structure.c
++++ b/lib/structure.c
+@@ -29,10 +29,13 @@
+ 
+ #include <int.h>
+ #include <structure.h>
+ #include "parser_aux.h"
+ #include <gstr.h>
++#include "c-ctype.h"
++#include "element.h"
++#include <limits.h>
+ 
+ 
+ extern char _asn1_identifierMissing[];
+ 
+ 
+@@ -389,10 +392,20 @@ asn1_delete_element (asn1_node structure
+   source_node = asn1_find_node (structure, 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)
+     {
+       p3 = _asn1_find_up (source_node);
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..f8b0371
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+0001-asn1_der_decoding2-optimize-_asn1_find_up-call-with-.patch
+0002-asn1_find_node-optimize-NUMBER-node-lookup-with-inde.patch

Attachment: signature.asc
Description: PGP signature

Reply via email to