* [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* [meta-python][scarthgap][PATCH 2/4] python3-ujson: Fix CVE-2026-32874 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 ` 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) 2 siblings, 0 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/4baeb950df780092bd3c89fc702a868e99a3a1d2 [2] https://nvd.nist.gov/vuln/detail/CVE-2026-32874 Signed-off-by: Hetvi Thakar <hthakar@cisco.com> --- .../python/python3-ujson/CVE-2026-32874.patch | 61 +++++++++++++++++++ .../python/python3-ujson_5.9.0.bb | 1 + 2 files changed, 62 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32874.patch diff --git a/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32874.patch b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32874.patch new file mode 100644 index 0000000000..09730b9623 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-32874.patch @@ -0,0 +1,61 @@ +From cf988dbccb1b71cc1cb27c59ac73e09f3a68c3c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Br=C3=A9nainn=20Woodsend?= <bwoodsend@gmail.com> +Date: Wed, 10 Dec 2025 22:37:20 +0000 +Subject: [PATCH] Fix memory leak parsing large integers + +CVE: CVE-2026-32874 +Upstream-Status: Backport [https://github.com/ultrajson/ultrajson/commit/4baeb950df780092bd3c89fc702a868e99a3a1d2] + +Backport Changes: +- Adjusted source paths for ujson 5.9.0's pre-src-layout tree. + +(cherry picked from commit 4baeb950df780092bd3c89fc702a868e99a3a1d2) +Signed-off-by: Hetvi Thakar <hthakar@cisco.com> +--- + python/JSONtoObj.c | 4 +++- + tests/test_ujson.py | 14 ++++++++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/python/JSONtoObj.c b/python/JSONtoObj.c +index 208055c..93e87f3 100644 +--- a/python/JSONtoObj.c ++++ b/python/JSONtoObj.c +@@ -136,7 +136,9 @@ static JSOBJ Object_newIntegerFromString(void *prv, char *value, size_t length) + char *buf = PyObject_Malloc(length + 1); + memcpy(buf, value, length); + buf[length] = '\0'; +- return PyLong_FromString(buf, NULL, 10); ++ PyObject *ret = PyLong_FromString(buf, NULL, 10); ++ PyObject_Free(buf); ++ return ret; + } + + static JSOBJ Object_newDouble(void *prv, double value) +diff --git a/tests/test_ujson.py b/tests/test_ujson.py +index d24edb0..9ba6f55 100644 +--- a/tests/test_ujson.py ++++ b/tests/test_ujson.py +@@ -653,6 +653,20 @@ def test_encode_decode_big_int(i, mode): + assert ujson.decode(json_string) == python_object + + ++@pytest.mark.xfail( ++ sys.implementation.name == "pypy", ++ reason="PyPy's PyNumber_ToBase ignores sys.get_int_max_str_digits()", ++) ++def test_encode_too_big_int_error(): ++ with pytest.raises(ValueError, match="integer string conversion"): ++ ujson.dumps(pow(10, 10_000)) ++ ++ ++def test_decode_too_big_int_error(): ++ with pytest.raises(ValueError, match="integer string conversion"): ++ ujson.loads("9" * 10_000) ++ ++ + @pytest.mark.parametrize( + "test_input, expected", + [ +-- +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 c6b69790e8..8b970ee564 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 @@ -12,6 +12,7 @@ SRC_URI += " \ file://run-ptest \ file://0001-setup.py-Do-not-strip-debugging-symbols.patch \ file://CVE-2026-32875.patch \ + file://CVE-2026-32874.patch \ " DEPENDS += "python3-setuptools-scm-native" -- 2.35.6 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [meta-python][scarthgap][PATCH 3/4] python3-ujson: Fix CVE-2026-44660 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 ` 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) 2 siblings, 0 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/82af1d0ac01d09aa40c887b460d44b9d9f4bccd9 [2] https://nvd.nist.gov/vuln/detail/CVE-2026-44660 Signed-off-by: Hetvi Thakar <hthakar@cisco.com> --- .../python/python3-ujson/CVE-2026-44660.patch | 112 ++++++++++++++++++ .../python/python3-ujson_5.9.0.bb | 1 + 2 files changed, 113 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-ujson/CVE-2026-44660.patch diff --git a/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-44660.patch b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-44660.patch new file mode 100644 index 0000000000..bfbaaf53b2 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-44660.patch @@ -0,0 +1,112 @@ +From 62fa316b5bdf9b2bb66efa60d1a17b38dc80f946 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Br=C3=A9nainn=20Woodsend?= <bwoodsend@gmail.com> +Date: Sun, 3 May 2026 12:22:48 +0100 +Subject: [PATCH] Fix failure cleanup paths in ujson.dump() + +* Add missing dec-refs for if PyTuple_Pack() or writing the payload to + file fails + +* Add missing bailout for failed PyTuple_Pack() + +* Add tests for all but the PyTuple_Pack() failing (which requires + inducing a malloc() failure) + +CVE: CVE-2026-44660 +Upstream-Status: Backport [https://github.com/ultrajson/ultrajson/commit/82af1d0ac01d09aa40c887b460d44b9d9f4bccd9] + +Backport Changes: +- Adjusted source paths for ujson 5.9.0's pre-src-layout tree. + +(cherry picked from commit 82af1d0ac01d09aa40c887b460d44b9d9f4bccd9) +Signed-off-by: Hetvi Thakar <hthakar@cisco.com> +--- + python/objToJSON.c | 7 +++++++ + tests/test_ujson.py | 33 +++++++++++++++++++++++++++++++++ + 2 files changed, 40 insertions(+) + +diff --git a/python/objToJSON.c b/python/objToJSON.c +index 9013205..47e46c1 100644 +--- a/python/objToJSON.c ++++ b/python/objToJSON.c +@@ -909,6 +909,11 @@ PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs) + } + + argtuple = PyTuple_Pack(1, data); ++ if (argtuple == NULL) ++ { ++ Py_XDECREF(write); ++ return NULL; ++ } + + string = objToJSON (self, argtuple, kwargs); + +@@ -925,6 +930,7 @@ PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs) + if (argtuple == NULL) + { + Py_XDECREF(write); ++ Py_DECREF(string); + return NULL; + } + +@@ -932,6 +938,7 @@ PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs) + if (write_result == NULL) + { + Py_XDECREF(write); ++ Py_DECREF(string); + Py_XDECREF(argtuple); + return NULL; + } +diff --git a/tests/test_ujson.py b/tests/test_ujson.py +index 9ba6f55..ccff37f 100644 +--- a/tests/test_ujson.py ++++ b/tests/test_ujson.py +@@ -8,6 +8,7 @@ import os.path + import re + import subprocess + import sys ++import types + import uuid + from collections import OrderedDict + from pathlib import Path +@@ -365,6 +366,38 @@ def test_dump_to_file_like_object(): + def test_dump_file_args_error(): + with pytest.raises(TypeError): + ujson.dump([], "") ++ with pytest.raises(TypeError): ++ ujson.dump([], "", "") ++ ++ ++def test_dump_non_callable_write(): ++ file = types.SimpleNamespace(write="a") ++ with pytest.raises(TypeError): ++ ujson.dump([7] * 100, file) ++ ++ ++def test_failed_dump(): ++ with pytest.raises(TypeError): ++ ujson.dump([[0] * 100, object()], io.StringIO()) ++ ++ ++def test_failed_dump_bogus_file(): ++ file = types.SimpleNamespace(write=lambda: None) ++ with pytest.raises(TypeError, match="0 positional arguments"): ++ ujson.dump([0] * 100, file) ++ ++ ++def test_failed_dump_failed_write(): ++ file = types.SimpleNamespace(write=lambda x: 1 / 0) ++ with pytest.raises(ZeroDivisionError): ++ ujson.dump([0] * 100, file) ++ ++ ++def test_failed_dump_closed_file(): ++ file = io.StringIO() ++ file.close() ++ with pytest.raises(ValueError, match="closed file"): ++ ujson.dump([0] * 100, file) + + + def test_load_file(): +-- +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 8b970ee564..ed08ede1d9 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 @@ -13,6 +13,7 @@ SRC_URI += " \ file://0001-setup.py-Do-not-strip-debugging-symbols.patch \ file://CVE-2026-32875.patch \ file://CVE-2026-32874.patch \ + file://CVE-2026-44660.patch \ " DEPENDS += "python3-setuptools-scm-native" -- 2.35.6 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [meta-python][scarthgap][PATCH 4/4] python3-ujson: Fix CVE-2026-54911 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 ` Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco) 2 siblings, 0 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/169eaf36b1116fece5034ee79a7a0ef3f6deedcf [2] https://nvd.nist.gov/vuln/detail/CVE-2026-54911 Signed-off-by: Hetvi Thakar <hthakar@cisco.com> --- .../python/python3-ujson/CVE-2026-54911.patch | 267 ++++++++++++++++++ .../python/python3-ujson_5.9.0.bb | 1 + 2 files changed, 268 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-ujson/CVE-2026-54911.patch diff --git a/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-54911.patch b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-54911.patch new file mode 100644 index 0000000000..c7c14066d4 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-ujson/CVE-2026-54911.patch @@ -0,0 +1,267 @@ +From 92a7b67d7b6155c2e3bc225fa0238ea35249bb36 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Br=C3=A9nainn=20Woodsend?= <bwoodsend@gmail.com> +Date: Fri, 24 Apr 2026 21:59:45 +0100 +Subject: [PATCH] More UTF-8 validation for ujson.dumps(b"...", + reject_bytes=False) + +* Fix off by one errors in detecting end of string mid sequence +* Add missing check for codepoints > max unicode +* Add missing check for bad continuation bytes + +CVE: CVE-2026-54911 +Upstream-Status: Backport [https://github.com/ultrajson/ultrajson/commit/169eaf36b1116fece5034ee79a7a0ef3f6deedcf] + +Backport Changes: +- Adjusted source paths for ujson 5.9.0's pre-src-layout tree. +- Relocated regression tests to the matching section of the 5.9.0 test suite. +- Added the `random` import required by the backported fuzz regression test; + newer upstream already imports it, while ujson 5.9.0 does not. + +(cherry picked from commit 169eaf36b1116fece5034ee79a7a0ef3f6deedcf) +Signed-off-by: Hetvi Thakar <hthakar@cisco.com> +--- + lib/ultrajsondec.c | 6 ++-- + lib/ultrajsonenc.c | 46 ++++++++++++++++++++++----- + tests/test_ujson.py | 76 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 118 insertions(+), 10 deletions(-) + +diff --git a/lib/ultrajsondec.c b/lib/ultrajsondec.c +index bccb0aa..5583376 100644 +--- a/lib/ultrajsondec.c ++++ b/lib/ultrajsondec.c +@@ -531,7 +531,7 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_string ( struct DecoderState *ds + return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'"); + } + ucs |= (*inputOffset++) & 0x3f; +- if (ucs < 0x80) return SetError (ds, -1, "Overlong 2 byte UTF-8 sequence detected when decoding 'string'"); ++ if (ucs < 0x80) return SetError (ds, -1, "Overlong 2-byte UTF-8 sequence detected when decoding 'string'"); + *(escOffset++) = (JSUINT32) ucs; + break; + } +@@ -554,7 +554,7 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_string ( struct DecoderState *ds + ucs |= oct & 0x3f; + } + +- if (ucs < 0x800) return SetError (ds, -1, "Overlong 3 byte UTF-8 sequence detected when encoding string"); ++ if (ucs < 0x800) return SetError (ds, -1, "Overlong 3-byte UTF-8 sequence detected when encoding string"); + *(escOffset++) = (JSUINT32) ucs; + break; + } +@@ -577,7 +577,7 @@ static FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_string ( struct DecoderState *ds + ucs |= oct & 0x3f; + } + +- if (ucs < 0x10000) return SetError (ds, -1, "Overlong 4 byte UTF-8 sequence detected when decoding 'string'"); ++ if (ucs < 0x10000) return SetError (ds, -1, "Overlong 4-byte UTF-8 sequence detected when decoding 'string'"); + + *(escOffset++) = (JSUINT32) ucs; + break; +diff --git a/lib/ultrajsonenc.c b/lib/ultrajsonenc.c +index 0f9fde3..5bafd52 100644 +--- a/lib/ultrajsonenc.c ++++ b/lib/ultrajsonenc.c +@@ -347,17 +347,24 @@ static int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, cons + continue; + } + ++ // https://en.wikipedia.org/wiki/UTF-8#Description + case 2: + { + JSUTF32 in; + JSUTF16 in16; + +- if (end - io < 1) ++ if (end - io < 2) + { + enc->offset += (of - enc->offset); + SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string"); + return FALSE; + } ++ if ((io[1] & 0xc0) != 0x80) ++ { ++ enc->offset += (of - enc->offset); ++ SetError (obj, enc, "Invalid continuation byte in 2-byte UTF-8 sequence detected when encoding string"); ++ return FALSE; ++ } + + memcpy(&in16, io, sizeof(JSUTF16)); + in = (JSUTF32) in16; +@@ -371,7 +378,7 @@ static int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, cons + if (ucs < 0x80) + { + enc->offset += (of - enc->offset); +- SetError (obj, enc, "Overlong 2 byte UTF-8 sequence detected when encoding string"); ++ SetError (obj, enc, "Overlong 2-byte UTF-8 sequence detected when encoding string"); + return FALSE; + } + +@@ -385,13 +392,26 @@ static int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, cons + JSUTF16 in16; + JSUINT8 in8; + +- if (end - io < 2) ++ if (end - io < 3) + { + enc->offset += (of - enc->offset); + SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string"); + return FALSE; + } +- ++ if ((io[1] & 0xc0) != 0x80 || (io[2] & 0xc0) != 0x80) ++ { ++ enc->offset += (of - enc->offset); ++ SetError (obj, enc, "Invalid continuation byte in 3-byte UTF-8 sequence detected when encoding string"); ++ return FALSE; ++ } ++ // Under normal UTF-8 decoding rules, UTF-16 surrogates should also be disallowed ++ // but in JSON, they're special cased and rewritten later as \udc7f. ++ // if ((JSUINT8) io[0] == 0xed && (JSUINT8) io[1] >= 0xa0) ++ // { ++ // enc->offset += (of - enc->offset); ++ // SetError (obj, enc, "Illegal UTF-16 surrogate in 3-byte UTF-8 sequence detected when encoding string"); ++ // return FALSE; ++ // } + memcpy(&in16, io, sizeof(JSUTF16)); + memcpy(&in8, io + 2, sizeof(JSUINT8)); + #ifdef __LITTLE_ENDIAN__ +@@ -407,7 +427,7 @@ static int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, cons + if (ucs < 0x800) + { + enc->offset += (of - enc->offset); +- SetError (obj, enc, "Overlong 3 byte UTF-8 sequence detected when encoding string"); ++ SetError (obj, enc, "Overlong 3-byte UTF-8 sequence detected when encoding string"); + return FALSE; + } + +@@ -418,12 +438,24 @@ static int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, cons + { + JSUTF32 in; + +- if (end - io < 3) ++ if (end - io < 4) + { + enc->offset += (of - enc->offset); + SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string"); + return FALSE; + } ++ if ((io[1] & 0xc0) != 0x80 || (io[2] & 0xc0) != 0x80 || (io[3] & 0xc0) != 0x80) ++ { ++ enc->offset += (of - enc->offset); ++ SetError (obj, enc, "Invalid continuation byte in 4-byte UTF-8 sequence detected when encoding string"); ++ return FALSE; ++ } ++ if (((JSUINT8) io[0] >= 0xf4 && (JSUINT8) io[1] >= 0x90) || (JSUINT8) io[0] >= 0xf5) ++ { ++ enc->offset += (of - enc->offset); ++ SetError (obj, enc, ">U+10FFFF in 4-byte UTF-8 sequence detected when encoding string"); ++ return FALSE; ++ } + + memcpy(&in, io, sizeof(JSUTF32)); + #ifdef __LITTLE_ENDIAN__ +@@ -434,7 +466,7 @@ static int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, cons + if (ucs < 0x10000) + { + enc->offset += (of - enc->offset); +- SetError (obj, enc, "Overlong 4 byte UTF-8 sequence detected when encoding string"); ++ SetError (obj, enc, "Overlong 4-byte UTF-8 sequence detected when encoding string"); + return FALSE; + } + +diff --git a/tests/test_ujson.py b/tests/test_ujson.py +index ccff37f..9024dac 100644 +--- a/tests/test_ujson.py ++++ b/tests/test_ujson.py +@@ -5,6 +5,7 @@ import io + import json + import math + import os.path ++import random + import re + import subprocess + import sys +@@ -1053,6 +1053,81 @@ def test_reject_bytes_false(): + assert ujson.dumps(data, reject_bytes=False) == '{"a":"b"}' + + ++@pytest.mark.parametrize( ++ "codepoint", ++ [0x0, 0x7F, 0x80, 0x7FF, 0x800, 0xFFFF, 0x10000, 0x10FFFF], ++) ++def test_reject_bytes_false_codepoint_boundaries(codepoint): ++ char = chr(codepoint) ++ assert ujson.loads(ujson.dumps(char.encode(), reject_bytes=False)) == char ++ ++ ++@pytest.mark.parametrize( ++ "value, error", ++ [ ++ # Bad start bytes ++ (b"\xfd", "Unsupported UTF-8 sequence length when encoding string"), ++ (b"\xfc:", "Unsupported UTF-8 sequence length when encoding string"), ++ (b"U>\xfb", "Unsupported UTF-8 sequence length when encoding string"), ++ (b"\\\xf8\x98\t", "Unsupported UTF-8 sequence length when encoding string"), ++ (b"\x9b", "'utf-8' codec can't decode byte 0x9b in position 1:"), ++ (b"B\x8a", "'utf-8' codec can't decode byte 0x8a in position 2:"), ++ # Bad continuation bytes (any non-start byte not matching 0b10xx_xxxx) ++ (b"\xcf\x13", "Invalid continuation byte in 2-byte UTF-8 sequence"), ++ (b"\xcfa", "Invalid continuation byte in 2-byte UTF-8 sequence"), ++ (b"\xd8\xcf\xd3", "Invalid continuation byte in 2-byte UTF-8 sequence"), ++ (b"\xd2\t\x8b\x84", "Invalid continuation byte in 2-byte UTF-8 sequence"), ++ (b"\xe2\x17\xce", "Invalid continuation byte in 3-byte UTF-8 sequence"), ++ (b"\xe2a\x17\xce", "Invalid continuation byte in 3-byte UTF-8 sequence"), ++ (b"\xe2\x17a", "Invalid continuation byte in 3-byte UTF-8 sequence"), ++ (b"\xe0\x9c\xc6\xde", "Invalid continuation byte in 3-byte UTF-8 sequence"), ++ (b"\xf0H\xce\x9b", "Invalid continuation byte in 4-byte UTF-8 sequence"), ++ (b"\xf0\xce4\x9b", "Invalid continuation byte in 4-byte UTF-8 sequence"), ++ # Truncated UTF-8 sequences ++ (b"\xc3", "Unterminated UTF-8 sequence when encoding string"), ++ (b"\x8c$\xe3", "Unterminated UTF-8 sequence when encoding string"), ++ (b"\x8c\xe3$", "Unterminated UTF-8 sequence when encoding string"), ++ (b"=\x8c\xe36", "Unterminated UTF-8 sequence when encoding string"), ++ (b"\x08\x11\xe3", "Unterminated UTF-8 sequence when encoding string"), ++ (b"\xf0\x90\x94", "Unterminated UTF-8 sequence when encoding string"), ++ # Small codepoints using longer byte sequences than they need ++ (b"\xc0\xa2", "Overlong 2-byte UTF-8 sequence"), ++ (b"A\xc1\x9c", "Overlong 2-byte UTF-8 sequence"), ++ (b"\xc1\xbf", "Overlong 2-byte UTF-8 sequence"), ++ (b"N\xc0\xb4\xb4", "Overlong 2-byte UTF-8 sequence"), ++ (b"\xe0\x9d\xb3", "Overlong 3-byte UTF-8 sequence"), ++ (b"E\xe0\x9e\x8b", "Overlong 3-byte UTF-8 sequence"), ++ (b"\xe0\x9f\xbf", "Overlong 3-byte UTF-8 sequence"), ++ (b"\xf0\x80\x80\x80", "Overlong 4-byte UTF-8 sequence"), ++ (b"\xf0\x8f\xbf\xbf", "Overlong 4-byte UTF-8 sequence"), ++ (b"\xf0\x85\xa7\xbd", "Overlong 4-byte UTF-8 sequence"), ++ # Codepoints above unicode max ++ (b"\xf4\x90\x80\x80", r">U\+10FFFF in 4-byte UTF-8 sequence"), ++ (b"\xf7\x8f\x99\x90", r">U\+10FFFF in 4-byte UTF-8 sequence"), ++ (b"\xf7\xbf\xbf\xbf", r">U\+10FFFF in 4-byte UTF-8 sequence"), ++ ], ++) ++def test_dump_bytes_invalid_utf8(value, error): ++ with pytest.raises((OverflowError, UnicodeDecodeError), match=error): ++ ujson.dumps(bytes(value), reject_bytes=False) ++ ++ ++def test_dump_bytes_fuzz(): ++ # ujson.dumps(..., reject_bytes=False) should accept or reject the same byte ++ # sequences as b"...".decode() when unpaired surrogates are allowed ++ for seed in range(10000): ++ r = random.Random(seed) ++ a = r.randbytes(r.randrange(8)) ++ try: ++ expected = a.decode(errors="surrogatepass") ++ except UnicodeDecodeError: ++ with pytest.raises((UnicodeDecodeError, OverflowError)): ++ ujson.dumps(a, reject_bytes=False) ++ else: ++ actual = ujson.loads(ujson.dumps(a, reject_bytes=False)) ++ assert actual == expected, (a, [bin(i) for i in a], actual, expected) ++ ++ + def test_encode_special_keys(): + data = {None: 0, True: 1, False: 2} + assert ujson.dumps(data) == '{"null":0,"true":1,"false":2}' +-- +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 ed08ede1d9..bd1f06acf9 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 @@ -14,6 +14,7 @@ SRC_URI += " \ file://CVE-2026-32875.patch \ file://CVE-2026-32874.patch \ file://CVE-2026-44660.patch \ + file://CVE-2026-54911.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.