Jiaying Song 60345ecc4b python3-pyasn1: fix CVE-2026-23490
pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.2, a
Denial-of-Service issue has been found that leads to memory exhaustion
from malformed RELATIVE-OID with excessive continuation octets. This
vulnerability is fixed in 0.6.2.

References:
https://nvd.nist.gov/vuln/detail/CVE-2026-23490

(From OE-Core rev: 205d360b49c7bbaa8709cb5a0b2e57457c32ad22)

Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com>
Signed-off-by: Yoann Congal <yoann.congal@smile.fr>
Signed-off-by: Paul Barker <paul@pbarker.dev>
2026-05-04 13:57:31 +01:00

137 lines
5.9 KiB
Diff

From d98d7bc91864e1e368d4849c26568e33c0dd0e27 Mon Sep 17 00:00:00 2001
From: Simon Pichugin <simon.pichugin@gmail.com>
Date: Wed, 28 Jan 2026 16:31:29 +0800
Subject: [PATCH] Merge commit from fork
Add limit of 20 continuation octets per OID arc to prevent a potential
memory exhaustion from excessive continuation bytes input.
CVE: CVE-2026-23490
Upstream-Status: Backport [https://github.com/pyasn1/pyasn1/commit/3908f14422]
Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
---
pyasn1/codec/ber/decoder.py | 13 ++++++-
tests/codec/ber/test_decoder.py | 65 +++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py
index 7cc863d..be8ba65 100644
--- a/pyasn1/codec/ber/decoder.py
+++ b/pyasn1/codec/ber/decoder.py
@@ -35,6 +35,10 @@ noValue = base.noValue
SubstrateUnderrunError = error.SubstrateUnderrunError
+# Maximum number of continuation octets (high-bit set) allowed per OID arc.
+# 20 octets allows up to 140-bit integers, supporting UUID-based OIDs
+MAX_OID_ARC_CONTINUATION_OCTETS = 20
+
class AbstractPayloadDecoder(object):
protoComponent = None
@@ -431,7 +435,14 @@ class ObjectIdentifierPayloadDecoder(AbstractSimplePayloadDecoder):
# Construct subid from a number of octets
nextSubId = subId
subId = 0
+ continuationOctetCount = 0
while nextSubId >= 128:
+ continuationOctetCount += 1
+ if continuationOctetCount > MAX_OID_ARC_CONTINUATION_OCTETS:
+ raise error.PyAsn1Error(
+ 'OID arc exceeds maximum continuation octets limit (%d) '
+ 'at position %d' % (MAX_OID_ARC_CONTINUATION_OCTETS, index)
+ )
subId = (subId << 7) + (nextSubId & 0x7F)
if index >= substrateLen:
raise error.SubstrateUnderrunError(
@@ -1872,7 +1883,7 @@ class StreamingDecoder(object):
:py:class:`~pyasn1.error.SubstrateUnderrunError` object indicating
insufficient BER/CER/DER serialization on input to fully recover ASN.1
objects from it.
-
+
In the latter case the caller is advised to ensure some more data in
the input stream, then call the iterator again. The decoder will resume
the decoding process using the newly arrived data.
diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
index 3b97ce4..f033dfd 100644
--- a/tests/codec/ber/test_decoder.py
+++ b/tests/codec/ber/test_decoder.py
@@ -450,6 +450,71 @@ class ObjectIdentifierDecoderTestCase(BaseTestCase):
ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47))
) == ((2, 999, 18446744073709551535184467440737095), null)
+ def testExcessiveContinuationOctets(self):
+ """Test that OID arcs with excessive continuation octets are rejected."""
+ # Create a payload with 25 continuation octets (exceeds 20 limit)
+ # 0x81 bytes are continuation octets, 0x01 terminates
+ malicious_payload = bytes([0x06, 26]) + bytes([0x81] * 25) + bytes([0x01])
+ try:
+ decoder.decode(malicious_payload)
+ except error.PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Excessive continuation octets tolerated'
+
+ def testMaxAllowedContinuationOctets(self):
+ """Test that OID arcs at the maximum continuation octets limit work."""
+ # Create a payload with exactly 20 continuation octets (at limit)
+ # This should succeed
+ payload = bytes([0x06, 21]) + bytes([0x81] * 20) + bytes([0x01])
+ try:
+ decoder.decode(payload)
+ except error.PyAsn1Error:
+ assert 0, 'Valid OID with 20 continuation octets rejected'
+
+ def testOneOverContinuationLimit(self):
+ """Test boundary: 21 continuation octets (one over limit) is rejected."""
+ payload = bytes([0x06, 22]) + bytes([0x81] * 21) + bytes([0x01])
+ try:
+ decoder.decode(payload)
+ except error.PyAsn1Error:
+ pass
+ else:
+ assert 0, '21 continuation octets tolerated (should be rejected)'
+
+ def testExcessiveContinuationInSecondArc(self):
+ """Test that limit applies to subsequent arcs, not just the first."""
+ # First arc: valid simple byte (0x55 = 85, decodes to arc 2.5)
+ # Second arc: excessive continuation octets
+ payload = bytes([0x06, 27]) + bytes([0x55]) + bytes([0x81] * 25) + bytes([0x01])
+ try:
+ decoder.decode(payload)
+ except error.PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Excessive continuation in second arc tolerated'
+
+ def testMultipleArcsAtLimit(self):
+ """Test multiple arcs each at the continuation limit work correctly."""
+ # Two arcs, each with 20 continuation octets (both at limit)
+ arc1 = bytes([0x81] * 20) + bytes([0x01]) # 21 bytes
+ arc2 = bytes([0x81] * 20) + bytes([0x01]) # 21 bytes
+ payload = bytes([0x06, 42]) + arc1 + arc2
+ try:
+ decoder.decode(payload)
+ except error.PyAsn1Error:
+ assert 0, 'Multiple valid arcs at limit rejected'
+
+ def testExcessiveContinuationWithMaxBytes(self):
+ """Test with 0xFF continuation bytes (maximum value, not just 0x81)."""
+ # 0xFF bytes are also continuation octets (high bit set)
+ malicious_payload = bytes([0x06, 26]) + bytes([0xFF] * 25) + bytes([0x01])
+ try:
+ decoder.decode(malicious_payload)
+ except error.PyAsn1Error:
+ pass
+ else:
+ assert 0, 'Excessive 0xFF continuation octets tolerated'
class RealDecoderTestCase(BaseTestCase):
def testChar(self):
--
2.34.1