cpython: 4a31f6b11e7a (original) (raw)

--- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -253,11 +253,15 @@ always available. :const:verbose :option:-v :const:bytes_warning :option:-b :const:quiet :option:-q

+ .. data:: float_info

--- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1272,6 +1272,8 @@ Basic customization inheritance of :meth:__hash__ will be blocked, just as if :attr:__hash__ had been explicitly set to :const:None.

.. method:: object.bool(self)

--- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -24,7 +24,7 @@ Command line When invoking Python, you may specify any of these options::

The most common use case is, of course, a simple invocation of a script:: @@ -227,6 +227,29 @@ Miscellaneous options .. versionadded:: 3.2 +.. cmdoption:: -R +

+ .. cmdoption:: -s Don't add the :data:user site-packages directory <site.USER_SITE> to @@ -350,6 +373,7 @@ Options you shouldn't use .. _Jython: http://jython.org[](#l3.44) + .. _using-on-envvars: Environment variables @@ -458,6 +482,27 @@ These environment variables influence Py option. +.. envvar:: PYTHONHASHSEED +

+ .. envvar:: PYTHONIOENCODING If this is set before running the interpreter, it overrides the encoding used

--- a/Include/object.h +++ b/Include/object.h @@ -517,6 +517,12 @@ PyAPI_FUNC(Py_hash_t) _Py_HashDouble(dou PyAPI_FUNC(Py_hash_t) _Py_HashPointer(void*); #endif +typedef struct {

+} _Py_HashSecret_t; +PyAPI_DATA(_Py_HashSecret_t) _Py_HashSecret; + /* Helper for passing objects to printf and the like */ #define PyObject_REPR(obj) _PyUnicode_AsString(PyObject_Repr(obj))

--- a/Include/pydebug.h +++ b/Include/pydebug.h @@ -20,6 +20,7 @@ PyAPI_DATA(int) Py_DivisionWarningFlag; PyAPI_DATA(int) Py_DontWriteBytecodeFlag; PyAPI_DATA(int) Py_NoUserSiteDirectory; PyAPI_DATA(int) Py_UnbufferedStdioFlag; +PyAPI_DATA(int) Py_HashRandomizationFlag; /* this is a wrapper around getenv() that pays attention to Py_IgnoreEnvironmentFlag. It should be used for getting variables like

--- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -248,6 +248,8 @@ typedef void (PyOS_sighandler_t)(int); PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); +/ Random */ +PyAPI_FUNC(int) _PyOS_URandom (void *buffer, Py_ssize_t size); #ifdef __cplusplus }

--- a/Lib/json/init.py +++ b/Lib/json/init.py @@ -31,7 +31,9 @@ Encoding basic Python object hierarchies Compact encoding:: >>> import json

--- a/Lib/os.py +++ b/Lib/os.py @@ -761,23 +761,6 @@ try: except NameError: # statvfs_result may not exist pass -if not _exists("urandom"):

-

-

-

Supply os.popen()

def popen(cmd, mode="r", buffering=-1): if not isinstance(cmd, str):

--- a/Lib/test/mapping_tests.py +++ b/Lib/test/mapping_tests.py @@ -14,7 +14,7 @@ class BasicTestMappingProtocol(unittest. def _reference(self): """Return a dictionary of values which are invariant by storage in the object under test."""

--- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -496,6 +496,11 @@ def main(tests=None, testdir=None, verbo except ValueError: print("Couldn't find starting test (%s), using all tests" % start) if randomize:

--- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -3,7 +3,6 @@ import sys import os -import re import os.path import tempfile import subprocess @@ -20,11 +19,15 @@ def _assert_python(expected_success, *ar cmd_line = [sys.executable] if not env_vars: cmd_line.append('-E')

--- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -330,6 +330,22 @@ class CmdLineTest(unittest.TestCase): def test_no_std_streams(self): self._test_no_stdio(['stdin', 'stdout', 'stderr'])

+

def test_main(): test.support.run_unittest(CmdLineTest)

--- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4474,8 +4474,18 @@ class DictProxyTests(unittest.TestCase): def test_repr(self): # Testing dict_proxy.repr

class PTypesLongInitTest(unittest.TestCase):

--- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -52,13 +52,18 @@ class DebuggerTests(unittest.TestCase): """Test that the debugger can debug Python."""

Returns its stdout, stderr """

@@ -118,7 +123,7 @@ class DebuggerTests(unittest.TestCase): # print ' '.join(args) # Use "args" to invoke gdb, capturing stdout, stderr:

# Ignore some noise on stderr due to the pending breakpoint: err = err.replace('Function "%s" not defined.\n' % breakpoint, '') @@ -207,7 +212,8 @@ class PrettyPrintTests(DebuggerTests): 'Verify the pretty-printing of dictionaries' self.assertGdbRepr({}) self.assertGdbRepr({'foo': 'bar'})

def test_lists(self): 'Verify the pretty-printing of lists' @@ -269,8 +275,8 @@ class PrettyPrintTests(DebuggerTests): def test_sets(self): 'Verify the pretty-printing of sets' self.assertGdbRepr(set())

# Ensure that we handle sets containing the "dummy" key value, # which happens on deletion: @@ -282,8 +288,8 @@ id(s)''') def test_frozensets(self): 'Verify the pretty-printing of frozensets' self.assertGdbRepr(frozenset())

def test_exceptions(self): # Test a RuntimeError

--- a/Lib/test/test_hash.py +++ b/Lib/test/test_hash.py @@ -3,10 +3,16 @@ #

Also test that hash implementations are inherited as expected

+import datetime +import os +import sys import unittest from test import support +from test.script_helper import assert_python_ok from collections import Hashable +IS_64BIT = sys.maxsize > 2**32 + class HashEqualityTestCase(unittest.TestCase): @@ -118,10 +124,92 @@ class HashBuiltinsTestCase(unittest.Test for obj in self.hashes_to_check: self.assertEqual(hash(obj), _default_hash(obj)) +class HashRandomizationTests(unittest.TestCase): +

+

+

+

+ +class StringlikeHashRandomizationTests(HashRandomizationTests):

+

+

+

+ +class StrHashRandomizationTests(StringlikeHashRandomizationTests):

+

+ +class BytesHashRandomizationTests(StringlikeHashRandomizationTests):

+

+ +class DatetimeTests(HashRandomizationTests):

+ +class DatetimeDateTests(DatetimeTests):

+ +class DatetimeDatetimeTests(DatetimeTests):

+ +class DatetimeTimeTests(DatetimeTests):

+ + def test_main(): support.run_unittest(HashEqualityTestCase,

if name == "main":

--- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -15,6 +15,7 @@ from test import support import contextlib import mmap import uuid +from test.script_helper import assert_python_ok

Detect whether we're on a Linux system that uses the (now outdated

and unmaintained) linuxthreads threading library. There's an issue

@@ -611,14 +612,33 @@ class DevNullTests(unittest.TestCase): self.assertEqual(f.read(), b'') class URandomTests(unittest.TestCase):

+

+

+

@contextlib.contextmanager def _execvpe_mockup(defpath=None):

--- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -733,6 +733,17 @@ class TestBasicOps(unittest.TestCase): if self.repr is not None: self.assertEqual(repr(self.set), self.repr)

+

+ def test_print(self): try: fo = open(support.TESTFN, "w") @@ -891,7 +902,9 @@ class TestBasicOpsString(TestBasicOps): self.set = set(self.values) self.dup = set(self.values) self.length = 3

+

#------------------------------------------------------------------------------ @@ -902,7 +915,9 @@ class TestBasicOpsBytes(TestBasicOps): self.set = set(self.values) self.dup = set(self.values) self.length = 3

+

#------------------------------------------------------------------------------ @@ -916,11 +931,13 @@ class TestBasicOpsMixedStringBytes(TestB self.set = set(self.values) self.dup = set(self.values) self.length = 4

def tearDown(self): self._warning_filters.exit(None, None, None)

+ #============================================================================== def baditer():

--- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -503,7 +503,7 @@ class SysModuleTest(unittest.TestCase): attrs = ("debug", "division_warning", "inspect", "interactive", "optimize", "dont_write_bytecode", "no_user_site", "no_site", "ignore_environment", "verbose",

--- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -13,6 +13,7 @@ import sys import tempfile from base64 import b64encode +import collections def hexescape(char): """Escape char as RFC 2396 specifies""" @@ -953,8 +954,9 @@ class urlencode_Tests(unittest.TestCase) self.assertEqual("a=1&a=2", urllib.parse.urlencode({"a": [1, 2]}, True)) self.assertEqual("a=None&a=a", urllib.parse.urlencode({"a": [None, "a"]}, True))

def test_urlencode_encoding(self): # ASCII encoding. Expect %3F with errors="replace'

old mode 100644 new mode 100755 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -769,7 +769,8 @@ class UrlParseTestCase(unittest.TestCase # Other tests incidentally urlencode things; test non-covered cases: # Sequence and object values. result = urllib.parse.urlencode({'a': [1, 2], 'b': (3, 4, 5)}, True)

class Trivial: def str(self):

--- a/Lib/tkinter/test/test_ttk/test_functions.py +++ b/Lib/tkinter/test/test_ttk/test_functions.py @@ -143,7 +143,7 @@ class InternalFunctionsTest(unittest.Tes ('a', 'b', 'c')), ("test {a b} c", ())) # state spec and options self.assertEqual(ttk._format_elemcreate('image', False, 'test',

--- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -322,6 +322,7 @@ PYTHON_OBJS= [](#l22.3) Python/pystate.o [](#l22.4) Python/pythonrun.o [](#l22.5) Python/pytime.o [](#l22.6) + Python/random.o [](#l22.7) Python/structmember.o [](#l22.8) Python/symtable.o [](#l22.9) Python/sysmodule.o [](#l22.10)

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ What's New in Python 3.2.3? Core and Builtins ----------------- +- Issue #13703: oCERT-2011-003: add -R command-line option and PYTHONHASHSEED

--- a/Misc/python.man +++ b/Misc/python.man @@ -37,6 +37,9 @@ python - an interpreted, interactive, o .B -OO ] [ +.B -R +] +[ .B -Q .I argument ] @@ -152,6 +155,18 @@ Discard docstrings in addition to the \f Do not print the version and copyright messages. These messages are also suppressed in non-interactive mode. .TP +.B -R +Turn on "hash randomization", so that the hash() values of str, bytes and +datetime objects are "salted" with an unpredictable pseudo-random value. +Although they remain constant within an individual Python process, they are +not predictable between repeated invocations of Python. +.IP +This is intended to provide protection against a denial of service +caused by carefully-chosen inputs that exploit the worst case performance +of a dict insertion, O(n^2) complexity. See +http://www.ocert.org/advisories/ocert-2011-003.html[](#l24.26) +for details. +.TP .BI "-Q " argument Division control; see PEP 238. The argument must be one of "old" (the default, int/int and long/long return an int or long), "new" (new @@ -413,6 +428,20 @@ specifying \fB-v\fP multiple times. .IP PYTHONWARNINGS If this is set to a comma-separated string it is equivalent to specifying the \fB-W\fP option for each separate value. +.IP PYTHONHASHSEED +If this variable is set to "random", the effect is the same as specifying +the \fB-R\fP option: a random value is used to seed the hashes of str, +bytes and datetime objects. + +If PYTHONHASHSEED is set to an integer value, it is used as a fixed seed for +generating the hash() of the types covered by the hash randomization. Its +purpose is to allow repeatable hashing, such as for selftests for the +interpreter itself, or to allow a cluster of python processes to share hash +values. + +The integer must be a decimal number in the range [0,4294967295]. Specifying +the value 0 will lead to the same hash values as when hash randomization is +disabled. .SH AUTHOR The Python Software Foundation: http://www.python.org/psf[](#l24.51) .SH INTERNET RESOURCES

--- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -2785,10 +2785,12 @@ generic_hash(unsigned char *data, int le register Py_hash_t x; p = (unsigned char *) data;

--- a/Modules/main.c +++ b/Modules/main.c @@ -46,7 +46,7 @@ static wchar_t *orig_argv; static int orig_argc; / command line options */ -#define BASE_OPTS L"bBc:dEhiJm:OqsStuvVW:xX:?" +#define BASE_OPTS L"bBc:dEhiJm:OqRsStuvVW:xX:?" #define PROGRAM_OPTS BASE_OPTS @@ -72,6 +72,9 @@ static char *usage_2 = "[](#l26.12) -O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n[](#l26.13) -OO : remove doc-strings in addition to the -O optimizations\n[](#l26.14) -q : don't print version and copyright messages on interactive startup\n[](#l26.15) +-R : use a pseudo-random salt to make hash() values of various types be\n[](#l26.16)

-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n[](#l26.19) -S : don't imply 'import site' on initialization\n[](#l26.20) "; @@ -99,8 +102,14 @@ static char *usage_5 = "PYTHONHOME : alternate directory (or %c).\n" " The default module search path uses %s.\n" "PYTHONCASEOK : ignore case in 'import' statements (Windows).\n" -"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n" -; +"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n[](#l26.28) +"; +static char *usage_6 = "[](#l26.30) +PYTHONHASHSEED: if this variable is set to random, the effect is the same \n[](#l26.31)

static int usage(int exitcode, wchar_t* program) @@ -116,6 +125,7 @@ usage(int exitcode, wchar_t* program) fputs(usage_3, f); fprintf(f, usage_4, DELIM); fprintf(f, usage_5, DELIM, PYTHONHOMEHELP);

#if defined(__VMS) if (exitcode == 0) { @@ -429,6 +439,10 @@ Py_Main(int argc, wchar_t **argv) Py_QuietFlag++; break;

+ /* This space reserved for other options */ default:

--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7614,82 +7614,6 @@ posix_getloadavg(PyObject *self, PyObjec } #endif -#ifdef MS_WINDOWS - -PyDoc_STRVAR(win32_urandom__doc__, -"urandom(n) -> str\n\n[](#l27.10) -Return n random bytes suitable for cryptographic use."); - -typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,[](#l27.13)

-typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,[](#l27.16)

- -static CRYPTGENRANDOM pCryptGenRandom = NULL; -/* This handle is never explicitly released. Instead, the operating

-static PyObject* -win32_urandom(PyObject *self, PyObject *args) -{

-

-

-

-

-

-

-

-} -#endif - PyDoc_STRVAR(device_encoding__doc__, "device_encoding(fd) -> str\n\n[](#l27.84) Return a string describing the encoding of the device\n[](#l27.85) @@ -7727,41 +7651,35 @@ device_encoding(PyObject self, PyObject return Py_None; } -#ifdef __VMS -/ Use openssl random routine / -#include <openssl/rand.h> -PyDoc_STRVAR(vms_urandom__doc__, +PyDoc_STRVAR(posix_urandom__doc__, "urandom(n) -> str\n\n[](#l27.95) Return n random bytes suitable for cryptographic use."); -static PyObject -vms_urandom(PyObject *self, PyObject *args) -{

-

+static PyObject * +posix_urandom(PyObject *self, PyObject *args) +{

+

-

+

#ifdef HAVE_SETRESUID PyDoc_STRVAR(posix_setresuid__doc__, @@ -8137,12 +8055,7 @@ static PyMethodDef posix_methods[] = { #ifdef HAVE_GETLOADAVG {"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__}, #endif

#ifdef HAVE_SETRESUID {"setresuid", posix_setresuid, METH_VARARGS, posix_setresuid__doc__}, #endif @@ -8155,7 +8068,6 @@ static PyMethodDef posix_methods[] = { #ifdef HAVE_GETRESGID {"getresgid", posix_getresgid, METH_NOARGS, posix_getresgid__doc__}, #endif - {NULL, NULL} /* Sentinel */ };

--- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -878,11 +878,21 @@ bytes_hash(PyBytesObject *a) if (a->ob_shash != -1) return a->ob_shash; len = Py_SIZE(a);

--- a/Objects/object.c +++ b/Objects/object.c @@ -754,6 +754,8 @@ PyObject_HashNotImplemented(PyObject *v) return -1; } +_Py_HashSecret_t _Py_HashSecret; + Py_hash_t PyObject_Hash(PyObject *v) {

--- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7676,11 +7676,21 @@ unicode_hash(PyUnicodeObject *self) if (self->hash != -1) return self->hash; len = Py_SIZE(self);

--- a/PCbuild/pythoncore.vcproj +++ b/PCbuild/pythoncore.vcproj @@ -1882,6 +1882,10 @@ RelativePath="..\Python\pythonrun.c" >

--- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -70,6 +70,7 @@ extern void _PyUnicode_Init(void); extern void _PyUnicode_Fini(void); extern int _PyLong_Init(void); extern void PyLong_Fini(void); +extern void _PyRandom_Init(void); #ifdef WITH_THREAD extern void _PyGILState_Init(PyInterpreterState , PyThreadState ); @@ -89,6 +90,7 @@ int Py_FrozenFlag; / Needed by getpath. int Py_IgnoreEnvironmentFlag; / e.g. PYTHONPATH, PYTHONHOME / int Py_NoUserSiteDirectory = 0; / for -s and site.py / int Py_UnbufferedStdioFlag = 0; / Unbuffered binary std{in,out,err} / +int Py_HashRandomizationFlag = 0; / for -R and PYTHONHASHSEED */ PyThreadState *_Py_Finalizing = NULL; @@ -207,6 +209,12 @@ Py_InitializeEx(int install_sigs) Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0') Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p);

+

interp = PyInterpreterState_New(); if (interp == NULL)

new file mode 100644 --- /dev/null +++ b/Python/random.c @@ -0,0 +1,302 @@ +#include "Python.h" +#ifdef MS_WINDOWS +#include <windows.h> +#else +#include <fcntl.h> +#endif + +static int random_initialized = 0; + +#ifdef MS_WINDOWS +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,[](#l33.15)

+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,[](#l33.18)

+ +static CRYPTGENRANDOM pCryptGenRandom = NULL; +/* This handle is never explicitly released. Instead, the operating

+static int +win32_urandom_init(int raise) +{

+

+

+

+

+

+ +error:

+} + +/* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen

+

+

+} +#endif /* MS_WINDOWS / + + +#ifdef __VMS +/ Use openssl random routine */ +#include <openssl/rand.h> +static int +vms_urandom(unsigned char *buffer, Py_ssize_t size, int raise) +{

+} +#endif /* __VMS / + + +#if !defined(MS_WINDOWS) && !defined(__VMS) + +/ Read size bytes from /dev/urandom into buffer.

+

+

+

+} + +/* Read size bytes from /dev/urandom into buffer.

+

+

+

+

+} +#endif /* !defined(MS_WINDOWS) && !defined(__VMS) / + +/ Fill buffer with pseudo-random bytes generated by a linear congruent

+

+

+} + +/* Fill buffer with size pseudo-random bytes, not suitable for cryptographic

+ +#ifdef MS_WINDOWS

+#else +# ifdef __VMS

+# else

+# endif +#endif +} + +void +_PyRandom_Init(void) +{

+

+

+

+

+#ifdef MS_WINDOWS

+#else /* #ifdef MS_WINDOWS */ +# ifdef __VMS

+# else

+# endif +#endif

+}

--- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1368,6 +1368,7 @@ static PyStructSequence_Field flags_fiel /* {"skip_first", "-x"}, */ {"bytes_warning", "-b"}, {"quiet", "-q"},

#ifdef RISCOS

#else

#endif }; @@ -1412,6 +1413,7 @@ make_flags(void) /* SetFlag(skipfirstline); */ SetFlag(Py_BytesWarningFlag); SetFlag(Py_QuietFlag);

#undef SetFlag if (PyErr_Occurred()) {