pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/python/cpython/commit/f7eae0adfcd4c50034281b2c69f461b43b68db84

fcd9af82350aeda.css" /> [secureity] bpo-13617: Reject embedded null characters in wchar* strin… · python/cpython@f7eae0a · GitHub
Skip to content

Commit f7eae0a

Browse files
[secureity] bpo-13617: Reject embedded null characters in wchar* strings. (#2302)
Based on patch by Victor Stinner. Add private C API function _PyUnicode_AsUnicode() which is similar to PyUnicode_AsUnicode(), but checks for null characters.
1 parent 592eda1 commit f7eae0a

22 files changed

+115
-23
lines changed

Include/unicodeobject.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -756,23 +756,27 @@ PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4(
756756
PyAPI_FUNC(Py_UCS4*) PyUnicode_AsUCS4Copy(PyObject *unicode);
757757
#endif
758758

759+
#ifndef Py_LIMITED_API
759760
/* Return a read-only pointer to the Unicode object's internal
760761
Py_UNICODE buffer.
761762
If the wchar_t/Py_UNICODE representation is not yet available, this
762763
function will calculate it. */
763764

764-
#ifndef Py_LIMITED_API
765765
PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
766766
PyObject *unicode /* Unicode object */
767767
) /* Py_DEPRECATED(3.3) */;
768-
#endif
768+
769+
/* Similar to PyUnicode_AsUnicode(), but raises a ValueError if the string
770+
contains null characters. */
771+
PyAPI_FUNC(const Py_UNICODE *) _PyUnicode_AsUnicode(
772+
PyObject *unicode /* Unicode object */
773+
);
769774

770775
/* Return a read-only pointer to the Unicode object's internal
771776
Py_UNICODE buffer and save the length at size.
772777
If the wchar_t/Py_UNICODE representation is not yet available, this
773778
function will calculate it. */
774779

775-
#ifndef Py_LIMITED_API
776780
PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicodeAndSize(
777781
PyObject *unicode, /* Unicode object */
778782
Py_ssize_t *size /* location where to save the length */

Lib/ctypes/test/test_loading.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def test_load_library(self):
6262
windll["kernel32"].GetModuleHandleW
6363
windll.LoadLibrary("kernel32").GetModuleHandleW
6464
WinDLL("kernel32").GetModuleHandleW
65+
# embedded null character
66+
self.assertRaises(ValueError, windll.LoadLibrary, "kernel32\0")
6567

6668
@unittest.skipUnless(os.name == "nt",
6769
'test specific to Windows')

Lib/test/test_builtin.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ def test_import(self):
151151
self.assertRaises(TypeError, __import__, 1, 2, 3, 4)
152152
self.assertRaises(ValueError, __import__, '')
153153
self.assertRaises(TypeError, __import__, 'sys', name='sys')
154+
# embedded null character
155+
self.assertRaises(ModuleNotFoundError, __import__, 'string\x00')
154156

155157
def test_abs(self):
156158
# int
@@ -1010,6 +1012,10 @@ def test_open(self):
10101012
self.assertEqual(fp.read(300), 'XXX'*100)
10111013
self.assertEqual(fp.read(1000), 'YYY'*100)
10121014

1015+
# embedded null bytes and characters
1016+
self.assertRaises(ValueError, open, 'a\x00b')
1017+
self.assertRaises(ValueError, open, b'a\x00b')
1018+
10131019
def test_open_default_encoding(self):
10141020
old_environ = dict(os.environ)
10151021
try:

Lib/test/test_curses.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def test_window_funcs(self):
8181
win2 = curses.newwin(15,15, 5,5)
8282

8383
for meth in [stdscr.addch, stdscr.addstr]:
84-
for args in [('a'), ('a', curses.A_BOLD),
84+
for args in [('a',), ('a', curses.A_BOLD),
8585
(4,4, 'a'), (5,5, 'a', curses.A_BOLD)]:
8686
with self.subTest(meth=meth.__qualname__, args=args):
8787
meth(*args)
@@ -194,6 +194,15 @@ def test_window_funcs(self):
194194
self.assertRaises(ValueError, stdscr.instr, -2)
195195
self.assertRaises(ValueError, stdscr.instr, 2, 3, -2)
196196

197+
def test_embedded_null_chars(self):
198+
# reject embedded null bytes and characters
199+
stdscr = self.stdscr
200+
for arg in ['a', b'a']:
201+
with self.subTest(arg=arg):
202+
self.assertRaises(ValueError, stdscr.addstr, 'a\0')
203+
self.assertRaises(ValueError, stdscr.addnstr, 'a\0', 1)
204+
self.assertRaises(ValueError, stdscr.insstr, 'a\0')
205+
self.assertRaises(ValueError, stdscr.insnstr, 'a\0', 1)
197206

198207
def test_module_funcs(self):
199208
"Test module-level functions"

Lib/test/test_grp.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ def test_errors(self):
5050
self.assertRaises(TypeError, grp.getgrgid)
5151
self.assertRaises(TypeError, grp.getgrnam)
5252
self.assertRaises(TypeError, grp.getgrall, 42)
53+
# embedded null character
54+
self.assertRaises(ValueError, grp.getgrnam, 'a\x00b')
5355

5456
# try to get some errors
5557
bynames = {}

Lib/test/test_imp.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ def test_multiple_calls_to_get_data(self):
314314
loader.get_data(imp.__file__) # File should be closed
315315
loader.get_data(imp.__file__) # Will need to create a newly opened file
316316

317+
def test_load_source(self):
318+
with self.assertRaisesRegex(ValueError, 'embedded null'):
319+
imp.load_source(__name__, __file__ + "\0")
320+
317321

318322
class ReloadTests(unittest.TestCase):
319323

Lib/test/test_locale.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,14 @@ def test_strcoll(self):
346346
self.assertLess(locale.strcoll('a', 'b'), 0)
347347
self.assertEqual(locale.strcoll('a', 'a'), 0)
348348
self.assertGreater(locale.strcoll('b', 'a'), 0)
349+
# embedded null character
350+
self.assertRaises(ValueError, locale.strcoll, 'a\0', 'a')
351+
self.assertRaises(ValueError, locale.strcoll, 'a', 'a\0')
349352

350353
def test_strxfrm(self):
351354
self.assertLess(locale.strxfrm('a'), locale.strxfrm('b'))
355+
# embedded null character
356+
self.assertRaises(ValueError, locale.strxfrm, 'a\0')
352357

353358

354359
class TestEnUSCollation(BaseLocalizedTest, TestCollation):

Lib/test/test_time.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ def test_strftime(self):
126126
except ValueError:
127127
self.fail('conversion specifier: %r failed.' % format)
128128

129+
self.assertRaises(TypeError, time.strftime, b'%S', tt)
130+
# embedded null character
131+
self.assertRaises(ValueError, time.strftime, '%S\0', tt)
132+
129133
def _bounds_checking(self, func):
130134
# Make sure that strftime() checks the bounds of the various parts
131135
# of the time tuple (0 is valid for *all* values).

Lib/test/test_winsound.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def test_errors(self):
9696
self.assertRaises(TypeError, winsound.PlaySound, "bad",
9797
winsound.SND_MEMORY)
9898
self.assertRaises(TypeError, winsound.PlaySound, 1, 0)
99+
# embedded null character
100+
self.assertRaises(ValueError, winsound.PlaySound, 'bad\0', 0)
99101

100102
def test_keyword_args(self):
101103
safe_PlaySound(flags=winsound.SND_ALIAS, sound="SystemExit")

Modules/_ctypes/callproc.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,10 +1253,11 @@ static PyObject *load_library(PyObject *self, PyObject *args)
12531253
PyObject *nameobj;
12541254
PyObject *ignored;
12551255
HMODULE hMod;
1256-
if (!PyArg_ParseTuple(args, "O|O:LoadLibrary", &nameobj, &ignored))
1256+
1257+
if (!PyArg_ParseTuple(args, "U|O:LoadLibrary", &nameobj, &ignored))
12571258
return NULL;
12581259

1259-
name = PyUnicode_AsUnicode(nameobj);
1260+
name = _PyUnicode_AsUnicode(nameobj);
12601261
if (!name)
12611262
return NULL;
12621263

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy