@@ -19,6 +19,7 @@ inherit ptest
SRC_URI += " \
file://run-ptest \
file://CVE-2026-23490.patch \
+ file://CVE-2026-59886.patch \
"
RDEPENDS:${PN}-ptest += " \
new file mode 100644
@@ -0,0 +1,252 @@
+From 9b89b511a7284f17ef3a2de6d05fbf6030133abb Mon Sep 17 00:00:00 2001
+From: Simon Pichugin <simon.pichugin@gmail.com>
+Date: Wed, 8 Jul 2026 17:32:09 -0700
+Subject: [PATCH] Merge commit from fork
+
+CVE: CVE-2026-59886
+Upstream-Status: Backport [https://github.com/pyasn1/pyasn1/commit/e60c691cb91addb8fcefa2f537e85ede6fb1e886]
+
+(cherry picked from commit e60c691cb91addb8fcefa2f537e85ede6fb1e886)
+Signed-off-by: Emily Vekariya <evekariy@cisco.com>
+---
+ pyasn1/type/univ.py | 21 +++++++++----
+ tests/codec/ber/test_decoder.py | 53 +++++++++++++++++++++++++++------
+ tests/codec/cer/test_decoder.py | 10 +++++++
+ tests/codec/der/test_decoder.py | 19 ++++++++++++
+ tests/type/test_univ.py | 40 +++++++++++++++++++++++++
+ 5 files changed, 129 insertions(+), 14 deletions(-)
+
+diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
+index c5d0778..adff2df 100644
+--- a/pyasn1/type/univ.py
++++ b/pyasn1/type/univ.py
+@@ -1318,7 +1318,7 @@ class Real(base.SimpleAsn1Type):
+ def __normalizeBase10(value):
+ m, b, e = value
+ while m and m % 10 == 0:
+- m /= 10
++ m //= 10
+ e += 1
+ return m, b, e
+
+@@ -1457,10 +1457,21 @@ class Real(base.SimpleAsn1Type):
+ def __float__(self):
+ if self._value in self._inf:
+ return self._value
+- else:
+- return float(
+- self._value[0] * pow(self._value[1], self._value[2])
+- )
++
++ mantissa, base, exponent = self._value
++
++ if not mantissa:
++ return 0.0
++
++ if base == 2:
++ return math.ldexp(float(mantissa), exponent)
++
++ # base is 10 (prettyIn() rejects everything else); refuse to
++ # materialize astronomically large integers via pow()
++ if exponent > sys.float_info.max_10_exp:
++ raise OverflowError('Real value too large to convert to float')
++
++ return float(mantissa * pow(base, exponent))
+
+ def __abs__(self):
+ return self.clone(abs(float(self)))
+diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
+index f033dfd..f6ff7b0 100644
+--- a/tests/codec/ber/test_decoder.py
++++ b/tests/codec/ber/test_decoder.py
+@@ -21,6 +21,7 @@ from pyasn1.type import univ
+ from pyasn1.type import char
+ from pyasn1.codec import streaming
+ from pyasn1.codec.ber import decoder
++from pyasn1.codec.ber import encoder
+ from pyasn1.codec.ber import eoo
+ from pyasn1.compat.octets import ints2octs, str2octs, null
+ from pyasn1 import error
+@@ -547,17 +548,51 @@ class RealDecoderTestCase(BaseTestCase):
+ ints2octs((9, 4, 161, 255, 1, 3))
+ ) == (univ.Real((3, 2, -1020)), null)
+
+-# TODO: this requires Real type comparison fix
++ def testBin6(self): # large exponent, base = 16
++ value, rest = decoder.decode(
++ bytes((9, 5, 162, 0, 255, 255, 1))
++ )
++
++ assert tuple(value) == (1, 2, 262140)
++ assert rest == b''
++
++ def testBin7(self): # large exponent in 4-octet form, base = 16
++ value, rest = decoder.decode(
++ bytes((9, 7, 227, 4, 1, 35, 69, 103, 1))
++ )
+
+-# def testBin6(self):
+-# assert decoder.decode(
+-# ints2octs((9, 5, 162, 0, 255, 255, 1))
+-# ) == (univ.Real((1, 2, 262140)), null)
++ assert tuple(value) == (-1, 2, 76354972)
++ assert rest == b''
++
++ def testLargeBinaryRoundTrip(self):
++ substrate = encoder.encode(univ.Real((-1, 2, 76354972)))
++ value, rest = decoder.decode(substrate)
++
++ assert tuple(value) == (-1, 2, 76354972)
++ assert rest == b''
++
++ def testLongFormBinaryRealExponentLength(self):
++ value, rest = decoder.decode(
++ bytes((9, 6, 0x83, 3, 0x0f, 0x42, 0x40, 1))
++ )
+
+-# def testBin7(self):
+-# assert decoder.decode(
+-# ints2octs((9, 7, 227, 4, 1, 35, 69, 103, 1))
+-# ) == (univ.Real((-1, 2, 76354972)), null)
++ assert tuple(value) == (1, 2, 1000000)
++ assert rest == b''
++
++ def testLargeBinaryPrettyPrintOverflow(self):
++ value, rest = decoder.decode(
++ b'\t\t\xeb\x060662.666\xd0B\x00\x00\x00\x00\x00\x00\x00'
++ )
++
++ assert value.prettyPrint() == '<overflow>'
++ assert rest == b'6\xd0B\x00\x00\x00\x00\x00\x00\x00'
++
++ try:
++ float(value)
++ except OverflowError:
++ pass
++ else:
++ assert 0, '__float__() tolerated overflow'
+
+ def testPlusInf(self):
+ assert decoder.decode(
+diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py
+index 133affd..3d27194 100644
+--- a/tests/codec/cer/test_decoder.py
++++ b/tests/codec/cer/test_decoder.py
+@@ -15,6 +15,7 @@ from pyasn1.type import opentype
+ from pyasn1.type import univ
+ from pyasn1.codec.cer import decoder
+ from pyasn1.compat.octets import ints2octs, str2octs, null
++from pyasn1.codec.cer import encoder
+ from pyasn1.error import PyAsn1Error
+
+
+@@ -66,6 +67,15 @@ class OctetStringDecoderTestCase(BaseTestCase):
+ # TODO: test failures on short chunked and long unchunked substrate samples
+
+
++class RealDecoderTestCase(BaseTestCase):
++ def testLargeBinaryRoundTrip(self):
++ substrate = encoder.encode(univ.Real((-1, 2, 76354972)))
++ value, rest = decoder.decode(substrate)
++
++ assert tuple(value) == (-1, 2, 76354972)
++ assert rest == b''
++
++
+ class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py
+index 5bc9deb..553563c 100644
+--- a/tests/codec/der/test_decoder.py
++++ b/tests/codec/der/test_decoder.py
+@@ -15,6 +15,7 @@ from pyasn1.type import opentype
+ from pyasn1.type import univ
+ from pyasn1.codec.der import decoder
+ from pyasn1.compat.octets import ints2octs, null
++from pyasn1.codec.der import encoder
+ from pyasn1.error import PyAsn1Error
+
+
+@@ -72,6 +73,24 @@ class OctetStringDecoderTestCase(BaseTestCase):
+ assert 0, 'chunked encoding tolerated'
+
+
++class RealDecoderTestCase(BaseTestCase):
++ def testCanonicalLargeBinaryReal(self):
++ substrate = encoder.encode(univ.Real((1, 2, 1000000)))
++ assert substrate == bytes((9, 5, 0x82, 0x0f, 0x42, 0x40, 1))
++
++ value, rest = decoder.decode(substrate)
++
++ assert tuple(value) == (1, 2, 1000000)
++ assert rest == b''
++
++ def testLargeBinaryRoundTrip(self):
++ substrate = encoder.encode(univ.Real((-1, 2, 76354972)))
++ value, rest = decoder.decode(substrate)
++
++ assert tuple(value) == (-1, 2, 76354972)
++ assert rest == b''
++
++
+ class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase):
+ def setUp(self):
+ openType = opentype.OpenType(
+diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py
+index 8aec183..bc21c37 100644
+--- a/tests/type/test_univ.py
++++ b/tests/type/test_univ.py
+@@ -780,9 +780,49 @@ class RealTestCase(BaseTestCase):
+ def testFloat(self):
+ assert float(univ.Real(4.0)) == 4.0, '__float__() fails'
+
++ def testFloatBase10Precision(self):
++ assert float(univ.Real((3, 10, 23))) == 3e23, '__float__() lost base-10 behavior'
++
++ def testFloatOverflow(self):
++ try:
++ float(univ.Real((1, 2, 1000000)))
++ except OverflowError:
++ pass
++ else:
++ assert 0, '__float__() tolerated overflow'
++
++ assert univ.Real((1, 2, 1000000)).prettyPrint() == '<overflow>'
++
++ def testFloatUnderflow(self):
++ assert float(univ.Real((1, 2, -1000000))) == 0.0, '__float__() failed underflow'
++
++ def testFloatZeroMantissa(self):
++ assert float(univ.Real((0, 10, 1000000000))) == 0.0, '__float__() failed zero mantissa'
++ assert float(univ.Real((0, 2, 1000000000))) == 0.0, '__float__() failed zero mantissa'
++
++ def testFloatBase10Overflow(self):
++ try:
++ float(univ.Real((1, 10, sys.float_info.max_10_exp + 1)))
++ except OverflowError:
++ pass
++ else:
++ assert 0, '__float__() tolerated base-10 overflow'
++
++ def testFloatBase10NormalizedOverflow(self):
++ try:
++ float(univ.Real((10, 10, sys.float_info.max_10_exp)))
++ except OverflowError:
++ pass
++ else:
++ assert 0, '__float__() tolerated normalized base-10 overflow'
++
+ def testPrettyIn(self):
+ assert univ.Real((3, 10, 0)) == 3, 'prettyIn() fails'
+
++ def testPrettyInBigBase10Mantissa(self):
++ assert tuple(univ.Real((10 ** 400, 10, 0))) == (1, 10, 400), \
++ 'prettyIn() big mantissa normalization fails'
++
+ # infinite float values
+ def testStrInf(self):
+ assert str(univ.Real('inf')) == 'inf', 'str() fails'
+--
+2.34.1
+