All of lore.kernel.org
 help / color / mirror / Atom feed
* [meta-python][scarthgap][PATCH 1/4] python3-ujson: Fix CVE-2026-32875
@ 2026-08-20  5:16 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)
  2026-08-20  5:16 ` [meta-python][scarthgap][PATCH 2/4] python3-ujson: Fix CVE-2026-32874 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco) @ 2026-08-20  5:16 UTC (permalink / raw)
  To: openembedded-devel; +Cc: xe-linux-external, Hetvi Thakar

From: Hetvi Thakar <hthakar@cisco.com>

This patch applies the upstream fix referenced in [2], using the
commit shown in [1].

[1] https://github.com/ultrajson/ultrajson/commit/486bd4553dc471a1de11613bc7347a6b318e37ea
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-32875

Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
---
 .../python/python3-ujson/CVE-2026-32875.patch | 199 ++++++++++++++++++
 .../python/python3-ujson_5.9.0.bb             |   1 +
 2 files changed, 200 insertions(+)
 create mode 100644 meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32875.patch

diff --git a/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32875.patch b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32875.patch
new file mode 100644
index 0000000000..5727412835
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32875.patch
@@ -0,0 +1,199 @@
+From efe3a00499a74ff44867711f40f9bcc279d2ea92 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Br=C3=A9nainn=20Woodsend?= <bwoodsend@gmail.com>
+Date: Wed, 4 Mar 2026 22:28:11 +0000
+Subject: [PATCH] Fix buffer overflow/infinite loop from indent handling
+
+If indent * nest depth is large enough to overflow an int, it causes the
+required output buffer size to be underestimated leading to a buffer
+overflow.
+
+The offending arithmetic is upgraded to a ptrdiff_t and indent is
+artificially capped. An overflow is still technically possible given a
+high enough recursion depth but not without first consuming petabytes of
+RAM.
+
+If indent is negative, it causes a size_t to underflow to some number a
+little bellow size_t max. If that underflow isn't accidentally rectified
+by a subsequent overflow (if -indent * (nest_depth + 1) >
+current_buffer_size) then the buffer up-sizer gets stuck in an infinite
+loop trying to find a power of two that fits in a size_t but is greater
+that size_t max / 2.
+
+It's hard to tell if `ujson.dumps(..., indent=-1)` was ever an
+intentional feature but I don't feel comfortable breaking it in a
+security fix. For now, the dubious *any negative indent -> pad colons
+but add no indentation or newlines* behaviour is preserved but
+internally the indent is clipped to -1 and all subsequent indentation
+code paths are skipped over.
+
+CVE: CVE-2026-32875
+Upstream-Status: Backport [https://github.com/ultrajson/ultrajson/commit/486bd4553dc471a1de11613bc7347a6b318e37ea]
+
+Backport Changes:
+- Adjusted source paths for ujson 5.9.0's pre-src-layout tree.
+
+(cherry picked from commit 486bd4553dc471a1de11613bc7347a6b318e37ea)
+Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
+---
+ lib/ultrajson.h     |  3 ++-
+ lib/ultrajsonenc.c  | 16 +++++++++-------
+ python/objToJSON.c  | 16 +++++++++++++++-
+ tests/test_ujson.py | 20 ++++++++++++++++++--
+ 4 files changed, 44 insertions(+), 11 deletions(-)
+
+diff --git a/lib/ultrajson.h b/lib/ultrajson.h
+index 143cd9e..4560f4d 100644
+--- a/lib/ultrajson.h
++++ b/lib/ultrajson.h
+@@ -54,6 +54,7 @@ tree doesn't have cyclic references.
+ #define __ULTRAJSON_H__
+ 
+ #include <stdio.h>
++#include <stddef.h>
+ 
+ // Max decimals to encode double floating point numbers with
+ #ifndef JSON_DOUBLE_MAX_DECIMALS
+@@ -257,7 +258,7 @@ typedef struct __JSONObjectEncoder
+ 
+   /*
+   Configuration for spaces of indent */
+-  int indent;
++  ptrdiff_t indent;
+ 
+   /*
+   If true, NaN will be encoded as a string matching the Python standard library's JSON behavior.
+diff --git a/lib/ultrajsonenc.c b/lib/ultrajsonenc.c
+index 9ec2faf..0f9fde3 100644
+--- a/lib/ultrajsonenc.c
++++ b/lib/ultrajsonenc.c
+@@ -575,7 +575,7 @@ static void Buffer_AppendIndentNewlineUnchecked(JSONObjectEncoder *enc)
+ 
+ static void Buffer_AppendIndentUnchecked(JSONObjectEncoder *enc, JSINT32 value)
+ {
+-  int i;
++  ptrdiff_t i;
+   if (enc->indent > 0)
+     while (value-- > 0)
+       for (i = 0; i < enc->indent; i++)
+@@ -741,10 +741,11 @@ static void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t c
+ 
+       Buffer_AppendCharUnchecked (enc, '[');
+ 
++      // The extra 1 byte covers the optional newline.
++      size_t per_item_reserve = (enc->indent > 0 ? enc->indent : 0) * (enc->level + 1) + enc->itemSeparatorLength + 1;
+       while (enc->iterNext(obj, &tc))
+       {
+-        // The extra 1 byte covers the optional newline.
+-        Buffer_Reserve (enc, enc->indent * (enc->level + 1) + enc->itemSeparatorLength + 1);
++        Buffer_Reserve (enc, per_item_reserve);
+ 
+         if (count > 0)
+         {
+@@ -769,7 +770,7 @@ static void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t c
+ 
+       enc->iterEnd(obj, &tc);
+ 
+-      if (count > 0) {
++      if (count > 0 && enc->indent > 0) {
+         // Reserve space for the indentation plus the newline.
+         Buffer_Reserve (enc, enc->indent * enc->level + 1);
+         Buffer_AppendIndentNewlineUnchecked (enc);
+@@ -786,10 +787,11 @@ static void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t c
+ 
+       Buffer_AppendCharUnchecked (enc, '{');
+ 
++      // The extra 1 byte covers the optional newline.
++      size_t reserve_size = (enc->indent > 0 ? enc->indent : 0) * (enc->level + 1) + enc->itemSeparatorLength + 1;
+       while ((res = enc->iterNext(obj, &tc)))
+       {
+-        // The extra 1 byte covers the optional newline.
+-        Buffer_Reserve (enc, enc->indent * (enc->level + 1) + enc->itemSeparatorLength + 1);
++        Buffer_Reserve (enc, reserve_size);
+ 
+         if(res < 0)
+         {
+@@ -823,7 +825,7 @@ static void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t c
+ 
+       enc->iterEnd(obj, &tc);
+ 
+-      if (count > 0) {
++      if (count > 0 && enc->indent > 0) {
+         Buffer_Reserve (enc, enc->indent * enc->level + 1);
+         Buffer_AppendIndentNewlineUnchecked (enc);
+         Buffer_AppendIndentUnchecked (enc, enc->level);
+diff --git a/python/objToJSON.c b/python/objToJSON.c
+index b754819..9013205 100644
+--- a/python/objToJSON.c
++++ b/python/objToJSON.c
+@@ -678,6 +678,7 @@ PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs)
+   PyObject *separatorsKeyBytes = NULL;
+   int allowNan = -1;
+   int orejectBytes = -1;
++  int indent = 0;
+   size_t retLen;
+ 
+   JSONObjectEncoder encoder =
+@@ -714,7 +715,7 @@ PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs)
+ 
+   PRINTMARK();
+ 
+-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOOiiiOO", kwlist, &oinput, &oensureAscii, &oencodeHTMLChars, &oescapeForwardSlashes, &osortKeys, &encoder.indent, &allowNan, &orejectBytes, &odefaultFn, &oseparators))
++  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOOiiiOO", kwlist, &oinput, &oensureAscii, &oencodeHTMLChars, &oescapeForwardSlashes, &osortKeys, &indent, &allowNan, &orejectBytes, &odefaultFn, &oseparators))
+   {
+     return NULL;
+   }
+@@ -761,6 +762,19 @@ PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs)
+     encoder.rejectBytes = orejectBytes;
+   }
+ 
++  if (indent < -1)
++  {
++    encoder.indent = -1;
++  }
++  else if (indent > 1000)
++  {
++    PyErr_SetString(PyExc_ValueError, "Maximum allowed indentation is 1000");
++    return NULL;
++  }
++  else {
++    encoder.indent = indent;
++  }
++
+   if (oseparators != NULL && oseparators != Py_None)
+   {
+     if (!PyTuple_Check(oseparators))
+diff --git a/tests/test_ujson.py b/tests/test_ujson.py
+index 506666d..d24edb0 100644
+--- a/tests/test_ujson.py
++++ b/tests/test_ujson.py
+@@ -1050,9 +1050,25 @@ def test_default_function():
+         ujson.dumps(unjsonable_obj, default=default)
+ 
+ 
+-@pytest.mark.parametrize("indent", list(range(65537, 65542)))
++@pytest.mark.parametrize("indent", [999, 1000, 1001, 1 << 30, 1 << 63, 1 << 128])
+ def test_dump_huge_indent(indent):
+-    ujson.encode({"a": True}, indent=indent)
++    obj = {"list": [1, [2, 3], 4], "nested": {"key": "value", "a": True}}
++    if indent <= 1000:
++        assert ujson.loads(ujson.encode(obj, indent=indent)) == obj
++    else:
++        with pytest.raises((ValueError, OverflowError)):
++            ujson.encode(obj, indent=indent)
++
++
++def test_negative_indent():
++    obj = {"a": [1, 2], "b": "c"}
++    assert ujson.dumps(obj) == '{"a":[1,2],"b":"c"}'
++    assert ujson.dumps(obj, 0) == '{"a":[1,2],"b":"c"}'
++    assert ujson.dumps(obj, indent=-1) == '{"a": [1,2],"b": "c"}'
++    assert ujson.dumps(obj, indent=-1000000) == '{"a": [1,2],"b": "c"}'
++    assert (
++        ujson.dumps(obj, indent=2) == '{\n  "a": [\n    1,\n    2\n  ],\n  "b": "c"\n}'
++    )
+ 
+ 
+ @pytest.mark.parametrize("first_length", list(range(2, 7)))
+-- 
+2.35.6
+
diff --git a/meta-python/recipes-devtools/python/python3-ujson_5.9.0.bb b/meta-python/recipes-devtools/python/python3-ujson_5.9.0.bb
index b5f6be9f27..c6b69790e8 100644
--- a/meta-python/recipes-devtools/python/python3-ujson_5.9.0.bb
+++ b/meta-python/recipes-devtools/python/python3-ujson_5.9.0.bb
@@ -11,6 +11,7 @@ inherit pypi ptest setuptools3
 SRC_URI += " \
     file://run-ptest \
     file://0001-setup.py-Do-not-strip-debugging-symbols.patch \
+    file://CVE-2026-32875.patch \
 "
 
 DEPENDS += "python3-setuptools-scm-native"
-- 
2.35.6



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-08-20  5:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20  5:16 [meta-python][scarthgap][PATCH 1/4] python3-ujson: Fix CVE-2026-32875 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-08-20  5:16 ` [meta-python][scarthgap][PATCH 2/4] python3-ujson: Fix CVE-2026-32874 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-08-20  5:16 ` [meta-python][scarthgap][PATCH 3/4] python3-ujson: Fix CVE-2026-44660 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)
2026-08-20  5:16 ` [meta-python][scarthgap][PATCH 4/4] python3-ujson: Fix CVE-2026-54911 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.