Skip to content

Commit c9f54cf

Browse files
committed
enable hash randomization by default
1 parent 6ca5a4d commit c9f54cf

File tree

9 files changed

+44
-65
lines changed

9 files changed

+44
-65
lines changed

Doc/reference/datamodel.rst

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,29 @@ Basic customization
12771277
inheritance of :meth:`__hash__` will be blocked, just as if :attr:`__hash__`
12781278
had been explicitly set to :const:`None`.
12791279

1280-
See also the :option:`-R` command-line option.
1280+
1281+
.. note::
1282+
1283+
Note by default the :meth:`__hash__` values of str, bytes and datetime
1284+
objects are "salted" with an unpredictable random value. Although they
1285+
remain constant within an individual Python process, they are not
1286+
predictable between repeated invocations of Python.
1287+
1288+
This is intended to provide protection against a denial-of-service caused
1289+
by carefully-chosen inputs that exploit the worst case performance of a
1290+
dict insertion, O(n^2) complexity. See
1291+
http://www.ocert.org/advisories/ocert-2011-003.html for details.
1292+
1293+
Changing hash values affects the order in which keys are retrieved from a
1294+
dict. Although Python has never made guarantees about this ordering (and
1295+
it typically varies between 32-bit and 64-bit builds), enough real-world
1296+
code implicitly relies on this non-guaranteed behavior that the
1297+
randomization is disabled by default.
1298+
1299+
See also :envvar:`PYTHONHASHSEED`.
1300+
1301+
.. versionchanged:: 3.3
1302+
Hash randomization is enabled by default.
12811303

12821304

12831305
.. method:: object.__bool__(self)

Doc/using/cmdline.rst

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Command line
2424

2525
When invoking Python, you may specify any of these options::
2626

27-
python [-bBdEhiORqsSuvVWx?] [-c command | -m module-name | script | - ] [args]
27+
python [-bBdEhiOqsSuvVWx?] [-c command | -m module-name | script | - ] [args]
2828

2929
The most common use case is, of course, a simple invocation of a script::
3030

@@ -486,9 +486,8 @@ These environment variables influence Python's behavior.
486486

487487
.. envvar:: PYTHONHASHSEED
488488

489-
If this variable is set to ``random``, the effect is the same as specifying
490-
the :option:`-R` option: a random value is used to seed the hashes of str,
491-
bytes and datetime objects.
489+
If this variable is set to ``random``, a random value is used to seed the
490+
hashes of str, bytes and datetime objects.
492491

493492
If :envvar:`PYTHONHASHSEED` is set to an integer value, it is used as a fixed
494493
seed for generating the hash() of the types covered by the hash
@@ -499,8 +498,7 @@ These environment variables influence Python's behavior.
499498
values.
500499

501500
The integer must be a decimal number in the range [0,4294967295]. Specifying
502-
the value 0 will lead to the same hash values as when hash randomization is
503-
disabled.
501+
the value 0 will disable hash randomization.
504502

505503
.. versionadded:: 3.2.3
506504

Lib/test/test_cmd_line.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,14 +330,14 @@ def test_hash_randomization(self):
330330
hashes = []
331331
for i in range(2):
332332
code = 'print(hash("spam"))'
333-
rc, out, err = assert_python_ok('-R', '-c', code)
333+
rc, out, err = assert_python_ok('-c', code)
334334
self.assertEqual(rc, 0)
335335
hashes.append(out)
336336
self.assertNotEqual(hashes[0], hashes[1])
337337

338338
# Verify that sys.flags contains hash_randomization
339339
code = 'import sys; print("random is", sys.flags.hash_randomization)'
340-
rc, out, err = assert_python_ok('-R', '-c', code)
340+
rc, out, err = assert_python_ok('-c', code)
341341
self.assertEqual(rc, 0)
342342
self.assertIn(b'random is 1', out)
343343

Lib/test/test_hash.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ def test_null_hash(self):
159159
else:
160160
known_hash_of_obj = -1600925533
161161

162-
# Randomization is disabled by default:
163-
self.assertEqual(self.get_hash(self.repr_), known_hash_of_obj)
162+
# Randomization is enabled by default:
163+
self.assertNotEqual(self.get_hash(self.repr_), known_hash_of_obj)
164164

165165
# It can also be disabled by setting the seed to 0:
166166
self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)

Misc/NEWS

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ Core and Builtins
1818
- Issue #14051: Allow arbitrary attributes to be set of classmethod and
1919
staticmethod.
2020

21-
- Issue #13703: oCERT-2011-003: add -R command-line option and PYTHONHASHSEED
22-
environment variable, to provide an opt-in way to protect against denial of
23-
service attacks due to hash collisions within the dict and set types. Patch
24-
by David Malcolm, based on work by Victor Stinner.
21+
- Issue #13703: oCERT-2011-003: Randomize hashes of str and bytes to protect
22+
against denial of service attacks due to hash collisions within the dict and
23+
set types. Patch by David Malcolm, based on work by Victor Stinner.
2524

2625
- Issue #13020: Fix a reference leak when allocating a structsequence object
2726
fails. Patch by Suman Saha.

Misc/python.man

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ python \- an interpreted, interactive, object-oriented programming language
3737
.B \-OO
3838
]
3939
[
40-
.B \-R
41-
]
42-
[
4340
.B \-s
4441
]
4542
[
@@ -151,18 +148,6 @@ Discard docstrings in addition to the \fB-O\fP optimizations.
151148
Do not print the version and copyright messages. These messages are
152149
also suppressed in non-interactive mode.
153150
.TP
154-
.B \-R
155-
Turn on "hash randomization", so that the hash() values of str, bytes and
156-
datetime objects are "salted" with an unpredictable pseudo-random value.
157-
Although they remain constant within an individual Python process, they are
158-
not predictable between repeated invocations of Python.
159-
.IP
160-
This is intended to provide protection against a denial of service
161-
caused by carefully-chosen inputs that exploit the worst case performance
162-
of a dict insertion, O(n^2) complexity. See
163-
http://www.ocert.org/advisories/ocert-2011-003.html
164-
for details.
165-
.TP
166151
.B \-s
167152
Don't add user site directory to sys.path.
168153
.TP
@@ -418,9 +403,8 @@ specifying \fB\-v\fP multiple times.
418403
If this is set to a comma-separated string it is equivalent to
419404
specifying the \fB\-W\fP option for each separate value.
420405
.IP PYTHONHASHSEED
421-
If this variable is set to "random", the effect is the same as specifying
422-
the \fB-R\fP option: a random value is used to seed the hashes of str,
423-
bytes and datetime objects.
406+
If this variable is set to "random", a random value is used to seed the hashes
407+
of str, bytes and datetime objects.
424408

425409
If PYTHONHASHSEED is set to an integer value, it is used as a fixed seed for
426410
generating the hash() of the types covered by the hash randomization. Its
@@ -429,8 +413,7 @@ interpreter itself, or to allow a cluster of python processes to share hash
429413
values.
430414

431415
The integer must be a decimal number in the range [0,4294967295]. Specifying
432-
the value 0 will lead to the same hash values as when hash randomization is
433-
disabled.
416+
the value 0 will disable hash randomization.
434417
.SH AUTHOR
435418
The Python Software Foundation: http://www.python.org/psf
436419
.SH INTERNET RESOURCES

Modules/main.c

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ static char *usage_2 = "\
7373
-O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n\
7474
-OO : remove doc-strings in addition to the -O optimizations\n\
7575
-q : don't print version and copyright messages on interactive startup\n\
76-
-R : use a pseudo-random salt to make hash() values of various types be\n\
77-
unpredictable between separate invocations of the interpreter, as\n\
78-
a defence against denial-of-service attacks\n\
7976
-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
8077
-S : don't imply 'import site' on initialization\n\
8178
";
@@ -107,10 +104,10 @@ static char *usage_5 =
107104
"PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n\
108105
";
109106
static char *usage_6 = "\
110-
PYTHONHASHSEED: if this variable is set to ``random``, the effect is the same \n\
111-
as specifying the :option:`-R` option: a random value is used to seed the\n\
112-
hashes of str, bytes and datetime objects. It can also be set to an integer\n\
113-
in the range [0,4294967295] to get hash values with a predictable seed.\n\
107+
PYTHONHASHSEED: if this variable is set to ``random``, a random value is used\n\
108+
to seed the hashes of str, bytes and datetime objects. It can also be\n\
109+
set to an integer in the range [0,4294967295] to get hash values with a\n\
110+
predictable seed.\n\
114111
";
115112

116113
static int
@@ -347,21 +344,13 @@ Py_Main(int argc, wchar_t **argv)
347344
not interpreter options. */
348345
break;
349346
}
350-
switch (c) {
351-
case 'E':
347+
if (c == 'E') {
352348
Py_IgnoreEnvironmentFlag++;
353349
break;
354-
case 'R':
355-
Py_HashRandomizationFlag++;
356-
break;
357350
}
358351
}
359-
/* The variable is only tested for existence here; _PyRandom_Init will
360-
check its value further. */
361-
if (!Py_HashRandomizationFlag &&
362-
(p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0')
363-
Py_HashRandomizationFlag = 1;
364352

353+
Py_HashRandomizationFlag = 1;
365354
_PyRandom_Init();
366355

367356
PySys_ResetWarnOptions();
@@ -468,7 +457,7 @@ Py_Main(int argc, wchar_t **argv)
468457
break;
469458

470459
case 'R':
471-
/* Already handled above */
460+
/* Ignored */
472461
break;
473462

474463
/* This space reserved for other options */

Python/random.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -256,17 +256,6 @@ _PyRandom_Init(void)
256256
return;
257257
_Py_HashSecret_Initialized = 1;
258258

259-
/*
260-
By default, hash randomization is disabled, and only
261-
enabled if PYTHONHASHSEED is set to non-empty or if
262-
"-R" is provided at the command line:
263-
*/
264-
if (!Py_HashRandomizationFlag) {
265-
/* Disable the randomized hash: */
266-
memset(secret, 0, secret_size);
267-
return;
268-
}
269-
270259
/*
271260
Hash randomization is enabled. Generate a per-process secret,
272261
using PYTHONHASHSEED if provided.

Tools/scripts/run_tests.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ def main(regrtest_args):
2525
'-W', 'default', # Warnings set to 'default'
2626
'-bb', # Warnings about bytes/bytearray
2727
'-E', # Ignore environment variables
28-
'-R', # Randomize hashing
2928
]
3029
# Allow user-specified interpreter options to override our defaults.
3130
args.extend(test.support.args_from_interpreter_flags())

0 commit comments

Comments
 (0)