Sync from SUSE:ALP:Source:Standard:1.0 python311 revision 55e37eb2b84ad153e90618a704f31d01
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
-------------------------------------------------------------------
|
||||
Wed Apr 15 18:00:50 UTC 2026 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
- Add CVE-2026-3446-base64-padding.patch preventing ignoring
|
||||
excess Base64 data after the first padded quad (bsc#1261970,
|
||||
CVE-2026-3446, gh#python/cpython#145264).
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Apr 2 13:55:57 UTC 2026 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
|
||||
@@ -215,6 +215,9 @@ Patch41: CVE-2026-4519-webbrowser-open-dashes.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2026-3479-pkgutil_get_data.patch bsc#1259989 mcepl@suse.com
|
||||
# pkgutil.get_data() reject invalid resource arguments
|
||||
Patch42: CVE-2026-3479-pkgutil_get_data.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2026-3446-base64-padding.patch bsc#1261970 mcepl@suse.com
|
||||
# Do not ignore excess Base64 data after the first padded quad
|
||||
Patch43: CVE-2026-3446-base64-padding.patch
|
||||
### END OF PATCHES
|
||||
BuildRequires: autoconf-archive
|
||||
BuildRequires: automake
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
From bd4ab523ba664863d40470cc718c566158adfa31 Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Date: Tue, 24 Mar 2026 01:20:26 +0200
|
||||
Subject: [PATCH] [3.14] gh-145264: Do not ignore excess Base64 data after the
|
||||
first padded quad (GH-145267) (GH-146326)
|
||||
|
||||
Base64 decoder (see binascii.a2b_base64(), base64.b64decode(), etc)
|
||||
no longer ignores excess data after the first padded quad in non-strict
|
||||
(default) mode. Instead, in conformance with RFC 4648, it ignores the
|
||||
pad character, "=", if it is present before the end of the encoded data.
|
||||
(cherry picked from commit 4561f6418a691b3e89aef0901f53fe0dfb7f7c0e)
|
||||
(cherry picked from commit e31c55121620189a0d1a07b689762d8ca9c1b7fa)
|
||||
|
||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
||||
---
|
||||
Lib/test/test_binascii.py | 33 +++
|
||||
Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst | 4
|
||||
Modules/binascii.c | 90 +++++-----
|
||||
3 files changed, 78 insertions(+), 49 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst
|
||||
|
||||
Index: Python-3.11.15/Lib/test/test_binascii.py
|
||||
===================================================================
|
||||
--- Python-3.11.15.orig/Lib/test/test_binascii.py 2026-04-16 01:25:00.019387400 +0200
|
||||
+++ Python-3.11.15/Lib/test/test_binascii.py 2026-04-16 01:37:02.691981027 +0200
|
||||
@@ -132,13 +132,20 @@
|
||||
def assertDiscontinuousPadding(data, non_strict_mode_expected_result: bytes):
|
||||
_assertRegexTemplate(r'(?i)Discontinuous padding', data, non_strict_mode_expected_result)
|
||||
|
||||
+ def assertExcessPadding(data, non_strict_mode_expected_result: bytes):
|
||||
+ _assertRegexTemplate(r'(?i)Excess padding', data, non_strict_mode_expected_result)
|
||||
+
|
||||
# Test excess data exceptions
|
||||
- assertExcessData(b'ab==a', b'i')
|
||||
- assertExcessData(b'ab===', b'i')
|
||||
- assertExcessData(b'ab==:', b'i')
|
||||
- assertExcessData(b'abc=a', b'i\xb7')
|
||||
- assertExcessData(b'abc=:', b'i\xb7')
|
||||
- assertExcessData(b'ab==\n', b'i')
|
||||
+ assertExcessPadding(b'ab===', b'i')
|
||||
+ assertExcessPadding(b'ab====', b'i')
|
||||
+ assertNonBase64Data(b'ab==:', b'i')
|
||||
+ assertExcessData(b'abc=a', b'i\xb7\x1a')
|
||||
+ assertNonBase64Data(b'abc=:', b'i\xb7')
|
||||
+ assertNonBase64Data(b'ab==\n', b'i')
|
||||
+ assertExcessPadding(b'abc==', b'i\xb7')
|
||||
+ assertExcessPadding(b'abc===', b'i\xb7')
|
||||
+ assertExcessPadding(b'abc====', b'i\xb7')
|
||||
+ assertExcessPadding(b'abc=====', b'i\xb7')
|
||||
|
||||
# Test non-base64 data exceptions
|
||||
assertNonBase64Data(b'\nab==', b'i')
|
||||
@@ -153,6 +160,20 @@
|
||||
assertDiscontinuousPadding(b'ab=c=', b'i\xb7')
|
||||
assertDiscontinuousPadding(b'ab=ab==', b'i\xb6\x9b')
|
||||
|
||||
+ def test_base64_excess_data(self):
|
||||
+ # Test excess data exceptions
|
||||
+ def assertExcessData(data, expected):
|
||||
+ assert_regex = r'(?i)Excess data'
|
||||
+ data = self.type2test(data)
|
||||
+ with self.assertRaisesRegex(binascii.Error, assert_regex):
|
||||
+ binascii.a2b_base64(data, strict_mode=True)
|
||||
+ self.assertEqual(binascii.a2b_base64(data, strict_mode=False),
|
||||
+ expected)
|
||||
+ self.assertEqual(binascii.a2b_base64(data), expected)
|
||||
+
|
||||
+ assertExcessData(b'ab==c=', b'i\xb7')
|
||||
+ assertExcessData(b'ab==cd', b'i\xb7\x1d')
|
||||
+ assertExcessData(b'abc=d', b'i\xb7\x1d')
|
||||
|
||||
def test_base64errors(self):
|
||||
# Test base64 with invalid padding
|
||||
Index: Python-3.11.15/Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.11.15/Misc/NEWS.d/next/Library/2026-02-26-20-13-16.gh-issue-145264.4pggX_.rst 2026-04-16 01:25:07.716277511 +0200
|
||||
@@ -0,0 +1,4 @@
|
||||
+Base64 decoder (see :func:`binascii.a2b_base64`, :func:`base64.b64decode`, etc) no
|
||||
+longer ignores excess data after the first padded quad in non-strict
|
||||
+(default) mode. Instead, in conformance with :rfc:`4648`, section 3.3, it now ignores
|
||||
+the pad character, "=", if it is present before the end of the encoded data.
|
||||
Index: Python-3.11.15/Modules/binascii.c
|
||||
===================================================================
|
||||
--- Python-3.11.15.orig/Modules/binascii.c 2026-03-03 01:52:57.000000000 +0100
|
||||
+++ Python-3.11.15/Modules/binascii.c 2026-04-16 01:33:46.756241326 +0200
|
||||
@@ -393,7 +393,6 @@
|
||||
const unsigned char *ascii_data = data->buf;
|
||||
size_t ascii_len = data->len;
|
||||
binascii_state *state = NULL;
|
||||
- char padding_started = 0;
|
||||
|
||||
/* Allocate the buffer */
|
||||
Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
|
||||
@@ -404,14 +403,6 @@
|
||||
return NULL;
|
||||
unsigned char *bin_data_start = bin_data;
|
||||
|
||||
- if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') {
|
||||
- state = get_binascii_state(module);
|
||||
- if (state) {
|
||||
- PyErr_SetString(state->Error, "Leading padding not allowed");
|
||||
- }
|
||||
- goto error_end;
|
||||
- }
|
||||
-
|
||||
int quad_pos = 0;
|
||||
unsigned char leftchar = 0;
|
||||
int pads = 0;
|
||||
@@ -422,28 +413,34 @@
|
||||
** the invalid ones.
|
||||
*/
|
||||
if (this_ch == BASE64_PAD) {
|
||||
- padding_started = 1;
|
||||
-
|
||||
- if (quad_pos >= 2 && quad_pos + ++pads >= 4) {
|
||||
- /* A pad sequence means we should not parse more input.
|
||||
- ** We've already interpreted the data from the quad at this point.
|
||||
- ** in strict mode, an error should raise if there's excess data after the padding.
|
||||
- */
|
||||
- if (strict_mode && i + 1 < ascii_len) {
|
||||
- state = get_binascii_state(module);
|
||||
- if (state) {
|
||||
- PyErr_SetString(state->Error, "Excess data after padding");
|
||||
- }
|
||||
- goto error_end;
|
||||
- }
|
||||
-
|
||||
- goto done;
|
||||
+ pads++;
|
||||
+ if (quad_pos >= 2 && quad_pos + pads <= 4) {
|
||||
+ continue;
|
||||
}
|
||||
- continue;
|
||||
+ // See RFC 4648, section-3.3: "specifications MAY ignore the
|
||||
+ // pad character, "=", treating it as non-alphabet data, if
|
||||
+ // it is present before the end of the encoded data" and
|
||||
+ // "the excess pad characters MAY also be ignored."
|
||||
+ if (!strict_mode) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (quad_pos == 1) {
|
||||
+ /* Set an error below. */
|
||||
+ break;
|
||||
+ }
|
||||
+ state = get_binascii_state(module);
|
||||
+ if (state) {
|
||||
+ PyErr_SetString(state->Error,
|
||||
+ (quad_pos == 0 && i == 0)
|
||||
+ ? "Leading padding not allowed"
|
||||
+ : "Excess padding not allowed");
|
||||
+ }
|
||||
+ goto error_end;
|
||||
}
|
||||
|
||||
this_ch = table_a2b_base64[this_ch];
|
||||
if (this_ch >= 64) {
|
||||
+ // See RFC 4648, section-3.3.
|
||||
if (strict_mode) {
|
||||
state = get_binascii_state(module);
|
||||
if (state) {
|
||||
@@ -454,11 +451,14 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
- // Characters that are not '=', in the middle of the padding, are not allowed
|
||||
- if (strict_mode && padding_started) {
|
||||
+ // Characters that are not '=', in the middle of the padding, are
|
||||
+ // not allowed (except when they are). See RFC 4648, section-3.3.
|
||||
+ if (pads && strict_mode) {
|
||||
state = get_binascii_state(module);
|
||||
if (state) {
|
||||
- PyErr_SetString(state->Error, "Discontinuous padding not allowed");
|
||||
+ PyErr_SetString(state->Error, (quad_pos + pads == 4)
|
||||
+ ? "Excess data after padding"
|
||||
+ : "Discontinuous padding not allowed");
|
||||
}
|
||||
goto error_end;
|
||||
}
|
||||
@@ -487,31 +487,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
- if (quad_pos != 0) {
|
||||
+ if (quad_pos == 1) {
|
||||
+ /* There is exactly one extra valid, non-padding, base64 character.
|
||||
+ * * This is an invalid length, as there is no possible input that
|
||||
+ ** could encoded into such a base64 string.
|
||||
+ */
|
||||
state = get_binascii_state(module);
|
||||
- if (state == NULL) {
|
||||
- /* error already set, from get_binascii_state */
|
||||
- } else if (quad_pos == 1) {
|
||||
- /*
|
||||
- ** There is exactly one extra valid, non-padding, base64 character.
|
||||
- ** This is an invalid length, as there is no possible input that
|
||||
- ** could encoded into such a base64 string.
|
||||
- */
|
||||
+ if (state) {
|
||||
PyErr_Format(state->Error,
|
||||
"Invalid base64-encoded string: "
|
||||
"number of data characters (%zd) cannot be 1 more "
|
||||
"than a multiple of 4",
|
||||
(bin_data - bin_data_start) / 3 * 4 + 1);
|
||||
- } else {
|
||||
+ }
|
||||
+ goto error_end;
|
||||
+ }
|
||||
+
|
||||
+ if (quad_pos != 0 && quad_pos + pads < 4) {
|
||||
+ state = get_binascii_state(module);
|
||||
+ if (state) {
|
||||
PyErr_SetString(state->Error, "Incorrect padding");
|
||||
}
|
||||
- error_end:
|
||||
- _PyBytesWriter_Dealloc(&writer);
|
||||
- return NULL;
|
||||
+ goto error_end;
|
||||
}
|
||||
|
||||
-done:
|
||||
return _PyBytesWriter_Finish(&writer, bin_data);
|
||||
+
|
||||
+error_end:
|
||||
+ _PyBytesWriter_Dealloc(&writer);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user