From: "Yoann Congal" <yoann.congal@smile.fr>
To: "Song, Jiaying (CN)" <Jiaying.Song.CN@windriver.com>,
"Wang, Jinfeng (CN)" <Jinfeng.Wang.CN@windriver.com>,
"openembedded-core@lists.openembedded.org"
<openembedded-core@lists.openembedded.org>
Subject: Re: [OE-core] [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922
Date: Fri, 08 May 2026 01:01:30 +0200 [thread overview]
Message-ID: <DICTHBF30UIC.SLD2UTBGTJVU@smile.fr> (raw)
In-Reply-To: <IA4PR11MB942062CFC3DECE261B819667B8362@IA4PR11MB9420.namprd11.prod.outlook.com>
On Mon Apr 27, 2026 at 8:04 AM CEST, Jiaying (CN) Song wrote:
> Hi Yoann,
>
> This patch is for scarthgap where pyasn1 is at 0.5.1. The 0.6.2 -> 0.6.3 upgrade would only apply to master. According to https://github.com/pyasn1/pyasn1/security/advisories/GHSA-jr27-m4p2-rc6r ,
> all versions <= 0.6.2 are affected, so for scarthgap, this patch is still needed to fix the CVE.
Yes, agreed but the trouble was that is was not fixed on master and,
therefore, could not be fixed on scarthgap.
Now the situation has changed, it is fixed on master by upgrading to
0.6.3 but wrynose is now vulnerable.
Can you send a fix to wrynose? I can't merge a fix to scarthgap without
one for wrynose.
Thanks!
>
> Best regards,
> Jiaying.
> -----Original Message-----
> From: openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org> On Behalf Of Yoann Congal via lists.openembedded.org
> Sent: Friday, April 24, 2026 3:36 PM
> To: Wang, Jinfeng (CN) <Jinfeng.Wang.CN@windriver.com>; openembedded-core@lists.openembedded.org
> Subject: Re: [OE-core] [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922
>
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and know the content is safe.
>
> On Thu Apr 9, 2026 at 8:16 AM CEST, Jinfeng (CN) via lists.openembedded.org Wang wrote:
>> From: Jiaying Song <jiaying.song.cn@windriver.com>
>>
>> pyasn1 is a generic ASN.1 library for Python. Prior to 0.6.3, the
>> `pyasn1` library is vulnerable to a Denial of Service (DoS) attack
>> caused by uncontrolled recursion when decoding ASN.1 data with deeply
>> nested structures. An attacker can supply a crafted payload containing
>> thousands of nested `SEQUENCE` (`0x30`) or `SET` (`0x31`) tags with
>> "Indefinite Length" (`0x80`) markers. This forces the decoder to
>> recursively call itself until the Python interpreter crashes with a
>> `RecursionError` or consumes all available memory (OOM), crashing the
>> host application. This is a distinct vulnerability from CVE-2026-23490
>> (which addressed integer overflows in OID decoding). The fix for
>> CVE-2026-23490 (`MAX_OID_ARC_CONTINUATION_OCTETS`) does not mitigate
>> this recursion issue. Version 0.6.3 fixes this specific issue.
>>
>> References:
>> https://nvd.nist.gov/vuln/detail/CVE-2026-30922
>>
>> Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
>> Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com>
>> ---
>
> AFAIK, this CVE also apply to master (I'm not sure why it does not appear on https://valkyrie.yocto.io/pub/non-release/patchmetrics/)
>
> I'll hold this patch until "python3-pyasn1: upgrade 0.6.2 -> 0.6.3"
> merges.
>
>> .../recipes-devtools/python/python-pyasn1.inc | 1 +
>> .../python3-pyasn1/CVE-2026-30922.patch | 257 ++++++++++++++++++
>> 2 files changed, 258 insertions(+)
>> create mode 100644
>> meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch
>>
>> diff --git a/meta/recipes-devtools/python/python-pyasn1.inc
>> b/meta/recipes-devtools/python/python-pyasn1.inc
>> index 96b4a3b52a..d69cdf8877 100644
>> --- a/meta/recipes-devtools/python/python-pyasn1.inc
>> +++ b/meta/recipes-devtools/python/python-pyasn1.inc
>> @@ -19,6 +19,7 @@ inherit ptest
>> SRC_URI += " \
>> file://run-ptest \
>> file://CVE-2026-23490.patch \
>> + file://CVE-2026-30922.patch \
>> "
>>
>> RDEPENDS:${PN}-ptest += " \
>> diff --git
>> a/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch
>> b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch
>> new file mode 100644
>> index 0000000000..7eceaa2595
>> --- /dev/null
>> +++ b/meta/recipes-devtools/python/python3-pyasn1/CVE-2026-30922.patch
>> @@ -0,0 +1,257 @@
>> +From 85e901d1dacdcd17363cc2dd18a91cfb72363eeb Mon Sep 17 00:00:00
>> +2001
>> +From: Simon Pichugin <simon.pichugin@gmail.com>
>> +Date: Thu, 19 Mar 2026 17:11:40 +0800
>> +Subject: [PATCH] Merge commit from fork
>> +
>> +CVE: CVE-2026-30922
>> +
>> +Upstream-Status: Backport
>> +[https://github.com/pyasn1/pyasn1/commit/25ad481c19]
>> +
>> +Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com>
>> +---
>> + pyasn1/codec/ber/decoder.py | 10 +++
>> + tests/codec/ber/test_decoder.py | 114
>> +++++++++++++++++++++++++++++++++ tests/codec/cer/test_decoder.py |
>> +22 ++++++ tests/codec/der/test_decoder.py | 40 +++++++++++
>> + 4 files changed, 186 insertions(+)
>> +
>> +diff --git a/pyasn1/codec/ber/decoder.py
>> +b/pyasn1/codec/ber/decoder.py index be8ba65..da2a048 100644
>> +--- a/pyasn1/codec/ber/decoder.py
>> ++++ b/pyasn1/codec/ber/decoder.py
>> +@@ -38,6 +38,7 @@ 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
>> ++MAX_NESTING_DEPTH = 100
>> +
>> +
>> + class AbstractPayloadDecoder(object):
>> +@@ -1515,6 +1516,15 @@ class SingleItemDecoder(object):
>> + decodeFun=None, substrateFun=None,
>> + **options):
>> +
>> ++ _nestingLevel = options.get('_nestingLevel', 0)
>> ++
>> ++ if _nestingLevel > MAX_NESTING_DEPTH:
>> ++ raise error.PyAsn1Error(
>> ++ 'ASN.1 structure nesting depth exceeds limit (%d)' % MAX_NESTING_DEPTH
>> ++ )
>> ++
>> ++ options['_nestingLevel'] = _nestingLevel + 1
>> ++
>> + allowEoo = options.pop('allowEoo', False)
>> +
>> + if LOG:
>> +diff --git a/tests/codec/ber/test_decoder.py
>> +b/tests/codec/ber/test_decoder.py index f033dfd..226381a 100644
>> +--- a/tests/codec/ber/test_decoder.py
>> ++++ b/tests/codec/ber/test_decoder.py
>> +@@ -1987,6 +1987,120 @@ class CompressedFilesTestCase(BaseTestCase):
>> + finally:
>> + os.remove(path)
>> +
>> ++class NestingDepthLimitTestCase(BaseTestCase):
>> ++ """Test protection against deeply nested ASN.1 structures (CVE prevention)."""
>> ++
>> ++ def testIndefLenSequenceNesting(self):
>> ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error."""
>> ++ # Each \x30\x80 opens a new indefinite-length SEQUENCE
>> ++ payload = b'\x30\x80' * 200
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except error.PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected'
>> ++
>> ++ def testIndefLenSetNesting(self):
>> ++ """Deeply nested indefinite-length SETs must raise PyAsn1Error."""
>> ++ # Each \x31\x80 opens a new indefinite-length SET
>> ++ payload = b'\x31\x80' * 200
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except error.PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Deeply nested indef-length SETs not rejected'
>> ++
>> ++ def testDefiniteLenNesting(self):
>> ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error."""
>> ++ inner = b'\x05\x00' # NULL
>> ++ for _ in range(200):
>> ++ length = len(inner)
>> ++ if length < 128:
>> ++ inner = b'\x30' + bytes([length]) + inner
>> ++ else:
>> ++ length_bytes = length.to_bytes(
>> ++ (length.bit_length() + 7) // 8, 'big')
>> ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \
>> ++ length_bytes + inner
>> ++ try:
>> ++ decoder.decode(inner)
>> ++ except error.PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected'
>> ++
>> ++ def testNestingUnderLimitWorks(self):
>> ++ """Nesting within the limit must decode successfully."""
>> ++ inner = b'\x05\x00' # NULL
>> ++ for _ in range(50):
>> ++ length = len(inner)
>> ++ if length < 128:
>> ++ inner = b'\x30' + bytes([length]) + inner
>> ++ else:
>> ++ length_bytes = length.to_bytes(
>> ++ (length.bit_length() + 7) // 8, 'big')
>> ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \
>> ++ length_bytes + inner
>> ++ asn1Object, _ = decoder.decode(inner)
>> ++ assert asn1Object is not None, 'Valid nested structure rejected'
>> ++
>> ++ def testSiblingsDontIncreaseDepth(self):
>> ++ """Sibling elements at the same level must not inflate depth count."""
>> ++ # SEQUENCE containing 200 INTEGER siblings - should decode fine
>> ++ components = b'\x02\x01\x01' * 200 # 200 x INTEGER(1)
>> ++ length = len(components)
>> ++ length_bytes = length.to_bytes(
>> ++ (length.bit_length() + 7) // 8, 'big')
>> ++ payload = b'\x30' + bytes([0x80 | len(length_bytes)]) + \
>> ++ length_bytes + components
>> ++ asn1Object, _ = decoder.decode(payload)
>> ++ assert asn1Object is not None, 'Siblings incorrectly rejected'
>> ++
>> ++ def testErrorMessageContainsLimit(self):
>> ++ """Error message must indicate the nesting depth limit."""
>> ++ payload = b'\x30\x80' * 200
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except error.PyAsn1Error as exc:
>> ++ assert 'nesting depth' in str(exc).lower(), \
>> ++ 'Error message missing depth info: %s' % exc
>> ++ else:
>> ++ assert False, 'Expected PyAsn1Error'
>> ++
>> ++ def testNoRecursionError(self):
>> ++ """Must raise PyAsn1Error, not RecursionError."""
>> ++ payload = b'\x30\x80' * 50000
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except error.PyAsn1Error:
>> ++ pass
>> ++ except RecursionError:
>> ++ assert False, 'Got RecursionError instead of PyAsn1Error'
>> ++
>> ++ def testMixedNesting(self):
>> ++ """Mixed SEQUENCE and SET nesting must be caught."""
>> ++ # Alternate SEQUENCE (0x30) and SET (0x31) with indef length
>> ++ payload = b''
>> ++ for i in range(200):
>> ++ payload += b'\x30\x80' if i % 2 == 0 else b'\x31\x80'
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except error.PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Mixed nesting not rejected'
>> ++
>> ++ def testWithSchema(self):
>> ++ """Deeply nested structures must be caught even with schema."""
>> ++ payload = b'\x30\x80' * 200
>> ++ try:
>> ++ decoder.decode(payload, asn1Spec=univ.Sequence())
>> ++ except error.PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Deeply nested with schema not rejected'
>> +
>> + class NonStreamingCompatibilityTestCase(BaseTestCase):
>> + def setUp(self):
>> +diff --git a/tests/codec/cer/test_decoder.py
>> +b/tests/codec/cer/test_decoder.py index 133affd..fbb1145 100644
>> +--- a/tests/codec/cer/test_decoder.py
>> ++++ b/tests/codec/cer/test_decoder.py
>> +@@ -363,6 +363,28 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
>> + assert s[0] == 3
>> + assert s[1][0] == univ.OctetString(hexValue='02010C')
>> +
>> ++class NestingDepthLimitTestCase(BaseTestCase):
>> ++ """Test CER decoder protection against deeply nested structures."""
>> ++
>> ++ def testIndefLenNesting(self):
>> ++ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error."""
>> ++ payload = b'\x30\x80' * 200
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Deeply nested indef-length SEQUENCEs not rejected'
>> ++
>> ++ def testNoRecursionError(self):
>> ++ """Must raise PyAsn1Error, not RecursionError."""
>> ++ payload = b'\x30\x80' * 50000
>> ++ try:
>> ++ decoder.decode(payload)
>> ++ except PyAsn1Error:
>> ++ pass
>> ++ except RecursionError:
>> ++ assert False, 'Got RecursionError instead of PyAsn1Error'
>> +
>> + suite =
>> + unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
>> +
>> +diff --git a/tests/codec/der/test_decoder.py
>> +b/tests/codec/der/test_decoder.py index 5bc9deb..b0fa867 100644
>> +--- a/tests/codec/der/test_decoder.py
>> ++++ b/tests/codec/der/test_decoder.py
>> +@@ -361,6 +361,46 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase):
>> + assert s[0] == 3
>> + assert s[1][0] == univ.OctetString(hexValue='02010C')
>> +
>> ++class NestingDepthLimitTestCase(BaseTestCase):
>> ++ """Test DER decoder protection against deeply nested structures."""
>> ++
>> ++ def testDefiniteLenNesting(self):
>> ++ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error."""
>> ++ inner = b'\x05\x00' # NULL
>> ++ for _ in range(200):
>> ++ length = len(inner)
>> ++ if length < 128:
>> ++ inner = b'\x30' + bytes([length]) + inner
>> ++ else:
>> ++ length_bytes = length.to_bytes(
>> ++ (length.bit_length() + 7) // 8, 'big')
>> ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \
>> ++ length_bytes + inner
>> ++ try:
>> ++ decoder.decode(inner)
>> ++ except PyAsn1Error:
>> ++ pass
>> ++ else:
>> ++ assert False, 'Deeply nested definite-length SEQUENCEs not rejected'
>> ++
>> ++ def testNoRecursionError(self):
>> ++ """Must raise PyAsn1Error, not RecursionError."""
>> ++ inner = b'\x05\x00'
>> ++ for _ in range(200):
>> ++ length = len(inner)
>> ++ if length < 128:
>> ++ inner = b'\x30' + bytes([length]) + inner
>> ++ else:
>> ++ length_bytes = length.to_bytes(
>> ++ (length.bit_length() + 7) // 8, 'big')
>> ++ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \
>> ++ length_bytes + inner
>> ++ try:
>> ++ decoder.decode(inner)
>> ++ except PyAsn1Error:
>> ++ pass
>> ++ except RecursionError:
>> ++ assert False, 'Got RecursionError instead of PyAsn1Error'
>> +
>> + suite =
>> + unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
>> +
>> +--
>> +2.34.1
>> +
>
>
> --
> Yoann Congal
> Smile ECS
--
Yoann Congal
Smile ECS
next prev parent reply other threads:[~2026-05-07 23:01 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 6:16 [scarthgap][PATCH 00/12] Fix multiple CVEs jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 01/12] gi-docgen: fix CVE-2025-11687 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 02/12] libsoup: fix CVE-2025-14523/CVE-2025-32049 jinfeng.wang.cn
2026-04-23 17:09 ` [OE-core] " Yoann Congal
2026-04-24 7:16 ` Li, Changqing
2026-04-09 6:16 ` [scarthgap][PATCH 03/12] libsoup-2.4: " jinfeng.wang.cn
2026-04-23 17:13 ` [OE-core] " Yoann Congal
2026-04-24 7:37 ` Li, Changqing
2026-04-09 6:16 ` [scarthgap][PATCH 04/12] python3-ply: fix CVE-2025-56005 jinfeng.wang.cn
2026-04-24 6:45 ` [OE-core] " Yoann Congal
2026-04-27 6:20 ` Chen, Libo (CN)
[not found] ` <18AA22684C0F041F.2188217@lists.openembedded.org>
2026-05-06 8:24 ` Chen, Libo (CN)
2026-05-07 11:02 ` Yoann Congal
2026-04-09 6:16 ` [scarthgap][PATCH 05/12] python3-pyasn1: fix CVE-2026-23490 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 06/12] python3-wheel: fix CVE-2026-24049 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 07/12] gnupg: fix CVE-2026-24882 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 08/12] libxml2: Fix CVE-2026-1757 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 09/12] python3-pyasn1: fix CVE-2026-30922 jinfeng.wang.cn
2026-04-24 7:36 ` [OE-core] " Yoann Congal
2026-04-27 6:04 ` Song, Jiaying (CN)
2026-05-07 23:01 ` Yoann Congal [this message]
2026-04-09 6:16 ` [scarthgap][PATCH 10/12] busybox: fix CVE-2026-26157 and CVE-2026-26158 jinfeng.wang.cn
2026-04-09 6:16 ` [scarthgap][PATCH 11/12] zlib: upgrade 1.3.1 -> 1.3.2 jinfeng.wang.cn
2026-04-24 8:10 ` [OE-core] " Yoann Congal
2026-04-09 6:16 ` [scarthgap][PATCH 12/12] libpcap: 1.10.4 -> 1.10.6 jinfeng.wang.cn
2026-04-24 8:21 ` [OE-core] " Yoann Congal
2026-05-06 3:05 ` Kai
2026-05-07 16:32 ` Yoann Congal
2026-05-09 6:17 ` Kai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DICTHBF30UIC.SLD2UTBGTJVU@smile.fr \
--to=yoann.congal@smile.fr \
--cc=Jiaying.Song.CN@windriver.com \
--cc=Jinfeng.Wang.CN@windriver.com \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.