Browse Source

python package update

Signed-off-by: basebuilder_pel7x64builder0 <basebuilder@powerel.org>
master
basebuilder_pel7x64builder0 6 years ago
parent
commit
066c8ccf11
  1. 940
      SOURCES/00055-systemtap.patch
  2. 46
      SOURCES/00111-no-static-lib.patch
  3. 54
      SOURCES/00132-add-rpmbuild-hooks-to-unittest.patch
  4. 12
      SOURCES/00137-skip-distutils-tests-that-fail-in-rpmbuild.patch
  5. 603
      SOURCES/00146-hashlib-fips.patch
  6. 12
      SOURCES/00155-avoid-ctypes-thunks.patch
  7. 105
      SOURCES/00157-uid-gid-overflows.patch
  8. 302
      SOURCES/00170-gc-assertions.patch
  9. 11
      SOURCES/00180-python-add-support-for-ppc64p7.patch
  10. 353
      SOURCES/00209-pep466-backport-hmac.compare_digest.patch
  11. 489
      SOURCES/00210-pep466-backport-hashlib.pbkdf2_hmac.patch
  12. 67
      SOURCES/00211-pep466-UTF-7-decoder-fix-illegal-unicode.patch
  13. 40
      SOURCES/00212-pep466-pyunicode_fromformat-raise-overflow.patch
  14. 176
      SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch
  15. 13082
      SOURCES/00214-pep466-backport-py3-ssl-changes.patch
  16. 26
      SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch
  17. 72
      SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch
  18. 189
      SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch
  19. 165
      SOURCES/00218-pep466-backport-urandom-pers-fd.patch
  20. 91
      SOURCES/00219-pep466-fix-referenced-sslwrap.patch
  21. 673
      SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch
  22. 49
      SOURCES/00222-add-2014-bit-dh-key.patch
  23. 153
      SOURCES/00223-pep476-verify-certs-by-default.patch
  24. 103
      SOURCES/00224-pep476-add-toggle-for-cert-verify.patch
  25. 25
      SOURCES/00225-cprofile-sort-option.patch
  26. 78
      SOURCES/00227-accept-none-keyfile-loadcertchain.patch
  27. 260
      SOURCES/00228-backport-ssl-version.patch
  28. 48
      SOURCES/00229-Expect-a-failure-when-trying-to-connect-with-SSLv2-c.patch
  29. 18
      SOURCES/00230-force-all-child-threads-to-terminate-in-TestForkInThread.patch
  30. 11
      SOURCES/00231-Initialize-OpenSSL_add_all_digests-in-_hashlib.patch
  31. 9
      SOURCES/00232-man-page-date-macro-removal.patch
  32. 2274
      SOURCES/00233-Computed-Goto-dispatch.patch
  33. 137
      SOURCES/00234-PEP493-updated-implementation.patch
  34. 226
      SOURCES/00235-JSON-decoder-lone-surrogates-fix.patch
  35. 101
      SOURCES/00236-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch
  36. 34
      SOURCES/00237-CVE-2016-0772-smtplib.patch
  37. 158
      SOURCES/00238-CVE-2016-5699-httplib.patch
  38. 66
      SOURCES/00240-increase-smtplib-tests-timeouts.patch
  39. 39
      SOURCES/00241-CVE-2016-5636-buffer-overflow-in-zipimport-module-fix.patch
  40. 121
      SOURCES/00242-CVE-2016-1000110-httpoxy.patch
  41. 235
      SOURCES/00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch
  42. 20
      SOURCES/00257-threading-wait-clamp-remaining-time.patch
  43. 14
      SOURCES/00263-fix-ssl-reference-leaks.patch
  44. 114
      SOURCES/00265-protect-key-list-during-fork.patch
  45. 376
      SOURCES/00266-fix-shutil.make_archive-ignoring-empty-dirs.patch
  46. 20
      SOURCES/00268-set-stream-name-to-None.patch
  47. 22
      SOURCES/00275-fix-fnctl-with-integer-on-big-endian.patch
  48. 22
      SOURCES/00276-increase-imaplib-MAXLINE.patch
  49. 91
      SOURCES/00281-add-context-parameter-to-xmlrpclib.ServerProxy.patch
  50. 157
      SOURCES/00282-obmalloc-mmap-threshold.patch
  51. 59
      SOURCES/00285-fix-non-deterministic-read-in-test_pty.patch
  52. 135
      SOURCES/00287-fix-thread-hanging-on-inaccessible-nfs-server.patch
  53. 250
      SOURCES/00295-fix-https-behind-proxy.patch
  54. 26
      SOURCES/00296-Readd-the-private-_set_hostport-api-to-httplib.patch
  55. 60
      SOURCES/00298-do-not-send-IP-in-SNI-TLS-extension.patch
  56. 24
      SOURCES/00299-fix-ssl-module-pymax.patch
  57. 86
      SOURCES/00303-CVE-2018-1060-1.patch
  58. 53
      SOURCES/00305-CVE-2016-2183.patch
  59. 44
      SOURCES/00306-fix-oserror-17-upon-semaphores-creation.patch
  60. 216
      SOURCES/05000-autotool-intermediates.patch
  61. 8
      SOURCES/cert-verification.cfg
  62. 73
      SOURCES/macros.python
  63. 37
      SOURCES/macros.python2
  64. 2
      SOURCES/pynche
  65. 11
      SOURCES/python-2.5-cflags.patch
  66. 12
      SOURCES/python-2.5.1-plural-fix.patch
  67. 24
      SOURCES/python-2.5.1-sqlite-encoding.patch
  68. 12
      SOURCES/python-2.6-rpath.patch
  69. 20
      SOURCES/python-2.6.4-distutils-rpath.patch
  70. 44
      SOURCES/python-2.7-lib64-sysconfig.patch
  71. 283
      SOURCES/python-2.7.1-config.patch
  72. 27
      SOURCES/python-2.7.1-fix_test_abc_with_COUNT_ALLOCS.patch
  73. 18
      SOURCES/python-2.7.2-add-extension-suffix-to-python-config.patch
  74. 292
      SOURCES/python-2.7.3-debug-build.patch
  75. 196
      SOURCES/python-2.7.3-lib64.patch
  76. 14
      SOURCES/python-2.7rc1-binutils-no-dep.patch
  77. 64
      SOURCES/python-2.7rc1-socketmodule-constants.patch
  78. 19
      SOURCES/python-2.7rc1-socketmodule-constants2.patch
  79. 1
      SOURCES/python.conf
  80. 32
      SOURCES/pythondeps.sh
  81. 4233
      SPECS/python.spec

940
SOURCES/00055-systemtap.patch

@ -1,822 +1,198 @@
diff -up Python-3.3.0rc2/configure.ac.systemtap Python-3.3.0rc2/configure.ac diff -up Python-2.7rc1/configure.ac.systemtap Python-2.7rc1/configure.ac
--- Python-3.3.0rc2/configure.ac.systemtap 2012-09-09 05:11:14.000000000 -0400 --- Python-2.7rc1/configure.ac.systemtap 2010-06-06 10:53:15.514975012 -0400
+++ Python-3.3.0rc2/configure.ac 2012-09-10 09:17:21.114511781 -0400 +++ Python-2.7rc1/configure.ac 2010-06-06 10:53:15.520974361 -0400
@@ -2678,6 +2678,23 @@ if test "$with_valgrind" != no; then @@ -2616,6 +2616,38 @@ if test "$with_valgrind" != no; then
OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" )
fi fi
+# Check for systemtap support +# Check for dtrace support
+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap +AC_MSG_CHECKING(for --with-dtrace)
+AC_MSG_CHECKING([for --with-systemtap]) +AC_ARG_WITH(dtrace,
+AC_ARG_WITH([systemtap], + AC_HELP_STRING(--with(out)-dtrace, disable/enable dtrace support))
+ AC_HELP_STRING([--with(out)-systemtap], [disable/enable SystemTap support]),, +
+ with_systemtap=no) +if test ! -z "$with_dtrace"
+AC_MSG_RESULT([$with_systemtap]) +then
+if test "$with_systemtap" != no; then + if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null
+ AC_DEFINE(WITH_SYSTEMTAP, 1, + then
+ [Define if you want to compile in SystemTap support]) + AC_DEFINE(WITH_DTRACE, 1,
+ SYSTEMTAPOBJS="Python/pysystemtap.o" + [Define if you want to compile in Dtrace support])
+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h" + with_dtrace="Sun"
+fi + DTRACEOBJS="Python/dtrace.o"
+ + DTRADEHDRS=""
+AC_SUBST(SYSTEMTAPOBJS) + elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d
+AC_SUBST(SYSTEMTAPDEPS) + then
+ + AC_DEFINE(WITH_DTRACE, 1,
# -I${DLINCLDIR} is added to the compile rule for importdl.o + [Define if you want to compile in Dtrace support])
AC_SUBST(DLINCLDIR) + with_dtrace="Apple"
DLINCLDIR=. + DTRACEOBJS=""
diff -up Python-3.3.0rc2/configure.systemtap Python-3.3.0rc2/configure + DTRADEHDRS="pydtrace.h"
--- Python-3.3.0rc2/configure.systemtap 2012-09-09 05:11:14.000000000 -0400 + else
+++ Python-3.3.0rc2/configure 2012-09-10 09:17:21.116511780 -0400 + with_dtrace="no"
@@ -618,6 +618,8 @@ TRUE + fi
MACHDEP_OBJS
DYNLOADFILE
DLINCLDIR
+SYSTEMTAPDEPS
+SYSTEMTAPOBJS
THREADOBJ
LDLAST
USE_THREAD_MODULE
@@ -779,6 +781,7 @@ with_doc_strings
with_tsc
with_pymalloc
with_valgrind
+with_systemtap
with_fpectl
with_libm
with_libc
@@ -1456,6 +1459,7 @@ Optional Packages:
--with(out)-tsc enable/disable timestamp counter profile
--with(out)-pymalloc disable/enable specialized mallocs
--with-valgrind Enable Valgrind support
+ --with(out)-systemtap disable/enable SystemTap support
--with-fpectl enable SIGFPE catching
--with-libm=STRING math library
--with-libc=STRING C library
@@ -10065,6 +10069,31 @@ fi
OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT"
fi
+# Check for systemtap support
+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-systemtap" >&5
+$as_echo_n "checking for --with-systemtap... " >&6; }
+
+# Check whether --with-systemtap was given.
+if test "${with_systemtap+set}" = set; then :
+ withval=$with_systemtap;
+else +else
+ with_systemtap=no + with_dtrace="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_systemtap" >&5
+$as_echo "$with_systemtap" >&6; }
+if test "$with_systemtap" != no; then
+
+$as_echo "#define WITH_SYSTEMTAP 1" >>confdefs.h
+
+ SYSTEMTAPOBJS="Python/pysystemtap.o"
+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h"
+fi +fi
+ +
+AC_MSG_RESULT($with_dtrace)
+AC_SUBST(DTRACEOBJS)
+AC_SUBST(DTRACEHDRS)
+
# Check for --with-wctype-functions
AC_MSG_CHECKING(for --with-wctype-functions)
AC_ARG_WITH(wctype-functions,
diff -up Python-2.7rc1/Include/pydtrace.d.systemtap Python-2.7rc1/Include/pydtrace.d
--- Python-2.7rc1/Include/pydtrace.d.systemtap 2010-06-06 10:53:15.520974361 -0400
+++ Python-2.7rc1/Include/pydtrace.d 2010-06-06 10:53:15.520974361 -0400
@@ -0,0 +1,10 @@
+provider python {
+ probe function__entry(const char *, const char *, int);
+ probe function__return(const char *, const char *, int);
+};
+ +
+ +#pragma D attributes Evolving/Evolving/Common provider python provider
+ +#pragma D attributes Private/Private/Common provider python module
# -I${DLINCLDIR} is added to the compile rule for importdl.o +#pragma D attributes Private/Private/Common provider python function
+#pragma D attributes Evolving/Evolving/Common provider python name
DLINCLDIR=. +#pragma D attributes Evolving/Evolving/Common provider python args
diff -up Python-3.3.0rc2/Doc/howto/index.rst.systemtap Python-3.3.0rc2/Doc/howto/index.rst diff -up Python-2.7rc1/Makefile.pre.in.systemtap Python-2.7rc1/Makefile.pre.in
--- Python-3.3.0rc2/Doc/howto/index.rst.systemtap 2012-09-09 05:10:51.000000000 -0400 --- Python-2.7rc1/Makefile.pre.in.systemtap 2010-06-06 10:53:15.488978775 -0400
+++ Python-3.3.0rc2/Doc/howto/index.rst 2012-09-10 09:17:21.117511779 -0400 +++ Python-2.7rc1/Makefile.pre.in 2010-06-06 11:05:30.411100568 -0400
@@ -29,4 +29,5 @@ Currently, the HOWTOs are: @@ -298,6 +298,7 @@ PYTHON_OBJS= \
argparse.rst
ipaddress.rst
clinic.rst
+ instrumentation.rst
diff -up Python-3.3.0rc2/Doc/howto/instrumentation.rst.systemtap Python-3.3.0rc2/Doc/howto/instrumentation.rst
--- Python-3.3.0rc2/Doc/howto/instrumentation.rst.systemtap 2012-09-10 09:17:21.117511779 -0400
+++ Python-3.3.0rc2/Doc/howto/instrumentation.rst 2012-09-10 09:17:21.117511779 -0400
@@ -0,0 +1,295 @@
+.. _instrumentation:
+
+====================================
+Instrumenting CPython with SystemTap
+====================================
+
+:author: David Malcolm <dmalcolm@redhat.com>
+
+DTrace and SystemTap are monitoring tools, each providing a way to inspect
+what the processes on a computer system are doing. They both use
+domain-specific languages allowing a user to write scripts which:
+
+ - filter which processes are to be observed
+ - gather data from the processes of interest
+ - generate reports on the data
+
+As of Python 3.3, CPython can be built with embedded "markers" that can be
+observed by a SystemTap script, making it easier to monitor what the CPython
+processes on a system are doing.
+
+.. Potentially this document could be expanded to also cover DTrace markers.
+ However, I'm not a DTrace expert.
+
+.. I'm using ".. code-block:: c" for SystemTap scripts, as "c" is syntactically
+ the closest match that Sphinx supports
+
+
+Enabling the static markers
+---------------------------
+
+In order to build CPython with the embedded markers for SystemTap, the
+SystemTap development tools must be installed.
+
+On a Fedora or Red Hat Enterprise Linux machine, this can be done via::
+
+ yum install systemtap-sdt-devel
+
+CPython must then be configured `--with-systemtap`::
+
+ checking for --with-systemtap... yes
+
+You can verify if the SystemTap static markers are present in the built
+binary by seeing if it contains a ".note.stapsdt" section.
+
+.. code-block:: bash
+
+ $ eu-readelf -S ./python | grep .note.stapsdt
+ [29] .note.stapsdt NOTE 0000000000000000 00308d78 000000b8 0 0 0 4
+
+If you've built python as a shared library (with --enable-shared), you need
+to look instead within the shared library. For example:
+
+.. code-block:: bash
+
+ $ eu-readelf -S libpython3.3dm.so.1.0 | grep .note.stapsdt
+ [28] .note.stapsdt NOTE 0000000000000000 00365b68 000000b8 0 0 0 4
+
+Earlier versions of SystemTap stored the markers in a ".probes" section.
+
+For the curious, you can see the metadata for the static markers using this
+invocation.
+
+.. code-block:: bash
+
+ $ eu-readelf -x .note.stapsdt ./python
+
+ Hex dump of section [29] '.note.stapsdt', 184 bytes at offset 0x308d78:
+ 0x00000000 08000000 45000000 03000000 73746170 ....E.......stap
+ 0x00000010 73647400 d4664b00 00000000 4fc36600 sdt..fK.....O.f.
+ 0x00000020 00000000 488d9000 00000000 70797468 ....H.......pyth
+ 0x00000030 6f6e0066 756e6374 696f6e5f 5f656e74 on.function__ent
+ 0x00000040 72790038 40257261 78203840 25726478 ry.8@%rax 8@%rdx
+ 0x00000050 202d3440 25656378 00000000 08000000 -4@%ecx........
+ 0x00000060 46000000 03000000 73746170 73647400 F.......stapsdt.
+ 0x00000070 0d674b00 00000000 4fc36600 00000000 .gK.....O.f.....
+ 0x00000080 4a8d9000 00000000 70797468 6f6e0066 J.......python.f
+ 0x00000090 756e6374 696f6e5f 5f726574 75726e00 unction__return.
+ 0x000000a0 38402572 61782038 40257264 78202d34 8@%rax 8@%rdx -4
+ 0x000000b0 40256563 78000000 @%ecx...
+
+and a sufficiently modern eu-readelf can print the metadata:
+
+.. code-block:: bash
+
+ $ eu-readelf -n ./python
+
+ Note section [ 1] '.note.gnu.build-id' of 36 bytes at offset 0x190:
+ Owner Data size Type
+ GNU 20 GNU_BUILD_ID
+ Build ID: a28f8db1b224530b0d38ad7b82a249cf7c3f18d6
+
+ Note section [27] '.note.stapsdt' of 184 bytes at offset 0x1ae884:
+ Owner Data size Type
+ stapsdt 70 Version: 3
+ PC: 0xe0d3a, Base: 0x14b150, Semaphore: 0x3ae882
+ Provider: python, Name: function__return, Args: '8@%rbx 8@%r13 -4@%eax'
+ stapsdt 69 Version: 3
+ PC: 0xe0f37, Base: 0x14b150, Semaphore: 0x3ae880
+ Provider: python, Name: function__entry, Args: '8@%rbx 8@%r13 -4@%eax'
+
+The above metadata contains information for SystemTap describing how it can
+patch strategically-placed machine code instructions to enable the tracing
+hooks used by a SystemTap script.
+
+
+Static markers
+--------------
+
+The low-level way to use the SystemTap integration is to use the static
+markers directly. This requires you to explicitly state the binary file
+containing them.
+
+For example, this script can be used to show the call/return hierarchy of a
+Python script:
+
+.. code-block:: c
+
+ probe process('python').mark("function__entry") {
+ filename = user_string($arg1);
+ funcname = user_string($arg2);
+ lineno = $arg3;
+
+ printf("%s => %s in %s:%d\\n",
+ thread_indent(1), funcname, filename, lineno);
+ }
+
+ probe process('python').mark("function__return") {
+ filename = user_string($arg1);
+ funcname = user_string($arg2);
+ lineno = $arg3;
+
+ printf("%s <= %s in %s:%d\\n",
+ thread_indent(-1), funcname, filename, lineno);
+ }
+
+It can be invoked like this:
+
+.. code-block:: bash
+
+ $ stap \
+ show-call-hierarchy.stp \
+ -c ./python test.py
+
+The output looks like this::
+
+ 11408 python(8274): => __contains__ in Lib/_abcoll.py:362
+ 11414 python(8274): => __getitem__ in Lib/os.py:425
+ 11418 python(8274): => encode in Lib/os.py:490
+ 11424 python(8274): <= encode in Lib/os.py:493
+ 11428 python(8274): <= __getitem__ in Lib/os.py:426
+ 11433 python(8274): <= __contains__ in Lib/_abcoll.py:366
+
+where the columns are:
+
+ - time in microseconds since start of script
+
+ - name of executable
+
+ - PID of process
+
+and the remainder indicates the call/return hierarchy as the script executes.
+
+For a `--enable-shared` build of CPython, the markers are contained within the
+libpython shared library, and the probe's dotted path needs to reflect this. For
+example, this line from the above example::
+
+ probe process('python').mark("function__entry") {
+
+should instead read::
+
+ probe process('python').library("libpython3.3dm.so.1.0").mark("function__entry") {
+
+(assuming a debug build of CPython 3.3)
+
+.. I'm reusing the "c:function" type for markers
+
+.. c:function:: function__entry(str filename, str funcname, int lineno)
+
+ This marker indicates that execution of a Python function has begun. It is
+ only triggered for pure-python (bytecode) functions.
+
+ The filename, function name, and line number are provided back to the
+ tracing script as positional arguments, which must be accessed using
+ `$arg1`, `$arg2`:
+
+ * `$arg1` : `(const char *)` filename, accessible using `user_string($arg1)`
+
+ * `$arg2` : `(const char *)` function name, accessible using
+ `user_string($arg2)`
+
+ * `$arg3` : `int` line number
+
+ * `$arg4` : `(PyFrameObject *)`, the frame being executed
+
+.. c:function:: function__return(str filename, str funcname, int lineno)
+
+ This marker is the converse of `function__entry`, and indicates that
+ execution of a Python function has ended (either via ``return``, or via an
+ exception). It is only triggered for pure-python (bytecode) functions.
+
+ The arguments are the same as for `function__entry`
+
+
+Tapsets
+-------
+
+The higher-level way to use the SystemTap integration is to use a "tapset":
+SystemTap's equivalent of a library, which hides some of the lower-level
+details of the static markers.
+
+Here is a tapset file, based on a non-shared build of CPython:
+
+.. code-block:: c
+
+ /*
+ Provide a higher-level wrapping around the function__entry and
+ function__return markers:
+ */
+ probe python.function.entry = process("python").mark("function__entry")
+ {
+ filename = user_string($arg1);
+ funcname = user_string($arg2);
+ lineno = $arg3;
+ frameptr = $arg4
+ }
+ probe python.function.return = process("python").mark("function__return")
+ {
+ filename = user_string($arg1);
+ funcname = user_string($arg2);
+ lineno = $arg3;
+ frameptr = $arg4
+ }
+
+If this file is installed in SystemTap's tapset directory (e.g.
+`/usr/share/systemtap/tapset`), then these additional probepoints become
+available:
+
+.. c:function:: python.function.entry(str filename, str funcname, int lineno, frameptr)
+
+ This probe point indicates that execution of a Python function has begun.
+ It is only triggered for pure-python (bytecode) functions.
+
+.. c:function:: python.function.return(str filename, str funcname, int lineno, frameptr)
+
+ This probe point is the converse of `python.function.return`, and indicates
+ that execution of a Python function has ended (either via ``return``, or
+ via an exception). It is only triggered for pure-python (bytecode) functions.
+
+
+Examples
+--------
+This SystemTap script uses the tapset above to more cleanly implement the
+example given above of tracing the Python function-call hierarchy, without
+needing to directly name the static markers:
+
+.. code-block:: c
+
+ probe python.function.entry
+ {
+ printf("%s => %s in %s:%d\n",
+ thread_indent(1), funcname, filename, lineno);
+ }
+
+ probe python.function.return
+ {
+ printf("%s <= %s in %s:%d\n",
+ thread_indent(-1), funcname, filename, lineno);
+ }
+
+
+The following script uses the tapset above to provide a top-like view of all
+running CPython code, showing the top 20 most frequently-entered bytecode
+frames, each second, across the whole system:
+
+.. code-block:: c
+
+ global fn_calls;
+
+ probe python.function.entry
+ {
+ fn_calls[pid(), filename, funcname, lineno] += 1;
+ }
+
+ probe timer.ms(1000) {
+ printf("\033[2J\033[1;1H") /* clear screen */
+ printf("%6s %80s %6s %30s %6s\n",
+ "PID", "FILENAME", "LINE", "FUNCTION", "CALLS")
+ foreach ([pid, filename, funcname, lineno] in fn_calls- limit 20) {
+ printf("%6d %80s %6d %30s %6d\n",
+ pid, filename, lineno, funcname,
+ fn_calls[pid, filename, funcname, lineno]);
+ }
+ delete fn_calls;
+ }
+
diff -up Python-3.3.0rc2/Lib/test/test_systemtap.py.systemtap Python-3.3.0rc2/Lib/test/test_systemtap.py
--- Python-3.3.0rc2/Lib/test/test_systemtap.py.systemtap 2012-09-10 09:17:21.117511779 -0400
+++ Python-3.3.0rc2/Lib/test/test_systemtap.py 2012-09-10 09:17:21.117511779 -0400
@@ -0,0 +1,234 @@
+# Verify that systemtap static probes work
+#
+import subprocess
+import sys
+import sysconfig
+import os
+import unittest
+
+from test.support import run_unittest, TESTFN, unlink
+
+if '--with-systemtap' not in sysconfig.get_config_var('CONFIG_ARGS'):
+ raise unittest.SkipTest("Python was not configured --with-systemtap")
+
+try:
+ _, stap_version = subprocess.Popen(["stap", "-V"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ ).communicate()
+except OSError:
+ # This is what "no stap" looks like. There may, however, be other
+ # errors that manifest this way too.
+ raise unittest.SkipTest("Couldn't find stap on the path")
+
+def invoke_systemtap_script(script, cmd):
+ # Start a child process, probing with the given systemtap script
+ # (passed as stdin to the "stap" tool)
+ # The script should be a bytes instance
+ # Return (stdout, stderr) pair
+
+ p = subprocess.Popen(["stap", "-", '-vv', '-c', cmd],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, err = p.communicate(input=script)
+ return out, err
+
+# Verify that stap can run a simple "hello world"-style script
+# This can fail for various reasons:
+# - missing kernel headers
+# - permissions (a non-root user needs to be in the "stapdev" group)
+TRIVIAL_STAP_SCRIPT = b'probe begin { println("hello world") exit () }'
+
+out, err = invoke_systemtap_script(TRIVIAL_STAP_SCRIPT, 'true')
+if out != b'hello world\n':
+ raise unittest.SkipTest("Test systemtap script did not run; stderr was: %s" % err)
+
+# We don't expect stderr to be empty, since we're invoking stap with "-vv": stap
+# will (we hope) generate debugging output on stderr.
+
+def invoke_python_under_systemtap(script, pythoncode=None, pythonfile=None):
+ # Start a child python process, probing with the given systemtap script
+ # (passed as stdin to the "stap" tool)
+ # The script should be a bytes instance
+ # Return (stdout, stderr) pair
+
+ if pythonfile:
+ pythoncmd = '%s %s' % (sys.executable, pythonfile)
+ else:
+ pythoncmd = '%s -c %r' % (sys.executable, pythoncode)
+
+ # The process tree of a stap invocation of a command goes through
+ # something like this:
+ # stap ->fork/exec(staprun; exec stapio ->f/e(-c cmd); exec staprun -r)
+ # and this trip through setuid leads to LD_LIBRARY_PATH being dropped,
+ # which would lead to an --enable-shared build of python failing to be
+ # find its libpython, with an error like:
+ # error while loading shared libraries: libpython3.3dm.so.1.0: cannot
+ # open shared object file: No such file or directory
+ # Hence we need to jump through some hoops to expose LD_LIBRARY_PATH to
+ # the invoked python process:
+ LD_LIBRARY_PATH = os.environ.get('LD_LIBRARY_PATH', '')
+ if LD_LIBRARY_PATH:
+ pythoncmd = 'env LD_LIBRARY_PATH=%s ' % LD_LIBRARY_PATH + pythoncmd
+
+ return invoke_systemtap_script(script, pythoncmd)
+
+# When using the static markers, we need to supply the prefix of a systemtap
+# dotted probe point that containing the marker.
+# See http://sourceware.org/systemtap/langref/Probe_points.html
+#
+# We need to determine if this is a shared-library build
+#
+# Note that sysconfig can get this wrong; see:
+# http://bugs.python.org/issue14774
+#
+if '--enable-shared' in sysconfig.get_config_var('CONFIG_ARGS'):
+ # For a shared-library build, the markers are in library(INSTSONAME):
+ INSTSONAME = sysconfig.get_config_var('INSTSONAME')
+ probe_prefix = 'process("%s").library("%s")' % (sys.executable, INSTSONAME)
+else:
+ # For a non-shared-library build, we can simply use sys.executable:
+ probe_prefix = 'process("%s")' % sys.executable
+
+# The following script ought to generate lots of lines showing recursive
+# function entry and return, of the form:
+# 11408 python(8274): => __contains__ in Lib/_abcoll.py:362
+# 11414 python(8274): => __getitem__ in Lib/os.py:425
+# 11418 python(8274): => encode in Lib/os.py:490
+# 11424 python(8274): <= encode in Lib/os.py:493
+# 11428 python(8274): <= __getitem__ in Lib/os.py:426
+# 11433 python(8274): <= __contains__ in Lib/_abcoll.py:366
+# where the column are:
+# - time in microseconds since start of script
+# - name of executable
+# - PID of process
+# and the remainder indicates the call/return hierarchy
+
+hierarchy_script = ('''
+probe %s.mark("function__entry") {
+ filename = user_string($arg1);
+ funcname = user_string($arg2);
+ lineno = $arg3;
+
+ printf("%%s => %%s in %%s:%%d\\n", thread_indent(1), funcname, filename, lineno);
+}
+
+probe %s.mark("function__return") {
+ filename = user_string($arg1);
+ funcname = user_string($arg2);
+ lineno = $arg3;
+
+ printf("%%s <= %%s in %%s:%%d\\n", thread_indent(-1), funcname, filename, lineno);
+}
+''' % (probe_prefix, probe_prefix)).encode('utf-8')
+
+
+class ErrorDumper:
+ # A context manager that dumps extra information if an exception is raised,
+ # to help track down why the problem occurred
+ def __init__(self, out, err):
+ self.out = out
+ self.err = err
+
+ def __enter__(self):
+ pass
+
+ def __exit__(self, type_, value, traceback):
+ if type_:
+ # an exception is being raised:
+ print('stdout: %s' % out.decode())
+ print('stderr: %s' % err.decode())
+
+class SystemtapTests(unittest.TestCase):
+
+ def test_invoking_python(self):
+ # Ensure that we can invoke python under stap, with a trivial stap
+ # script:
+ out, err = invoke_python_under_systemtap(
+ b'probe begin { println("hello from stap") exit () }',
+ pythoncode="print('hello from python')")
+ with ErrorDumper(out, err):
+ self.assertIn(b'hello from stap', out)
+ self.assertIn(b'hello from python', out)
+
+ def test_function_entry(self):
+ # Ensure that the function_entry static marker works
+ out, err = invoke_python_under_systemtap(hierarchy_script)
+ # stdout ought to contain various lines showing recursive function
+ # entry and return (see above)
+
+ # Uncomment this for debugging purposes:
+ # print(out.decode('utf-8'))
+
+ # Executing the cmdline-supplied "pass":
+ # 0 python(8274): => <module> in <string>:1
+ # 5 python(8274): <= <module> in <string>:1
+ with ErrorDumper(out, err):
+ self.assertIn(b'=> <module> in <string>:1', out,
+ msg="stdout: %s\nstderr: %s\n" % (out, err))
+
+ def test_function_encoding(self):
+ # Ensure that function names containing non-Latin 1 code
+ # points are handled:
+ pythonfile = TESTFN
+ try:
+ unlink(pythonfile)
+ f = open(pythonfile, "wb")
+ f.write("""
+# Sample script with non-ASCII filename, for use by test_systemtap.py
+# Implicitly UTF-8
+
+def 文字化け():
+ '''Function with non-ASCII identifier; I believe this reads "mojibake"'''
+ print("hello world!")
+
+文字化け()
+""".encode('utf-8'))
+ f.close()
+
+ out, err = invoke_python_under_systemtap(hierarchy_script,
+ pythonfile=pythonfile)
+ out_utf8 = out.decode('utf-8')
+ with ErrorDumper(out, err):
+ self.assertIn('=> <module> in %s:5' % pythonfile, out_utf8)
+ self.assertIn(' => 文字化け in %s:5' % pythonfile, out_utf8)
+ self.assertIn(' <= 文字化け in %s:7' % pythonfile, out_utf8)
+ self.assertIn('<= <module> in %s:9' % pythonfile, out_utf8)
+ finally:
+ unlink(pythonfile)
+
+ @unittest.skipIf(sys.getfilesystemencoding() == 'ascii',
+ 'the test filename is not encodable with ASCII')
+ def test_filename_encoding(self):
+ # Ensure that scripts names containing non-Latin 1 code
+ # points are handled:
+ pythonfile = TESTFN + '_☠.py'
+ try:
+ unlink(pythonfile)
+ f = open(pythonfile, "wb")
+ f.write("""
+def foo():
+ '''Function with non-ASCII identifier; I believe this reads "mojibake"'''
+ print("hello world!")
+
+foo()
+""".encode('utf-8'))
+ f.close()
+
+ out, err = invoke_python_under_systemtap(hierarchy_script,
+ pythonfile=pythonfile)
+ out_utf8 = out.decode('utf-8')
+ with ErrorDumper(out, err):
+ self.assertIn('=> <module> in %s:2' % pythonfile, out_utf8)
+ self.assertIn(' => foo in %s:2' % pythonfile, out_utf8)
+ self.assertIn(' <= foo in %s:4' % pythonfile, out_utf8)
+ self.assertIn('<= <module> in %s:6' % pythonfile, out_utf8)
+ finally:
+ unlink(pythonfile)
+
+def test_main():
+ run_unittest(SystemtapTests)
+
+if __name__ == "__main__":
+ test_main()
diff -up Python-3.3.0rc2/Makefile.pre.in.systemtap Python-3.3.0rc2/Makefile.pre.in
--- Python-3.3.0rc2/Makefile.pre.in.systemtap 2012-09-09 05:11:05.000000000 -0400
+++ Python-3.3.0rc2/Makefile.pre.in 2012-09-10 09:19:51.195501518 -0400
@@ -363,6 +363,7 @@ PYTHON_OBJS= \
Python/formatter_unicode.o \ Python/formatter_unicode.o \
Python/fileutils.o \ Python/formatter_string.o \
Python/$(DYNLOADFILE) \ Python/$(DYNLOADFILE) \
+ @SYSTEMTAPOBJS@ \ + @DTRACEOBJS@ \
$(LIBOBJS) \ $(LIBOBJS) \
$(MACHDEP_OBJS) \ $(MACHDEP_OBJS) \
$(THREADOBJ) $(THREADOBJ)
@@ -713,7 +714,8 @@ Objects/setobject.o: $(srcdir)/Objects/s @@ -599,6 +600,18 @@ Python/formatter_unicode.o: $(srcdir)/Py
$(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES) Python/formatter_string.o: $(srcdir)/Python/formatter_string.c \
$(OPCODETARGETGEN) $(OPCODETARGETS_H) $(STRINGLIB_HEADERS)
-Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h
+Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h \
+ $(srcdir)/Python/ceval_systemtap.h @SYSTEMTAPDEPS@
Python/frozen.o: Python/importlib.h Python/importlib_external.h +# Only needed with --with-dtrace
+buildinclude:
@@ -724,6 +726,13 @@ Objects/typeobject.o: $(srcdir)/Objects/ + mkdir -p Include
Objects/typeslots.inc: $(srcdir)/Include/typeslots.h $(srcdir)/Objects/typeslots.py +
$(PYTHON) $(srcdir)/Objects/typeslots.py < $(srcdir)/Include/typeslots.h > Objects/typeslots.inc +Include/pydtrace.h: buildinclude $(srcdir)/Include/pydtrace.d
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Include/pydtrace.d
+# Only needed with --with-systemtap; not a public header: +
+$(srcdir)/Python/pysystemtap.h: $(srcdir)/Python/pysystemtap.d +Python/ceval.o: Include/pydtrace.h
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Python/pysystemtap.d
+ +
+Python/pysystemtap.o: $(srcdir)/Python/pysystemtap.d Python/ceval.o +Python/dtrace.o: buildinclude $(srcdir)/Include/pydtrace.d Python/ceval.o
+ dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Python/pysystemtap.d Python/ceval.o + dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Include/pydtrace.d Python/ceval.o
+ +
############################################################################ ############################################################################
# Header files # Header files
@@ -1345,6 +1354,7 @@ clean: pycremoval @@ -1251,7 +1264,7 @@ Python/thread.o: @THREADHEADERS@
-rm -f Lib/lib2to3/*Grammar*.pickle .PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure
-rm -f Programs/_testembed Programs/_freeze_importlib .PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools
-rm -rf build .PHONY: frameworkaltinstallunixtools recheck autoconf clean clobber distclean
+ -rm -f $(srcdir)/Python/pysystemtap.h -.PHONY: smelly funny patchcheck touch altmaninstall
+.PHONY: smelly funny patchcheck touch altmaninstall buildinclude
profile-removal: .PHONY: gdbhooks
find . -name '*.gc??' -exec rm -f {} ';'
diff -up Python-3.3.0rc2/pyconfig.h.in.systemtap Python-3.3.0rc2/pyconfig.h.in # IF YOU PUT ANYTHING HERE IT WILL GO AWAY
--- Python-3.3.0rc2/pyconfig.h.in.systemtap 2012-09-09 05:11:14.000000000 -0400 diff -up Python-2.7rc1/pyconfig.h.in.systemtap Python-2.7rc1/pyconfig.h.in
+++ Python-3.3.0rc2/pyconfig.h.in 2012-09-10 09:17:21.120511781 -0400 --- Python-2.7rc1/pyconfig.h.in.systemtap 2010-05-08 07:04:18.000000000 -0400
@@ -1306,6 +1306,9 @@ +++ Python-2.7rc1/pyconfig.h.in 2010-06-06 10:53:15.521974070 -0400
/* Define if you want to compile in Python-specific mallocs */ @@ -1074,6 +1074,9 @@
#undef WITH_PYMALLOC /* Define if you want documentation strings in extension modules */
#undef WITH_DOC_STRINGS
+/* Define if you want to compile in SystemTap support */
+#undef WITH_SYSTEMTAP +/* Define if you want to compile in Dtrace support */
+ +#undef WITH_DTRACE
/* Define if you want to compile in rudimentary thread support */ +
#undef WITH_THREAD /* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic
linker (dyld) instead of the old-style (NextStep) dynamic linker (rld).
diff -up Python-3.3.0rc2/Python/ceval.c.systemtap Python-3.3.0rc2/Python/ceval.c Dyld is necessary to support frameworks. */
--- Python-3.3.0rc2/Python/ceval.c.systemtap 2012-09-09 05:11:12.000000000 -0400 diff -up Python-2.7rc1/Python/ceval.c.systemtap Python-2.7rc1/Python/ceval.c
+++ Python-3.3.0rc2/Python/ceval.c 2012-09-10 09:17:21.122511781 -0400 --- Python-2.7rc1/Python/ceval.c.systemtap 2010-05-09 10:46:46.000000000 -0400
@@ -18,6 +18,8 @@ +++ Python-2.7rc1/Python/ceval.c 2010-06-06 11:08:40.683100500 -0400
@@ -19,6 +19,10 @@
#include <ctype.h> #include <ctype.h>
+#include "ceval_systemtap.h" +#ifdef WITH_DTRACE
+#include "pydtrace.h"
+#endif
+ +
#ifndef WITH_TSC #ifndef WITH_TSC
#define READ_TIMESTAMP(var) #define READ_TIMESTAMP(var)
@@ -1160,6 +1162,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int @@ -671,6 +675,55 @@ PyEval_EvalCode(PyCodeObject *co, PyObje
} NULL);
} }
+ if (PYTHON_FUNCTION_ENTRY_ENABLED()) {
+ systemtap_function_entry(f);
+ }
+
co = f->f_code;
names = co->co_names;
consts = co->co_consts;
@@ -3077,6 +3083,11 @@ fast_yield:
/* pop frame */ +#ifdef WITH_DTRACE
exit_eval_frame: +static void
+ +dtrace_entry(PyFrameObject *f)
+ if (PYTHON_FUNCTION_RETURN_ENABLED()) {
+ systemtap_function_return(f);
+ }
+
Py_LeaveRecursiveCall();
f->f_executing = 0;
tstate->frame = f->f_back;
diff -up Python-3.3.0rc2/Python/ceval_systemtap.h.systemtap Python-3.3.0rc2/Python/ceval_systemtap.h
--- Python-3.3.0rc2/Python/ceval_systemtap.h.systemtap 2012-09-10 09:17:21.122511781 -0400
+++ Python-3.3.0rc2/Python/ceval_systemtap.h 2012-09-10 09:17:21.122511781 -0400
@@ -0,0 +1,86 @@
+/*
+ Support for SystemTap static markers
+*/
+
+#ifdef WITH_SYSTEMTAP
+
+#include "pysystemtap.h"
+
+/*
+ A struct to hold all of the information gathered when one of the traceable
+ markers is triggered
+*/
+struct frame_marker_info
+{ +{
+ PyObject *filename_obj;
+ PyObject *funcname_obj;
+ const char *filename; + const char *filename;
+ const char *funcname; + const char *fname;
+ int lineno; + int lineno;
+};
+ +
+static void + filename = PyString_AsString(f->f_code->co_filename);
+get_frame_marker_info(PyFrameObject *f, struct frame_marker_info *fmi) + fname = PyString_AsString(f->f_code->co_name);
+{ + lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+ PyObject *ptype;
+ PyObject *pvalue;
+ PyObject *ptraceback;
+
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+
+ fmi->filename_obj = PyUnicode_EncodeFSDefault(f->f_code->co_filename);
+ if (fmi->filename_obj) {
+ fmi->filename = PyBytes_AsString(fmi->filename_obj);
+ } else {
+ fmi->filename = NULL;
+ }
+ +
+ fmi->funcname_obj = PyUnicode_AsUTF8String(f->f_code->co_name); + PYTHON_FUNCTION_ENTRY((char *)filename, (char *)fname, lineno);
+ if (fmi->funcname_obj) {
+ fmi->funcname = PyBytes_AsString(fmi->funcname_obj);
+ } else {
+ fmi->funcname = NULL;
+ }
+
+ fmi->lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+ PyErr_Restore(ptype, pvalue, ptraceback);
+ +
+ /*
+ * Currently a USDT tail-call will not receive the correct arguments.
+ * Disable the tail call here.
+ */
+#if defined(__sparc)
+ asm("nop");
+#endif
+} +}
+ +
+static void +static void
+release_frame_marker_info(struct frame_marker_info *fmi) +dtrace_return(PyFrameObject *f)
+{ +{
+ Py_XDECREF(fmi->filename_obj); + const char *filename;
+ Py_XDECREF(fmi->funcname_obj); + const char *fname;
+} + int lineno;
+ +
+static void + filename = PyString_AsString(f->f_code->co_filename);
+systemtap_function_entry(PyFrameObject *f) + fname = PyString_AsString(f->f_code->co_name);
+{ + lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+ struct frame_marker_info fmi; + PYTHON_FUNCTION_RETURN((char *)filename, (char *)fname, lineno);
+ get_frame_marker_info(f, &fmi);
+ PYTHON_FUNCTION_ENTRY(fmi.filename, fmi.funcname, fmi.lineno, f);
+ release_frame_marker_info(&fmi);
+}
+ +
+static void + /*
+systemtap_function_return(PyFrameObject *f) + * Currently a USDT tail-call will not receive the correct arguments.
+{ + * Disable the tail call here.
+ struct frame_marker_info fmi; + */
+ get_frame_marker_info(f, &fmi); +#if defined(__sparc)
+ PYTHON_FUNCTION_RETURN(fmi.filename, fmi.funcname, fmi.lineno, f); + asm("nop");
+ release_frame_marker_info(&fmi); +#endif
+} +}
+#else
+#define PYTHON_FUNCTION_ENTRY_ENABLED() 0
+#define PYTHON_FUNCTION_RETURN_ENABLED() 0
+#define dtrace_entry(f)
+#define dtrace_return(f)
+#endif
/* Interpreter main loop */
@@ -909,6 +962,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int
}
}
+ if (PYTHON_FUNCTION_ENTRY_ENABLED())
+ dtrace_entry(f);
+ +
+#else /* #ifdef WITH_SYSTEMTAP */ co = f->f_code;
+ names = co->co_names;
+/* consts = co->co_consts;
+ When configured --without-systemtap, everything compiles away to nothing: @@ -3000,6 +3056,9 @@ fast_yield:
+*/
+#define PYTHON_FUNCTION_ENTRY_ENABLED() 0 /* pop frame */
+#define PYTHON_FUNCTION_RETURN_ENABLED() 0 exit_eval_frame:
+#define systemtap_function_entry(f) + if (PYTHON_FUNCTION_RETURN_ENABLED())
+#define systemtap_function_return(f) + dtrace_return(f);
+ +
+#endif Py_LeaveRecursiveCall();
diff -up Python-3.3.0rc2/Python/pysystemtap.d.systemtap Python-3.3.0rc2/Python/pysystemtap.d tstate->frame = f->f_back;
--- Python-3.3.0rc2/Python/pysystemtap.d.systemtap 2012-09-10 09:17:21.122511781 -0400
+++ Python-3.3.0rc2/Python/pysystemtap.d 2012-09-10 09:17:21.122511781 -0400
@@ -0,0 +1,4 @@
+provider python {
+ probe function__entry(const char *, const char *, int, PyFrameObject *);
+ probe function__return(const char *, const char *, int, PyFrameObject *);
+};

46
SOURCES/00111-no-static-lib.patch

@ -1,20 +1,19 @@
diff --git a/Makefile.pre.in b/Makefile.pre.in diff -up Python-2.7.3/Makefile.pre.in.no-static-lib Python-2.7.3/Makefile.pre.in
index 4b093e3..1088435 100644 --- Python-2.7.3/Makefile.pre.in.no-static-lib 2013-02-19 14:03:40.801993224 -0500
--- a/Makefile.pre.in +++ Python-2.7.3/Makefile.pre.in 2013-02-19 14:04:44.070988898 -0500
+++ b/Makefile.pre.in @@ -397,7 +397,7 @@ coverage:
@@ -543,7 +543,7 @@ clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c
$(PYTHON_FOR_REGEN) ./Tools/clinic/clinic.py --make
# Build the interpreter
-$(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
+$(BUILDPYTHON): Programs/python.o $(LDLIBRARY) $(PY3LIBRARY)
$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
platform: $(BUILDPYTHON) pybuilddir.txt # Build the interpreter
@@ -588,18 +588,6 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o -$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY)
+$(BUILDPYTHON): Modules/python.o $(LDLIBRARY)
$(LINKCC) $(CFLAGS) $(LDFLAGS) $(LINKFORSHARED) -o $@ \
Modules/python.o \
$(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
@@ -413,18 +413,6 @@ sharedmods: $(BUILDPYTHON)
$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build $(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
-# Build static library -# Build static library
-# avoid long command lines, same as LIBRARY_OBJS -# avoid long command lines, same as LIBRARY_OBJS
-$(LIBRARY): $(LIBRARY_OBJS) -$(LIBRARY): $(LIBRARY_OBJS)
@ -22,30 +21,21 @@ index 4b093e3..1088435 100644
- $(AR) $(ARFLAGS) $@ Modules/getbuildinfo.o - $(AR) $(ARFLAGS) $@ Modules/getbuildinfo.o
- $(AR) $(ARFLAGS) $@ $(PARSER_OBJS) - $(AR) $(ARFLAGS) $@ $(PARSER_OBJS)
- $(AR) $(ARFLAGS) $@ $(OBJECT_OBJS) - $(AR) $(ARFLAGS) $@ $(OBJECT_OBJS)
- $(AR) $(ARFLAGS) $@ $(PYTHON_OBJS) Python/frozen.o - $(AR) $(ARFLAGS) $@ $(PYTHON_OBJS)
- $(AR) $(ARFLAGS) $@ $(MODULE_OBJS) - $(AR) $(ARFLAGS) $@ $(MODULE_OBJS) $(SIGNAL_OBJS)
- $(AR) $(ARFLAGS) $@ $(MODOBJS) - $(AR) $(ARFLAGS) $@ $(MODOBJS)
- $(RANLIB) $@ - $(RANLIB) $@
- -
libpython$(LDVERSION).so: $(LIBRARY_OBJS) libpython$(VERSION).so: $(LIBRARY_OBJS)
if test $(INSTSONAME) != $(LDLIBRARY); then \ if test $(INSTSONAME) != $(LDLIBRARY); then \
$(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ $(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
@@ -689,7 +677,7 @@ Modules/Setup: $(srcdir)/Modules/Setup.dist @@ -1021,18 +1009,6 @@ libainstall: all python-config
echo "-----------------------------------------------"; \
fi
-Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
+Programs/_testembed: Programs/_testembed.o $(LDLIBRARY) $(PY3LIBRARY)
$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)
############################################################################
@@ -1425,18 +1413,6 @@ libainstall: @DEF_MAKE_RULE@ python-config
else true; \ else true; \
fi; \ fi; \
done done
- @if test -d $(LIBRARY); then :; else \ - @if test -d $(LIBRARY); then :; else \
- if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \ - if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \
- if test "$(SHLIB_SUFFIX)" = .dll; then \ - if test "$(SO)" = .dll; then \
- $(INSTALL_DATA) $(LDLIBRARY) $(DESTDIR)$(LIBPL) ; \ - $(INSTALL_DATA) $(LDLIBRARY) $(DESTDIR)$(LIBPL) ; \
- else \ - else \
- $(INSTALL_DATA) $(LIBRARY) $(DESTDIR)$(LIBPL)/$(LIBRARY) ; \ - $(INSTALL_DATA) $(LIBRARY) $(DESTDIR)$(LIBPL)/$(LIBRARY) ; \
@ -56,5 +46,5 @@ index 4b093e3..1088435 100644
- fi; \ - fi; \
- fi - fi
$(INSTALL_DATA) Modules/config.c $(DESTDIR)$(LIBPL)/config.c $(INSTALL_DATA) Modules/config.c $(DESTDIR)$(LIBPL)/config.c
$(INSTALL_DATA) Programs/python.o $(DESTDIR)$(LIBPL)/python.o $(INSTALL_DATA) Modules/python.o $(DESTDIR)$(LIBPL)/python.o
$(INSTALL_DATA) $(srcdir)/Modules/config.c.in $(DESTDIR)$(LIBPL)/config.c.in $(INSTALL_DATA) $(srcdir)/Modules/config.c.in $(DESTDIR)$(LIBPL)/config.c.in

54
SOURCES/00132-add-rpmbuild-hooks-to-unittest.patch

@ -1,16 +1,17 @@
diff -up Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python-3.2.2/Lib/unittest/case.py diff -up Python-2.7.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python-2.7.2/Lib/unittest/case.py
--- Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest 2011-09-03 12:16:44.000000000 -0400 --- Python-2.7.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest 2011-09-08 14:45:47.677169191 -0400
+++ Python-3.2.2/Lib/unittest/case.py 2011-09-09 06:35:16.365568382 -0400 +++ Python-2.7.2/Lib/unittest/case.py 2011-09-08 16:01:36.287858159 -0400
@@ -3,6 +3,7 @@ @@ -1,6 +1,7 @@
"""Test case implementation"""
import collections
+import os
import sys import sys
import functools import functools
import difflib import difflib
+import os @@ -94,6 +95,43 @@ def expectedFailure(func):
import logging return wrapper
import pprint
import re
@@ -101,5 +102,21 @@ def expectedFailure(func):
raise self.test_case.failureException(msg)
+# Non-standard/downstream-only hooks for handling issues with specific test +# Non-standard/downstream-only hooks for handling issues with specific test
+# cases: +# cases:
@ -28,19 +29,40 @@ diff -up Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python
+ else: + else:
+ return _id + return _id
+ +
class _AssertRaisesBaseContext(_BaseTestCaseContext): +def _expectedFailureInRpmBuild(func):
+ """
+ Non-standard/downstream-only decorator for marking a specific unit test
+ as expected to fail within the %check of an rpmbuild.
+
+ Specifically, this takes effect when WITHIN_PYTHON_RPM_BUILD is set within
+ the environment, and has no effect otherwise.
+ """
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ if 'WITHIN_PYTHON_RPM_BUILD' in os.environ:
+ try:
+ func(*args, **kwargs)
+ except Exception:
+ raise _ExpectedFailure(sys.exc_info())
+ raise _UnexpectedSuccess
+ else:
+ # Call directly:
+ func(*args, **kwargs)
+ return wrapper
+
class _AssertRaisesContext(object):
"""A context manager used to implement TestCase.assertRaises* methods."""
def __init__(self, expected, test_case, expected_regex=None): diff -up Python-2.7.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest Python-2.7.2/Lib/unittest/__init__.py
diff -up Python-3.2.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest Python-3.2.2/Lib/unittest/__init__.py --- Python-2.7.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest 2011-09-08 14:59:39.534112310 -0400
--- Python-3.2.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest 2011-09-03 12:16:44.000000000 -0400 +++ Python-2.7.2/Lib/unittest/__init__.py 2011-09-08 15:07:09.191081562 -0400
+++ Python-3.2.2/Lib/unittest/__init__.py 2011-09-09 06:35:16.366568382 -0400
@@ -57,7 +57,8 @@ __unittest = True @@ -57,7 +57,8 @@ __unittest = True
from .result import TestResult from .result import TestResult
from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf, from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
- skipUnless, expectedFailure) - skipUnless, expectedFailure)
+ skipUnless, expectedFailure, + skipUnless, expectedFailure,
+ _skipInRpmBuild) + _skipInRpmBuild, _expectedFailureInRpmBuild)
from .suite import BaseTestSuite, TestSuite from .suite import BaseTestSuite, TestSuite
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames, from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
findTestCases) findTestCases)

12
SOURCES/00137-skip-distutils-tests-that-fail-in-rpmbuild.patch

@ -1,12 +1,12 @@
diff -up Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py.skip-distutils-tests-that-fail-in-rpmbuild Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py diff -up Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py.mark-tests-that-fail-in-rpmbuild Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py
--- Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py.skip-distutils-tests-that-fail-in-rpmbuild 2011-09-03 12:16:40.000000000 -0400 --- Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py.mark-tests-that-fail-in-rpmbuild 2012-04-09 19:07:29.000000000 -0400
+++ Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py 2011-09-10 05:04:56.328852558 -0400 +++ Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py 2012-04-13 00:20:08.223819263 -0400
@@ -23,6 +23,7 @@ setup(name='foo', version='0.1', py_modu @@ -24,6 +24,7 @@ setup(name='foo', version='0.1', py_modu
""" """
+@unittest._skipInRpmBuild("don't try to nest one rpm build inside another rpm build") +@unittest._skipInRpmBuild("don't try to nest one rpm build inside another rpm build")
class BuildRpmTestCase(support.TempdirManager, class BuildRpmTestCase(support.TempdirManager,
support.EnvironGuard,
support.LoggingSilencer, support.LoggingSilencer,
diff -up Python-3.2.2/Lib/distutils/tests/test_build_ext.py.skip-distutils-tests-that-fail-in-rpmbuild Python-3.2.2/Lib/distutils/tests/test_build_ext.py unittest.TestCase):
diff -up Python-2.7.3/Lib/distutils/tests/test_build_ext.py.mark-tests-that-fail-in-rpmbuild Python-2.7.3/Lib/distutils/tests/test_build_ext.py

603
SOURCES/00146-hashlib-fips.patch

@ -1,48 +1,82 @@
diff --git a/Lib/hashlib.py b/Lib/hashlib.py diff -up Python-2.7.2/Lib/hashlib.py.hashlib-fips Python-2.7.2/Lib/hashlib.py
index 316cece..b7ad879 100644 --- Python-2.7.2/Lib/hashlib.py.hashlib-fips 2011-06-11 11:46:24.000000000 -0400
--- a/Lib/hashlib.py +++ Python-2.7.2/Lib/hashlib.py 2011-09-14 00:21:26.194252001 -0400
+++ b/Lib/hashlib.py @@ -6,9 +6,12 @@
@@ -23,6 +23,16 @@ the zlib module.
__doc__ = """hashlib module - A common interface to many hash functions.
-new(name, string='') - returns a new hash object implementing the
- given hash function; initializing the hash
- using the given string data.
+new(name, string='', usedforsecurity=True)
+ - returns a new hash object implementing the given hash function;
+ initializing the hash using the given string data.
+
+ "usedforsecurity" is a non-standard extension for better supporting
+ FIPS-compliant environments (see below)
Named constructor functions are also available, these are much faster
than using new():
@@ -24,6 +27,20 @@ the zlib module.
Choose your hash function wisely. Some have known collision weaknesses. Choose your hash function wisely. Some have known collision weaknesses.
sha384 and sha512 will be slow on 32 bit platforms. sha384 and sha512 will be slow on 32 bit platforms.
+If the underlying implementation supports "FIPS mode", and this is enabled, it +Our implementation of hashlib uses OpenSSL.
+may restrict the available hashes to only those that are compliant with FIPS +
+regulations. For example, it may deny the use of MD5, on the grounds that this +OpenSSL has a "FIPS mode", which, if enabled, may restrict the available hashes
+is not secure for uses such as authentication, system integrity checking, or +to only those that are compliant with FIPS regulations. For example, it may
+digital signatures. If you need to use such a hash for non-security purposes +deny the use of MD5, on the grounds that this is not secure for uses such as
+(such as indexing into a data structure for speed), you can override the keyword +authentication, system integrity checking, or digital signatures.
+argument "usedforsecurity" from True to False to signify that your code is not +
+relying on the hash for security purposes, and this will allow the hash to be +If you need to use such a hash for non-security purposes (such as indexing into
+usable even in FIPS mode. +a data structure for speed), you can override the keyword argument
+"usedforsecurity" from True to False to signify that your code is not relying
+on the hash for security purposes, and this will allow the hash to be usable
+even in FIPS mode. This is not a standard feature of Python 2.7's hashlib, and
+is included here to better support FIPS mode.
+ +
Hash objects have these methods: Hash objects have these methods:
- update(arg): Update the hash object with the bytes in arg. Repeated calls - update(arg): Update the hash object with the string arg. Repeated calls
are equivalent to a single call with the concatenation of all are equivalent to a single call with the concatenation of all
@@ -62,6 +72,18 @@ algorithms_available = set(__always_supported) @@ -63,74 +80,39 @@ algorithms = __always_supported
__all__ = __always_supported + ('new', 'algorithms_guaranteed', __all__ = __always_supported + ('new', 'algorithms')
'algorithms_available', 'pbkdf2_hmac')
+import functools -def __get_builtin_constructor(name):
+def __ignore_usedforsecurity(func): - try:
+ """Used for sha3_* functions. Until OpenSSL implements them, we want - if name in ('SHA1', 'sha1'):
+ to use them from Python _sha3 module, but we want them to accept - import _sha
+ usedforsecurity argument too.""" - return _sha.new
+ # TODO: remove this function when OpenSSL implements sha3 - elif name in ('MD5', 'md5'):
+ @functools.wraps(func) - import _md5
+ def inner(*args, **kwargs): - return _md5.new
+ if 'usedforsecurity' in kwargs: - elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'):
+ kwargs.pop('usedforsecurity') - import _sha256
+ return func(*args, **kwargs) - bs = name[3:]
+ return inner - if bs == '256':
- return _sha256.sha256
__builtin_constructor_cache = {} - elif bs == '224':
- return _sha256.sha224
@@ -100,31 +122,39 @@ def __get_openssl_constructor(name): - elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'):
- import _sha512
- bs = name[3:]
- if bs == '512':
- return _sha512.sha512
- elif bs == '384':
- return _sha512.sha384
- except ImportError:
- pass # no extension module, this hash is unsupported.
-
- raise ValueError('unsupported hash type ' + name)
-
-
def __get_openssl_constructor(name):
try:
f = getattr(_hashlib, 'openssl_' + name) f = getattr(_hashlib, 'openssl_' + name)
# Allow the C module to raise ValueError. The function will be # Allow the C module to raise ValueError. The function will be
# defined but the hash not actually available thanks to OpenSSL. # defined but the hash not actually available thanks to OpenSSL.
- f() - f()
+ #
+ # We pass "usedforsecurity=False" to disable FIPS-based restrictions: + # We pass "usedforsecurity=False" to disable FIPS-based restrictions:
+ # at this stage we're merely seeing if the function is callable, + # at this stage we're merely seeing if the function is callable,
+ # rather than using it for actual work. + # rather than using it for actual work.
@ -50,76 +84,61 @@ index 316cece..b7ad879 100644
# Use the C function directly (very fast) # Use the C function directly (very fast)
return f return f
except (AttributeError, ValueError): except (AttributeError, ValueError):
+ # TODO: We want to just raise here when OpenSSL implements sha3 - return __get_builtin_constructor(name)
+ # because we want to make sure that Fedora uses everything from OpenSSL + raise
return __get_builtin_constructor(name)
-def __py_new(name, data=b''):
- """new(name, data=b'') - Return a new hashing object using the named algorithm;
- optionally initialized with data (which must be bytes).
+def __py_new(name, data=b'', usedforsecurity=True):
+ """new(name, data=b'', usedforsecurity=True) - Return a new hashing object using
+ the named algorithm; optionally initialized with data (which must be bytes).
+ The 'usedforsecurity' keyword argument does nothing, and is for compatibilty
+ with the OpenSSL implementation
"""
return __get_builtin_constructor(name)(data)
-def __hash_new(name, data=b''): -
- """new(name, data=b'') - Return a new hashing object using the named algorithm; -def __py_new(name, string=''):
- optionally initialized with data (which must be bytes). - """new(name, string='') - Return a new hashing object using the named algorithm;
+def __hash_new(name, data=b'', usedforsecurity=True): - optionally initialized with a string.
+ """new(name, data=b'', usedforsecurity=True) - Return a new hashing object using - """
+ the named algorithm; optionally initialized with data (which must be bytes). - return __get_builtin_constructor(name)(string)
+ -
-
-def __hash_new(name, string=''):
+def __hash_new(name, string='', usedforsecurity=True):
"""new(name, string='') - Return a new hashing object using the named algorithm;
optionally initialized with a string.
+ Override 'usedforsecurity' to False when using for non-security purposes in + Override 'usedforsecurity' to False when using for non-security purposes in
+ a FIPS environment + a FIPS environment
""" """
try: try:
- return _hashlib.new(name, data) - return _hashlib.new(name, string)
+ return _hashlib.new(name, data, usedforsecurity) + return _hashlib.new(name, string, usedforsecurity)
except ValueError: except ValueError:
- # If the _hashlib module (OpenSSL) doesn't support the named - # If the _hashlib module (OpenSSL) doesn't support the named
- # hash, try using our builtin implementations. - # hash, try using our builtin implementations.
- # This allows for SHA224/256 and SHA384/512 support even though - # This allows for SHA224/256 and SHA384/512 support even though
- # the OpenSSL library prior to 0.9.8 doesn't provide them. - # the OpenSSL library prior to 0.9.8 doesn't provide them.
+ # TODO: We want to just raise here when OpenSSL implements sha3 - return __get_builtin_constructor(name)(string)
+ # because we want to make sure that Fedora uses everything from OpenSSL -
return __get_builtin_constructor(name)(data) + raise
try:
@@ -207,7 +237,10 @@ for __func_name in __always_supported: import _hashlib
new = __hash_new
__get_hash = __get_openssl_constructor
except ImportError:
- new = __py_new
- __get_hash = __get_builtin_constructor
+ # We don't build the legacy modules
+ raise
for __func_name in __always_supported:
# try them all, some may not work due to the OpenSSL # try them all, some may not work due to the OpenSSL
# version not supporting that algorithm. @@ -143,4 +125,4 @@ for __func_name in __always_supported:
try:
- globals()[__func_name] = __get_hash(__func_name)
+ func = __get_hash(__func_name)
+ if 'sha3_' in __func_name:
+ func = __ignore_usedforsecurity(func)
+ globals()[__func_name] = func
except ValueError:
import logging
logging.exception('code for hash %s was not found.', __func_name)
@@ -215,3 +248,4 @@ for __func_name in __always_supported:
# Cleanup locals() # Cleanup locals()
del __always_supported, __func_name, __get_hash del __always_supported, __func_name, __get_hash
del __py_new, __hash_new, __get_openssl_constructor -del __py_new, __hash_new, __get_openssl_constructor
+del __ignore_usedforsecurity +del __hash_new, __get_openssl_constructor
\ No newline at end of file diff -up Python-2.7.2/Lib/test/test_hashlib.py.hashlib-fips Python-2.7.2/Lib/test/test_hashlib.py
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- Python-2.7.2/Lib/test/test_hashlib.py.hashlib-fips 2011-06-11 11:46:25.000000000 -0400
index c9b113e..60e2392 100644 +++ Python-2.7.2/Lib/test/test_hashlib.py 2011-09-14 01:08:55.525254195 -0400
--- a/Lib/test/test_hashlib.py @@ -32,6 +32,19 @@ def hexstr(s):
+++ b/Lib/test/test_hashlib.py r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
@@ -24,7 +24,22 @@ from test.support import _4G, bigmemtest, import_fresh_module return r
COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount')
c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib'])
-py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib'])
+# skipped on Fedora, since we always use OpenSSL implementation
+# py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib'])
+
+def openssl_enforces_fips(): +def openssl_enforces_fips():
+ # Use the "openssl" command (if present) to try to determine if the local + # Use the "openssl" command (if present) to try to determine if the local
+ # OpenSSL is configured to enforce FIPS + # OpenSSL is configured to enforce FIPS
@ -134,80 +153,122 @@ index c9b113e..60e2392 100644
+ return b'unknown cipher' in stderr + return b'unknown cipher' in stderr
+OPENSSL_ENFORCES_FIPS = openssl_enforces_fips() +OPENSSL_ENFORCES_FIPS = openssl_enforces_fips()
def hexstr(s):
assert isinstance(s, bytes), repr(s)
@@ -34,6 +49,16 @@ def hexstr(s):
r += h[(i >> 4) & 0xF] + h[i & 0xF]
return r
+# hashlib and _hashlib-based functions support a "usedforsecurity" keyword
+# argument, and FIPS mode requires that it be used overridden with a False
+# value for these selftests to work. Other cryptographic code within Python
+# doesn't support this keyword.
+# Modify a function to one in which "usedforsecurity=False" is added to the
+# keyword arguments:
+def suppress_fips(f):
+ def g(*args, **kwargs):
+ return f(*args, usedforsecurity=False, **kwargs)
+ return g
class HashLibTestCase(unittest.TestCase): class HashLibTestCase(unittest.TestCase):
supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
@@ -63,11 +88,11 @@ class HashLibTestCase(unittest.TestCase): @@ -61,10 +74,10 @@ class HashLibTestCase(unittest.TestCase)
# For each algorithm, test the direct constructor and the use
# of hashlib.new given the algorithm name. # of hashlib.new given the algorithm name.
for algorithm, constructors in self.constructors_to_test.items(): for algorithm, constructors in self.constructors_to_test.items():
- constructors.add(getattr(hashlib, algorithm)) constructors.add(getattr(hashlib, algorithm))
+ constructors.add(suppress_fips(getattr(hashlib, algorithm))) - def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm):
def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm): + def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, usedforsecurity=True):
if data is None: if data is None:
- return hashlib.new(_alg) - return hashlib.new(_alg)
- return hashlib.new(_alg, data) - return hashlib.new(_alg, data)
+ return suppress_fips(hashlib.new)(_alg) + return hashlib.new(_alg, usedforsecurity=usedforsecurity)
+ return suppress_fips(hashlib.new)(_alg, data) + return hashlib.new(_alg, data, usedforsecurity=usedforsecurity)
constructors.add(_test_algorithm_via_hashlib_new) constructors.add(_test_algorithm_via_hashlib_new)
_hashlib = self._conditional_import_module('_hashlib') _hashlib = self._conditional_import_module('_hashlib')
@@ -79,27 +104,12 @@ class HashLibTestCase(unittest.TestCase): @@ -78,28 +91,13 @@ class HashLibTestCase(unittest.TestCase)
for algorithm, constructors in self.constructors_to_test.items():
constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
if constructor: if constructor:
- constructors.add(constructor) constructors.add(constructor)
+ constructors.add(suppress_fips(constructor))
def add_builtin_constructor(name):
constructor = getattr(hashlib, "__get_builtin_constructor")(name)
self.constructors_to_test[name].add(constructor)
- _md5 = self._conditional_import_module('_md5') - _md5 = self._conditional_import_module('_md5')
- if _md5: - if _md5:
- add_builtin_constructor('md5') - self.constructors_to_test['md5'].add(_md5.new)
- _sha1 = self._conditional_import_module('_sha1') - _sha = self._conditional_import_module('_sha')
- if _sha1: - if _sha:
- add_builtin_constructor('sha1') - self.constructors_to_test['sha1'].add(_sha.new)
- _sha256 = self._conditional_import_module('_sha256') - _sha256 = self._conditional_import_module('_sha256')
- if _sha256: - if _sha256:
- add_builtin_constructor('sha224') - self.constructors_to_test['sha224'].add(_sha256.sha224)
- add_builtin_constructor('sha256') - self.constructors_to_test['sha256'].add(_sha256.sha256)
- _sha512 = self._conditional_import_module('_sha512') - _sha512 = self._conditional_import_module('_sha512')
- if _sha512: - if _sha512:
- add_builtin_constructor('sha384') - self.constructors_to_test['sha384'].add(_sha512.sha384)
- add_builtin_constructor('sha512') - self.constructors_to_test['sha512'].add(_sha512.sha512)
- -
super(HashLibTestCase, self).__init__(*args, **kwargs) super(HashLibTestCase, self).__init__(*args, **kwargs)
@property def test_hash_array(self):
@@ -148,9 +158,6 @@ class HashLibTestCase(unittest.TestCase): a = array.array("b", range(10))
else: constructors = self.constructors_to_test.itervalues()
del sys.modules['_md5'] for cons in itertools.chain.from_iterable(constructors):
self.assertRaises(TypeError, get_builtin_constructor, 3) - c = cons(a)
- constructor = get_builtin_constructor('md5') + c = cons(a, usedforsecurity=False)
- self.assertIs(constructor, _md5.md5) c.hexdigest()
- self.assertEqual(sorted(builtin_constructor_cache), ['MD5', 'md5'])
def test_algorithms_attribute(self):
@@ -115,28 +113,9 @@ class HashLibTestCase(unittest.TestCase)
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
self.assertRaises(TypeError, hashlib.new, 1)
- def test_get_builtin_constructor(self):
- get_builtin_constructor = hashlib.__dict__[
- '__get_builtin_constructor']
- self.assertRaises(ValueError, get_builtin_constructor, 'test')
- try:
- import _md5
- except ImportError:
- pass
- # This forces an ImportError for "import _md5" statements
- sys.modules['_md5'] = None
- try:
- self.assertRaises(ValueError, get_builtin_constructor, 'md5')
- finally:
- if '_md5' in locals():
- sys.modules['_md5'] = _md5
- else:
- del sys.modules['_md5']
- self.assertRaises(TypeError, get_builtin_constructor, 3)
-
def test_hexdigest(self): def test_hexdigest(self):
for cons in self.hash_constructors: for name in self.supported_hash_names:
@@ -433,6 +440,64 @@ class HashLibTestCase(unittest.TestCase): - h = hashlib.new(name)
+ h = hashlib.new(name, usedforsecurity=False)
self.assertTrue(hexstr(h.digest()) == h.hexdigest())
def test_large_update(self):
@@ -145,16 +125,16 @@ class HashLibTestCase(unittest.TestCase)
abcs = aas + bees + cees
for name in self.supported_hash_names:
- m1 = hashlib.new(name)
+ m1 = hashlib.new(name, usedforsecurity=False)
m1.update(aas)
m1.update(bees)
m1.update(cees)
- m2 = hashlib.new(name)
+ m2 = hashlib.new(name, usedforsecurity=False)
m2.update(abcs)
self.assertEqual(m1.digest(), m2.digest(), name+' update problem.')
- m3 = hashlib.new(name, abcs)
+ m3 = hashlib.new(name, abcs, usedforsecurity=False)
self.assertEqual(m1.digest(), m3.digest(), name+' new problem.')
def check(self, name, data, digest):
@@ -162,7 +142,7 @@ class HashLibTestCase(unittest.TestCase)
# 2 is for hashlib.name(...) and hashlib.new(name, ...)
self.assertGreaterEqual(len(constructors), 2)
for hash_object_constructor in constructors:
- computed = hash_object_constructor(data).hexdigest()
+ computed = hash_object_constructor(data, usedforsecurity=False).hexdigest()
self.assertEqual(
computed, digest,
"Hash algorithm %s constructed using %s returned hexdigest"
@@ -172,7 +152,8 @@ class HashLibTestCase(unittest.TestCase)
def check_unicode(self, algorithm_name):
# Unicode objects are not allowed as input.
- expected = hashlib.new(algorithm_name, str(u'spam')).hexdigest()
+ expected = hashlib.new(algorithm_name, str(u'spam'),
+ usedforsecurity=False).hexdigest()
self.check(algorithm_name, u'spam', expected)
def test_unicode(self):
@@ -354,6 +335,70 @@ class HashLibTestCase(unittest.TestCase)
self.assertEqual(expected_hash, hasher.hexdigest()) self.assertEqual(expected_hash, hasher.hexdigest())
@ -227,74 +288,70 @@ index c9b113e..60e2392 100644
+ m = hashlib.new('md5', b'abc\n', usedforsecurity=False) + m = hashlib.new('md5', b'abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+ +
+ def assertRaisesUnknownCipher(self, callable_obj=None, *args, **kwargs):
+ try:
+ callable_obj(*args, **kwargs)
+ except ValueError, e:
+ if not e.args[0].endswith('unknown cipher'):
+ self.fail('Incorrect exception raised')
+ else:
+ self.fail('Exception was not raised')
+
+ @unittest.skipUnless(OPENSSL_ENFORCES_FIPS, + @unittest.skipUnless(OPENSSL_ENFORCES_FIPS,
+ 'FIPS enforcement required for this test.') + 'FIPS enforcement required for this test.')
+ def test_hashlib_fips_mode(self): + def test_hashlib_fips_mode(self):
+ # Ensure that we raise a ValueError on vanilla attempts to use MD5 + # Ensure that we raise a ValueError on vanilla attempts to use MD5
+ # in hashlib in a FIPS-enforced setting: + # in hashlib in a FIPS-enforced setting:
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'): + self.assertRaisesUnknownCipher(hashlib.md5)
+ m = hashlib.md5() + self.assertRaisesUnknownCipher(hashlib.new, 'md5')
+
+ if not self._conditional_import_module('_md5'):
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'):
+ m = hashlib.new('md5')
+ +
+ @unittest.skipUnless(OPENSSL_ENFORCES_FIPS, + @unittest.skipUnless(OPENSSL_ENFORCES_FIPS,
+ 'FIPS enforcement required for this test.') + 'FIPS enforcement required for this test.')
+ def test_hashopenssl_fips_mode(self): + def test_hashopenssl_fips_mode(self):
+ # Verify the _hashlib module's handling of md5: + # Verify the _hashlib module's handling of md5:
+ _hashlib = self._conditional_import_module('_hashlib') + import _hashlib
+ if _hashlib: +
+ assert hasattr(_hashlib, 'openssl_md5') + assert hasattr(_hashlib, 'openssl_md5')
+ +
+ # Ensure that _hashlib raises a ValueError on vanilla attempts to + # Ensure that _hashlib raises a ValueError on vanilla attempts to
+ # use MD5 in a FIPS-enforced setting: + # use MD5 in a FIPS-enforced setting:
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'): + self.assertRaisesUnknownCipher(_hashlib.openssl_md5)
+ m = _hashlib.openssl_md5() + self.assertRaisesUnknownCipher(_hashlib.new, 'md5')
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'):
+ m = _hashlib.new('md5')
+ +
+ # Ensure that in such a setting we can whitelist a callsite with + # Ensure that in such a setting we can whitelist a callsite with
+ # usedforsecurity=False and have it succeed: + # usedforsecurity=False and have it succeed:
+ m = _hashlib.openssl_md5(usedforsecurity=False) + m = _hashlib.openssl_md5(usedforsecurity=False)
+ m.update(b'abc\n') + m.update('abc\n')
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+ +
+ m = _hashlib.new('md5', usedforsecurity=False) + m = _hashlib.new('md5', usedforsecurity=False)
+ m.update(b'abc\n') + m.update('abc\n')
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
+ m = _hashlib.openssl_md5(b'abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+ +
+ m = _hashlib.new('md5', b'abc\n', usedforsecurity=False) + m = _hashlib.openssl_md5('abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1") + self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
class KDFTests(unittest.TestCase): + m = _hashlib.new('md5', 'abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
@@ -516,7 +581,7 @@ class KDFTests(unittest.TestCase): +
out = pbkdf2(hash_name='sha1', password=b'password', salt=b'salt', +
iterations=1, dklen=None) +
self.assertEqual(out, self.pbkdf2_results['sha1'][0][0]) def test_main():
- test_support.run_unittest(HashLibTestCase)
+ @unittest.skip('skipped on Fedora, as we always use OpenSSL pbkdf2_hmac')
def test_pbkdf2_hmac_py(self):
self._test_pbkdf2_hmac(py_hashlib.pbkdf2_hmac)
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index 44765ac..b8cf490 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -20,6 +20,8 @@
diff -up Python-2.7.2/Modules/_hashopenssl.c.hashlib-fips Python-2.7.2/Modules/_hashopenssl.c
--- Python-2.7.2/Modules/_hashopenssl.c.hashlib-fips 2011-06-11 11:46:26.000000000 -0400
+++ Python-2.7.2/Modules/_hashopenssl.c 2011-09-14 00:21:26.199252001 -0400
@@ -36,6 +36,8 @@
#endif
/* EVP is the preferred interface to hashing in OpenSSL */ /* EVP is the preferred interface to hashing in OpenSSL */
+#include <openssl/ssl.h> +#include <openssl/ssl.h>
+#include <openssl/err.h> +#include <openssl/err.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/hmac.h>
/* We use the object interface to discover what hashes OpenSSL supports. */ #define MUNCH_SIZE INT_MAX
@@ -45,11 +47,19 @@ typedef struct { @@ -65,11 +67,19 @@ typedef struct {
static PyTypeObject EVPtype; static PyTypeObject EVPtype;
@ -318,7 +375,7 @@ index 44765ac..b8cf490 100644
DEFINE_CONSTS_FOR_NEW(md5) DEFINE_CONSTS_FOR_NEW(md5)
DEFINE_CONSTS_FOR_NEW(sha1) DEFINE_CONSTS_FOR_NEW(sha1)
@@ -92,6 +102,48 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len) @@ -115,6 +125,48 @@ EVP_hash(EVPobject *self, const void *vp
} }
} }
@ -349,7 +406,7 @@ index 44765ac..b8cf490 100644
+ errstr = ERR_error_string(ERR_peek_last_error(), NULL); + errstr = ERR_error_string(ERR_peek_last_error(), NULL);
+ ERR_clear_error(); + ERR_clear_error();
+ +
+ return PyUnicode_FromString(errstr); /* Can be NULL */ + return PyString_FromString(errstr); /* Can be NULL */
+} +}
+ +
+static void +static void
@ -367,28 +424,27 @@ index 44765ac..b8cf490 100644
/* Internal methods for a hash object */ /* Internal methods for a hash object */
static void static void
@@ -259,15 +311,16 @@ EVP_repr(EVPobject *self) @@ -313,14 +365,15 @@ EVP_repr(PyObject *self)
static int static int
EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
{ {
- static char *kwlist[] = {"name", "string", NULL}; - static char *kwlist[] = {"name", "string", NULL};
+ static char *kwlist[] = {"name", "string", "usedforsecurity", NULL}; + static char *kwlist[] = {"name", "string", "usedforsecurity", NULL};
PyObject *name_obj = NULL; PyObject *name_obj = NULL;
PyObject *data_obj = NULL;
+ int usedforsecurity = 1; + int usedforsecurity = 1;
Py_buffer view; Py_buffer view = { 0 };
char *nameStr; char *nameStr;
const EVP_MD *digest; const EVP_MD *digest;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:HASH", kwlist, - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*:HASH", kwlist,
- &name_obj, &data_obj)) { - &name_obj, &view)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oi:HASH", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*i:HASH", kwlist,
+ &name_obj, &data_obj, &usedforsecurity)) { + &name_obj, &view, &usedforsecurity)) {
return -1; return -1;
} }
@@ -288,7 +341,12 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) @@ -336,7 +389,12 @@ EVP_tp_init(EVPobject *self, PyObject *a
PyBuffer_Release(&view); PyBuffer_Release(&view);
return -1; return -1;
} }
- EVP_DigestInit(&self->ctx, digest); - EVP_DigestInit(&self->ctx, digest);
@ -401,7 +457,7 @@ index 44765ac..b8cf490 100644
self->name = name_obj; self->name = name_obj;
Py_INCREF(self->name); Py_INCREF(self->name);
@@ -372,7 +430,8 @@ static PyTypeObject EVPtype = { @@ -420,7 +478,8 @@ static PyTypeObject EVPtype = {
static PyObject * static PyObject *
EVPnew(PyObject *name_obj, EVPnew(PyObject *name_obj,
const EVP_MD *digest, const EVP_MD_CTX *initial_ctx, const EVP_MD *digest, const EVP_MD_CTX *initial_ctx,
@ -411,7 +467,7 @@ index 44765ac..b8cf490 100644
{ {
EVPobject *self; EVPobject *self;
@@ -387,7 +446,12 @@ EVPnew(PyObject *name_obj, @@ -435,7 +494,12 @@ EVPnew(PyObject *name_obj,
if (initial_ctx) { if (initial_ctx) {
EVP_MD_CTX_copy(&self->ctx, initial_ctx); EVP_MD_CTX_copy(&self->ctx, initial_ctx);
} else { } else {
@ -425,7 +481,7 @@ index 44765ac..b8cf490 100644
} }
if (cp && len) { if (cp && len) {
@@ -411,21 +475,29 @@ PyDoc_STRVAR(EVP_new__doc__, @@ -459,20 +523,28 @@ PyDoc_STRVAR(EVP_new__doc__,
An optional string argument may be provided and will be\n\ An optional string argument may be provided and will be\n\
automatically hashed.\n\ automatically hashed.\n\
\n\ \n\
@ -445,32 +501,29 @@ index 44765ac..b8cf490 100644
- static char *kwlist[] = {"name", "string", NULL}; - static char *kwlist[] = {"name", "string", NULL};
+ static char *kwlist[] = {"name", "string", "usedforsecurity", NULL}; + static char *kwlist[] = {"name", "string", "usedforsecurity", NULL};
PyObject *name_obj = NULL; PyObject *name_obj = NULL;
PyObject *data_obj = NULL;
+ int usedforsecurity = 1;
Py_buffer view = { 0 }; Py_buffer view = { 0 };
PyObject *ret_obj; PyObject *ret_obj;
char *name; char *name;
const EVP_MD *digest; const EVP_MD *digest;
+ int usedforsecurity = 1;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|O:new", kwlist, - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*:new", kwlist,
- &name_obj, &data_obj)) { - &name_obj, &view)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|Oi:new", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*i:new", kwlist,
+ &name_obj, &data_obj, &usedforsecurity)) { + &name_obj, &view, &usedforsecurity)) {
return NULL; return NULL;
} }
@@ -439,7 +511,8 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) @@ -484,58 +556,118 @@ EVP_new(PyObject *self, PyObject *args,
digest = EVP_get_digestbyname(name); digest = EVP_get_digestbyname(name);
- ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, view.len); ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf,
+ ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, view.len, - view.len);
+ usedforsecurity); + view.len, usedforsecurity);
PyBuffer_Release(&view);
if (data_obj)
PyBuffer_Release(&view);
@@ -722,57 +795,114 @@ generate_hash_name_list(void)
return ret_obj;
}
/* /*
- * This macro generates constructor function definitions for specific - * This macro generates constructor function definitions for specific
@ -486,32 +539,25 @@ index 44765ac..b8cf490 100644
#define GEN_CONSTRUCTOR(NAME) \ #define GEN_CONSTRUCTOR(NAME) \
static PyObject * \ static PyObject * \
- EVP_new_ ## NAME (PyObject *self, PyObject *args) \ - EVP_new_ ## NAME (PyObject *self, PyObject *args) \
+ EVP_new_ ## NAME (PyObject *self, PyObject *args, PyObject *kwdict) \ + EVP_new_ ## NAME (PyObject *self, PyObject *args, PyObject *kwdict) \
{ \ { \
- PyObject *data_obj = NULL; \
- Py_buffer view = { 0 }; \ - Py_buffer view = { 0 }; \
- PyObject *ret_obj; \ - PyObject *ret_obj; \
- \ - \
- if (!PyArg_ParseTuple(args, "|O:" #NAME , &data_obj)) { \ - if (!PyArg_ParseTuple(args, "|s*:" #NAME , &view)) { \
- return NULL; \ - return NULL; \
- } \ - } \
- \ - \
- if (data_obj) \
- GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \
- \
- ret_obj = EVPnew( \ - ret_obj = EVPnew( \
- CONST_ ## NAME ## _name_obj, \ - CONST_ ## NAME ## _name_obj, \
- NULL, \ - NULL, \
- CONST_new_ ## NAME ## _ctx_p, \ - CONST_new_ ## NAME ## _ctx_p, \
- (unsigned char*)view.buf, \ - (unsigned char*)view.buf, view.len); \
- view.len); \ - PyBuffer_Release(&view); \
- \
- if (data_obj) \
- PyBuffer_Release(&view); \
- return ret_obj; \ - return ret_obj; \
+ return implement_specific_EVP_new(self, args, kwdict, \ + return implement_specific_EVP_new(self, args, kwdict, \
+ "|Oi:" #NAME, \ + "|s*i:" #NAME, \
+ &cached_info_ ## NAME ); \ + &cached_info_ ## NAME ); \
} }
+static PyObject * +static PyObject *
@ -520,7 +566,6 @@ index 44765ac..b8cf490 100644
+ EVPCachedInfo *cached_info) + EVPCachedInfo *cached_info)
+{ +{
+ static char *kwlist[] = {"string", "usedforsecurity", NULL}; + static char *kwlist[] = {"string", "usedforsecurity", NULL};
+ PyObject *data_obj = NULL;
+ Py_buffer view = { 0 }; + Py_buffer view = { 0 };
+ int usedforsecurity = 1; + int usedforsecurity = 1;
+ int idx; + int idx;
@ -529,13 +574,10 @@ index 44765ac..b8cf490 100644
+ assert(cached_info); + assert(cached_info);
+ +
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, format, kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwdict, format, kwlist,
+ &data_obj, &usedforsecurity)) { + &view, &usedforsecurity)) {
+ return NULL; + return NULL;
+ } + }
+ +
+ if (data_obj)
+ GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
+
+ idx = usedforsecurity ? 1 : 0; + idx = usedforsecurity ? 1 : 0;
+ +
+ /* + /*
@ -558,10 +600,9 @@ index 44765ac..b8cf490 100644
+ } else { + } else {
+ PyErr_SetString(PyExc_ValueError, "Error initializing hash"); + PyErr_SetString(PyExc_ValueError, "Error initializing hash");
+ } + }
+ } + }
+ +
+ if (data_obj) + PyBuffer_Release(&view);
+ PyBuffer_Release(&view);
+ +
+ return ret_obj; + return ret_obj;
+} +}
@ -570,7 +611,7 @@ index 44765ac..b8cf490 100644
#define CONSTRUCTOR_METH_DEF(NAME) \ #define CONSTRUCTOR_METH_DEF(NAME) \
- {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \ - {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \
+ {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, \ + {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, \
+ METH_VARARGS|METH_KEYWORDS, \ + METH_VARARGS |METH_KEYWORDS, \
PyDoc_STR("Returns a " #NAME \ PyDoc_STR("Returns a " #NAME \
" hash object; optionally initialized with a string") \ " hash object; optionally initialized with a string") \
} }
@ -579,7 +620,7 @@ index 44765ac..b8cf490 100644
- constructor constants if they haven't been initialized already. */ - constructor constants if they haven't been initialized already. */
-#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ -#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \
- if (CONST_ ## NAME ## _name_obj == NULL) { \ - if (CONST_ ## NAME ## _name_obj == NULL) { \
- CONST_ ## NAME ## _name_obj = PyUnicode_FromString(#NAME); \ - CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \
- if (EVP_get_digestbyname(#NAME)) { \ - if (EVP_get_digestbyname(#NAME)) { \
- CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \ - CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \
- EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \ - EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \
@ -591,17 +632,18 @@ index 44765ac..b8cf490 100644
+ Try to initialize a context for each hash twice, once with + Try to initialize a context for each hash twice, once with
+ EVP_MD_CTX_FLAG_NON_FIPS_ALLOW and once without. + EVP_MD_CTX_FLAG_NON_FIPS_ALLOW and once without.
+ +
+ Any that have errors during initialization will end up with a NULL ctx_ptrs + Any that have errors during initialization will end up wit a NULL ctx_ptrs
+ entry, and err_msgs will be set (unless we're very low on memory) + entry, and err_msgs will be set (unless we're very low on memory)
+*/ +*/
+#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ +#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \
+ init_constructor_constant(&cached_info_ ## NAME, #NAME); \ + init_constructor_constant(&cached_info_ ## NAME, #NAME); \
} while (0); } while (0);
+static void +static void
+init_constructor_constant(EVPCachedInfo *cached_info, const char *name) +init_constructor_constant(EVPCachedInfo *cached_info, const char *name)
+{ +{
+ assert(cached_info); + assert(cached_info);
+ cached_info->name_obj = PyUnicode_FromString(name); + cached_info->name_obj = PyString_FromString(name);
+ if (EVP_get_digestbyname(name)) { + if (EVP_get_digestbyname(name)) {
+ int i; + int i;
+ for (i=0; i<2; i++) { + for (i=0; i<2; i++) {
@ -612,29 +654,76 @@ index 44765ac..b8cf490 100644
+ cached_info->ctx_ptrs[i] = &cached_info->ctxs[i]; + cached_info->ctx_ptrs[i] = &cached_info->ctxs[i];
+ } else { + } else {
+ /* Failure: */ + /* Failure: */
+ cached_info->ctx_ptrs[i] = NULL; + cached_info->ctx_ptrs[i] = NULL;
+ cached_info->error_msgs[i] = error_msg_for_last_error(); + cached_info->error_msgs[i] = error_msg_for_last_error();
+ } + }
+ } + }
+ } + }
+} +}
+
GEN_CONSTRUCTOR(md5) GEN_CONSTRUCTOR(md5)
GEN_CONSTRUCTOR(sha1) GEN_CONSTRUCTOR(sha1)
@@ -819,13 +949,10 @@ PyInit__hashlib(void) #ifdef _OPENSSL_SUPPORTS_SHA2
@@ -565,13 +700,10 @@ init_hashlib(void)
{ {
PyObject *m, *openssl_md_meth_names; PyObject *m;
- OpenSSL_add_all_digests();
- ERR_load_crypto_strings();
+ SSL_load_error_strings(); + SSL_load_error_strings();
+ SSL_library_init(); + SSL_library_init();
OpenSSL_add_all_digests();
- /* TODO build EVP_functions openssl_* entries dynamically based - /* TODO build EVP_functions openssl_* entries dynamically based
- * on what hashes are supported rather than listing many - * on what hashes are supported rather than listing many
- * but having some be unsupported. Only init appropriate - * but having some be unsupported. Only init appropriate
- * constants. */ - * constants. */
+ OpenSSL_add_all_digests(); -
Py_TYPE(&EVPtype) = &PyType_Type; Py_TYPE(&EVPtype) = &PyType_Type;
if (PyType_Ready(&EVPtype) < 0) if (PyType_Ready(&EVPtype) < 0)
return;
diff -up Python-2.7.2/Modules/Setup.dist.hashlib-fips Python-2.7.2/Modules/Setup.dist
--- Python-2.7.2/Modules/Setup.dist.hashlib-fips 2011-09-14 00:21:26.163252001 -0400
+++ Python-2.7.2/Modules/Setup.dist 2011-09-14 00:21:26.201252001 -0400
@@ -248,14 +248,14 @@ imageop imageop.c # Operations on images
# Message-Digest Algorithm, described in RFC 1321. The necessary files
# md5.c and md5.h are included here.
-_md5 md5module.c md5.c
+#_md5 md5module.c md5.c
# The _sha module implements the SHA checksum algorithms.
# (NIST's Secure Hash Algorithms.)
-_sha shamodule.c
-_sha256 sha256module.c
-_sha512 sha512module.c
+#_sha shamodule.c
+#_sha256 sha256module.c
+#_sha512 sha512module.c
# SGI IRIX specific modules -- off by default.
diff -up Python-2.7.2/setup.py.hashlib-fips Python-2.7.2/setup.py
--- Python-2.7.2/setup.py.hashlib-fips 2011-09-14 00:21:25.722252001 -0400
+++ Python-2.7.2/setup.py 2011-09-14 00:21:26.203252001 -0400
@@ -768,21 +768,6 @@ class PyBuildExt(build_ext):
print ("warning: openssl 0x%08x is too old for _hashlib" %
openssl_ver)
missing.append('_hashlib')
- if COMPILED_WITH_PYDEBUG or not have_usable_openssl:
- # The _sha module implements the SHA1 hash algorithm.
- exts.append( Extension('_sha', ['shamodule.c']) )
- # The _md5 module implements the RSA Data Security, Inc. MD5
- # Message-Digest Algorithm, described in RFC 1321. The
- # necessary files md5.c and md5.h are included here.
- exts.append( Extension('_md5',
- sources = ['md5module.c', 'md5.c'],
- depends = ['md5.h']) )
-
- min_sha2_openssl_ver = 0x00908000
- if COMPILED_WITH_PYDEBUG or openssl_ver < min_sha2_openssl_ver:
- # OpenSSL doesn't do these until 0.9.8 so we'll bring our own hash
- exts.append( Extension('_sha256', ['sha256module.c']) )
- exts.append( Extension('_sha512', ['sha512module.c']) )
# Modules that provide persistent dictionary-like semantics. You will
# probably want to arrange for at least one of them to be available on

12
SOURCES/00155-avoid-ctypes-thunks.patch

@ -1,7 +1,7 @@
diff -up Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 Python-3.2.3/Lib/ctypes/__init__.py diff -up Python-2.7.3/Lib/ctypes/__init__.py.rhbz814391 Python-2.7.3/Lib/ctypes/__init__.py
--- Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 2012-04-20 15:12:49.017867692 -0400 --- Python-2.7.3/Lib/ctypes/__init__.py.rhbz814391 2012-04-20 14:51:19.390990244 -0400
+++ Python-3.2.3/Lib/ctypes/__init__.py 2012-04-20 15:15:09.501111408 -0400 +++ Python-2.7.3/Lib/ctypes/__init__.py 2012-04-20 14:51:45.141668316 -0400
@@ -275,11 +275,6 @@ def _reset_cache(): @@ -272,11 +272,6 @@ def _reset_cache():
# _SimpleCData.c_char_p_from_param # _SimpleCData.c_char_p_from_param
POINTER(c_char).from_param = c_char_p.from_param POINTER(c_char).from_param = c_char_p.from_param
_pointer_type_cache[None] = c_void_p _pointer_type_cache[None] = c_void_p
@ -11,5 +11,5 @@ diff -up Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 Python-3.2.3/Lib/ctypes/
- # compiled with the MS SDK compiler. Or an uninitialized variable? - # compiled with the MS SDK compiler. Or an uninitialized variable?
- CFUNCTYPE(c_int)(lambda: None) - CFUNCTYPE(c_int)(lambda: None)
def create_unicode_buffer(init, size=None): try:
"""create_unicode_buffer(aString) -> character array from _ctypes import set_conversion_mode

105
SOURCES/00157-uid-gid-overflows.patch

@ -1,68 +1,49 @@
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py diff -up Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows Python-2.7.3/Lib/test/test_os.py
index e9fdb07..ea60e6e 100644 --- Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows 2012-04-09 19:07:32.000000000 -0400
--- a/Lib/test/test_os.py +++ Python-2.7.3/Lib/test/test_os.py 2012-06-26 14:51:36.000817929 -0400
+++ b/Lib/test/test_os.py @@ -677,30 +677,36 @@ if sys.platform != 'win32':
@@ -1723,30 +1723,36 @@ class PosixUidGidTests(unittest.TestCase): def test_setuid(self):
def test_setuid(self): if os.getuid() != 0:
if os.getuid() != 0: self.assertRaises(os.error, os.setuid, 0)
self.assertRaises(OSError, os.setuid, 0) + self.assertRaises(TypeError, os.setuid, 'not an int')
+ self.assertRaises(TypeError, os.setuid, 'not an int') self.assertRaises(OverflowError, os.setuid, 1<<32)
self.assertRaises(OverflowError, os.setuid, 1<<32)
@unittest.skipUnless(hasattr(os, 'setgid'), 'test needs os.setgid()') if hasattr(os, 'setgid'):
def test_setgid(self): def test_setgid(self):
if os.getuid() != 0 and not HAVE_WHEEL_GROUP: if os.getuid() != 0:
self.assertRaises(OSError, os.setgid, 0) self.assertRaises(os.error, os.setgid, 0)
+ self.assertRaises(TypeError, os.setgid, 'not an int') + self.assertRaises(TypeError, os.setgid, 'not an int')
self.assertRaises(OverflowError, os.setgid, 1<<32) self.assertRaises(OverflowError, os.setgid, 1<<32)
@unittest.skipUnless(hasattr(os, 'seteuid'), 'test needs os.seteuid()') if hasattr(os, 'seteuid'):
def test_seteuid(self): def test_seteuid(self):
if os.getuid() != 0: if os.getuid() != 0:
self.assertRaises(OSError, os.seteuid, 0) self.assertRaises(os.error, os.seteuid, 0)
+ self.assertRaises(TypeError, os.seteuid, 'not an int') + self.assertRaises(TypeError, os.seteuid, 'not an int')
self.assertRaises(OverflowError, os.seteuid, 1<<32) self.assertRaises(OverflowError, os.seteuid, 1<<32)
@unittest.skipUnless(hasattr(os, 'setegid'), 'test needs os.setegid()') if hasattr(os, 'setegid'):
def test_setegid(self): def test_setegid(self):
if os.getuid() != 0 and not HAVE_WHEEL_GROUP: if os.getuid() != 0:
self.assertRaises(OSError, os.setegid, 0) self.assertRaises(os.error, os.setegid, 0)
+ self.assertRaises(TypeError, os.setegid, 'not an int') + self.assertRaises(TypeError, os.setegid, 'not an int')
self.assertRaises(OverflowError, os.setegid, 1<<32) self.assertRaises(OverflowError, os.setegid, 1<<32)
@unittest.skipUnless(hasattr(os, 'setreuid'), 'test needs os.setreuid()') if hasattr(os, 'setreuid'):
def test_setreuid(self): def test_setreuid(self):
if os.getuid() != 0: if os.getuid() != 0:
self.assertRaises(OSError, os.setreuid, 0, 0) self.assertRaises(os.error, os.setreuid, 0, 0)
+ self.assertRaises(TypeError, os.setreuid, 'not an int', 0) + self.assertRaises(TypeError, os.setreuid, 'not an int', 0)
+ self.assertRaises(TypeError, os.setreuid, 0, 'not an int') + self.assertRaises(TypeError, os.setreuid, 0, 'not an int')
self.assertRaises(OverflowError, os.setreuid, 1<<32, 0) self.assertRaises(OverflowError, os.setreuid, 1<<32, 0)
self.assertRaises(OverflowError, os.setreuid, 0, 1<<32) self.assertRaises(OverflowError, os.setreuid, 0, 1<<32)
@@ -1762,6 +1768,8 @@ class PosixUidGidTests(unittest.TestCase): @@ -715,6 +721,8 @@ if sys.platform != 'win32':
def test_setregid(self): def test_setregid(self):
if os.getuid() != 0 and not HAVE_WHEEL_GROUP: if os.getuid() != 0:
self.assertRaises(OSError, os.setregid, 0, 0) self.assertRaises(os.error, os.setregid, 0, 0)
+ self.assertRaises(TypeError, os.setregid, 'not an int', 0) + self.assertRaises(TypeError, os.setregid, 'not an int', 0)
+ self.assertRaises(TypeError, os.setregid, 0, 'not an int') + self.assertRaises(TypeError, os.setregid, 0, 'not an int')
self.assertRaises(OverflowError, os.setregid, 1<<32, 0) self.assertRaises(OverflowError, os.setregid, 1<<32, 0)
self.assertRaises(OverflowError, os.setregid, 0, 1<<32) self.assertRaises(OverflowError, os.setregid, 0, 1<<32)
diff --git a/Lib/test/test_pwd.py b/Lib/test/test_pwd.py
index ac9cff7..db98159 100644
--- a/Lib/test/test_pwd.py
+++ b/Lib/test/test_pwd.py
@@ -104,11 +104,11 @@ class PwdTest(unittest.TestCase):
# In some cases, byuids isn't a complete list of all users in the
# system, so if we try to pick a value not in byuids (via a perturbing
# loop, say), pwd.getpwuid() might still be able to find data for that
- # uid. Using sys.maxint may provoke the same problems, but hopefully
+ # uid. Using 2**32 - 2 may provoke the same problems, but hopefully
# it will be a more repeatable failure.
# Android accepts a very large span of uids including sys.maxsize and
# -1; it raises KeyError with 1 or 2 for example.
- fakeuid = sys.maxsize
+ fakeuid = 2**32 - 2
self.assertNotIn(fakeuid, byuids)
if not support.is_android:
self.assertRaises(KeyError, pwd.getpwuid, fakeuid)

302
SOURCES/00170-gc-assertions.patch

@ -1,92 +1,33 @@
diff --git a/Include/object.h b/Include/object.h diff -up Python-2.7.3/Lib/test/test_gc.py.gc-assertions Python-2.7.3/Lib/test/test_gc.py
index 0c88603..e3413e8 100644 --- Python-2.7.3/Lib/test/test_gc.py.gc-assertions 2013-02-20 16:28:20.890536607 -0500
--- a/Include/object.h +++ Python-2.7.3/Lib/test/test_gc.py 2013-02-20 16:39:52.720489297 -0500
+++ b/Include/object.h @@ -1,6 +1,7 @@
@@ -1059,6 +1059,49 @@ PyAPI_FUNC(void)
_PyObject_DebugTypeStats(FILE *out);
#endif /* ifndef Py_LIMITED_API */
+/*
+ Define a pair of assertion macros.
+
+ These work like the regular C assert(), in that they will abort the
+ process with a message on stderr if the given condition fails to hold,
+ but compile away to nothing if NDEBUG is defined.
+
+ However, before aborting, Python will also try to call _PyObject_Dump() on
+ the given object. This may be of use when investigating bugs in which a
+ particular object is corrupt (e.g. buggy a tp_visit method in an extension
+ module breaking the garbage collector), to help locate the broken objects.
+
+ The WITH_MSG variant allows you to supply an additional message that Python
+ will attempt to print to stderr, after the object dump.
+*/
+#ifdef NDEBUG
+/* No debugging: compile away the assertions: */
+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0)
+#else
+/* With debugging: generate checks: */
+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) \
+ ((expr) \
+ ? (void)(0) \
+ : _PyObject_AssertFailed((obj), \
+ (msg), \
+ (__STRING(expr)), \
+ (__FILE__), \
+ (__LINE__), \
+ (__PRETTY_FUNCTION__)))
+#endif
+
+#define PyObject_ASSERT(obj, expr) \
+ PyObject_ASSERT_WITH_MSG(obj, expr, NULL)
+
+/*
+ Declare and define the entrypoint even when NDEBUG is defined, to avoid
+ causing compiler/linker errors when building extensions without NDEBUG
+ against a Python built with NDEBUG defined
+*/
+PyAPI_FUNC(void) _PyObject_AssertFailed(PyObject *, const char *,
+ const char *, const char *, int,
+ const char *);
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
index e727499..6efcafb 100644
--- a/Lib/test/test_gc.py
+++ b/Lib/test/test_gc.py
@@ -1,10 +1,11 @@
import unittest import unittest
from test.support import (verbose, refcount_test, run_unittest, -from test.test_support import verbose, run_unittest
strip_python_stderr, cpython_only, start_threads, +from test.test_support import verbose, run_unittest, import_module
- temp_dir, requires_type_collecting)
+ temp_dir, import_module, requires_type_collecting)
from test.support.script_helper import assert_python_ok, make_script
import sys import sys
+import sysconfig +import sysconfig
import time import time
import gc import gc
import weakref import weakref
@@ -50,6 +51,8 @@ class GC_Detector(object): @@ -32,6 +33,8 @@ class GC_Detector(object):
# gc collects it.
self.wr = weakref.ref(C1055820(666), it_happened) self.wr = weakref.ref(C1055820(666), it_happened)
+BUILD_WITH_NDEBUG = ('-DNDEBUG' in sysconfig.get_config_vars()['PY_CFLAGS'])
+BUILT_WITH_NDEBUG = ('-DNDEBUG' in sysconfig.get_config_vars()['PY_CFLAGS'])
+ +
@with_tp_del ### Tests
class Uncollectable(object): ###############################################################################
"""Create a reference cycle with multiple __del__ methods.
@@ -862,6 +865,50 @@ class GCCallbackTests(unittest.TestCase):
self.assertEqual(len(gc.garbage), 0)
@@ -476,6 +479,49 @@ class GCTests(unittest.TestCase):
# would be damaged, with an empty __dict__.
self.assertEqual(x, None)
+ @unittest.skipIf(BUILD_WITH_NDEBUG, + @unittest.skipIf(BUILT_WITH_NDEBUG,
+ 'built with -NDEBUG') + 'built with -NDEBUG')
+ def test_refcount_errors(self): + def test_refcount_errors(self):
+ self.preclean()
+ # Verify the "handling" of objects with broken refcounts + # Verify the "handling" of objects with broken refcounts
+
+ import_module("ctypes") #skip if not supported + import_module("ctypes") #skip if not supported
+ +
+ import subprocess + import subprocess
@ -112,59 +53,131 @@ index e727499..6efcafb 100644
+ p.stdout.close() + p.stdout.close()
+ p.stderr.close() + p.stderr.close()
+ # Verify that stderr has a useful error message: + # Verify that stderr has a useful error message:
+ self.assertRegex(stderr, + self.assertRegexpMatches(stderr,
+ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "\(\(gc\)->gc.gc_refs >> \(1\)\) != 0" failed.') + b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "gc->gc.gc_refs != 0" failed.')
+ self.assertRegex(stderr, + self.assertRegexpMatches(stderr,
+ b'refcount was too small') + b'refcount was too small')
+ self.assertRegex(stderr, + self.assertRegexpMatches(stderr,
+ b'object : \[\]') + b'object : \[\]')
+ self.assertRegex(stderr, + self.assertRegexpMatches(stderr,
+ b'type : list') + b'type : list')
+ self.assertRegex(stderr, + self.assertRegexpMatches(stderr,
+ b'refcount: 1') + b'refcount: 1')
+ self.assertRegex(stderr, + self.assertRegexpMatches(stderr,
+ b'address : 0x[0-9a-f]+') + b'address : 0x[0-9a-f]+')
+
+ +
class GCTogglingTests(unittest.TestCase): class GCTogglingTests(unittest.TestCase):
def setUp(self): def setUp(self):
gc.enable() gc.enable()
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c diff -up Python-2.7.3/Modules/gcmodule.c.gc-assertions Python-2.7.3/Modules/gcmodule.c
index 0c6f444..87edd5a 100644 --- Python-2.7.3/Modules/gcmodule.c.gc-assertions 2012-04-09 19:07:34.000000000 -0400
--- a/Modules/gcmodule.c +++ Python-2.7.3/Modules/gcmodule.c 2013-02-20 16:28:21.029536600 -0500
+++ b/Modules/gcmodule.c @@ -21,6 +21,73 @@
@@ -341,7 +341,8 @@ update_refs(PyGC_Head *containers) #include "Python.h"
#include "frameobject.h" /* for PyFrame_ClearFreeList */
+/*
+ Define a pair of assertion macros.
+
+ These work like the regular C assert(), in that they will abort the
+ process with a message on stderr if the given condition fails to hold,
+ but compile away to nothing if NDEBUG is defined.
+
+ However, before aborting, Python will also try to call _PyObject_Dump() on
+ the given object. This may be of use when investigating bugs in which a
+ particular object is corrupt (e.g. buggy a tp_visit method in an extension
+ module breaking the garbage collector), to help locate the broken objects.
+
+ The WITH_MSG variant allows you to supply an additional message that Python
+ will attempt to print to stderr, after the object dump.
+*/
+#ifdef NDEBUG
+/* No debugging: compile away the assertions: */
+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) ((void)0)
+#else
+/* With debugging: generate checks: */
+#define PyObject_ASSERT_WITH_MSG(obj, expr, msg) \
+ ((expr) \
+ ? (void)(0) \
+ : _PyObject_AssertFailed((obj), \
+ (msg), \
+ (__STRING(expr)), \
+ (__FILE__), \
+ (__LINE__), \
+ (__PRETTY_FUNCTION__)))
+#endif
+
+#define PyObject_ASSERT(obj, expr) \
+ PyObject_ASSERT_WITH_MSG(obj, expr, NULL)
+
+static void _PyObject_AssertFailed(PyObject *, const char *,
+ const char *, const char *, int,
+ const char *);
+
+static void
+_PyObject_AssertFailed(PyObject *obj, const char *msg, const char *expr,
+ const char *file, int line, const char *function)
+{
+ fprintf(stderr,
+ "%s:%d: %s: Assertion \"%s\" failed.\n",
+ file, line, function, expr);
+ if (msg) {
+ fprintf(stderr, "%s\n", msg);
+ }
+
+ fflush(stderr);
+
+ if (obj) {
+ /* This might succeed or fail, but we're about to abort, so at least
+ try to provide any extra info we can: */
+ _PyObject_Dump(obj);
+ }
+ else {
+ fprintf(stderr, "NULL object\n");
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+
+ /* Terminate the process: */
+ abort();
+}
+
/* Get an object's GC head */
#define AS_GC(o) ((PyGC_Head *)(o)-1)
@@ -288,7 +355,8 @@ update_refs(PyGC_Head *containers)
{ {
PyGC_Head *gc = containers->gc.gc_next; PyGC_Head *gc = containers->gc.gc_next;
for (; gc != containers; gc = gc->gc.gc_next) { for (; gc != containers; gc = gc->gc.gc_next) {
- assert(_PyGCHead_REFS(gc) == GC_REACHABLE); - assert(gc->gc.gc_refs == GC_REACHABLE);
+ PyObject_ASSERT(FROM_GC(gc), + PyObject_ASSERT(FROM_GC(gc),
+ _PyGCHead_REFS(gc) == GC_REACHABLE); + gc->gc.gc_refs == GC_REACHABLE);
_PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc))); gc->gc.gc_refs = Py_REFCNT(FROM_GC(gc));
/* Python's cyclic gc should never see an incoming refcount /* Python's cyclic gc should never see an incoming refcount
* of 0: if something decref'ed to 0, it should have been * of 0: if something decref'ed to 0, it should have been
@@ -361,7 +362,8 @@ update_refs(PyGC_Head *containers) @@ -308,7 +376,8 @@ update_refs(PyGC_Head *containers)
* so serious that maybe this should be a release-build * so serious that maybe this should be a release-build
* check instead of an assert? * check instead of an assert?
*/ */
- assert(_PyGCHead_REFS(gc) != 0); - assert(gc->gc.gc_refs != 0);
+ PyObject_ASSERT(FROM_GC(gc), + PyObject_ASSERT(FROM_GC(gc),
+ _PyGCHead_REFS(gc) != 0); + gc->gc.gc_refs != 0);
} }
} }
@@ -376,7 +378,9 @@ visit_decref(PyObject *op, void *data) @@ -323,7 +392,9 @@ visit_decref(PyObject *op, void *data)
* generation being collected, which can be recognized * generation being collected, which can be recognized
* because only they have positive gc_refs. * because only they have positive gc_refs.
*/ */
- assert(_PyGCHead_REFS(gc) != 0); /* else refcount was too small */ - assert(gc->gc.gc_refs != 0); /* else refcount was too small */
+ PyObject_ASSERT_WITH_MSG(FROM_GC(gc), + PyObject_ASSERT_WITH_MSG(FROM_GC(gc),
+ _PyGCHead_REFS(gc) != 0, + gc->gc.gc_refs != 0,
+ "refcount was too small"); /* else refcount was too small */ + "refcount was too small");
if (_PyGCHead_REFS(gc) > 0) if (gc->gc.gc_refs > 0)
_PyGCHead_DECREF(gc); gc->gc.gc_refs--;
} }
@@ -436,9 +440,10 @@ visit_reachable(PyObject *op, PyGC_Head *reachable) @@ -383,9 +454,10 @@ visit_reachable(PyObject *op, PyGC_Head
* If gc_refs == GC_UNTRACKED, it must be ignored. * If gc_refs == GC_UNTRACKED, it must be ignored.
*/ */
else { else {
@ -178,25 +191,26 @@ index 0c6f444..87edd5a 100644
} }
} }
return 0; return 0;
@@ -480,7 +485,7 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) @@ -427,7 +499,7 @@ move_unreachable(PyGC_Head *young, PyGC_
*/ */
PyObject *op = FROM_GC(gc); PyObject *op = FROM_GC(gc);
traverseproc traverse = Py_TYPE(op)->tp_traverse; traverseproc traverse = Py_TYPE(op)->tp_traverse;
- assert(_PyGCHead_REFS(gc) > 0); - assert(gc->gc.gc_refs > 0);
+ PyObject_ASSERT(op, _PyGCHead_REFS(gc) > 0); + PyObject_ASSERT(op, gc->gc.gc_refs > 0);
_PyGCHead_SET_REFS(gc, GC_REACHABLE); gc->gc.gc_refs = GC_REACHABLE;
(void) traverse(op, (void) traverse(op,
(visitproc)visit_reachable, (visitproc)visit_reachable,
@@ -543,7 +548,7 @@ move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) @@ -494,7 +566,8 @@ move_finalizers(PyGC_Head *unreachable,
for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) {
PyObject *op = FROM_GC(gc); PyObject *op = FROM_GC(gc);
- assert(IS_TENTATIVELY_UNREACHABLE(op)); - assert(IS_TENTATIVELY_UNREACHABLE(op));
+ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op)); + PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
+
next = gc->gc.gc_next; next = gc->gc.gc_next;
if (has_legacy_finalizer(op)) { if (has_finalizer(op)) {
@@ -619,7 +624,7 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) @@ -570,7 +643,7 @@ handle_weakrefs(PyGC_Head *unreachable,
PyWeakReference **wrlist; PyWeakReference **wrlist;
op = FROM_GC(gc); op = FROM_GC(gc);
@ -205,7 +219,7 @@ index 0c6f444..87edd5a 100644
next = gc->gc.gc_next; next = gc->gc.gc_next;
if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op))) if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
@@ -640,9 +645,9 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) @@ -591,9 +664,9 @@ handle_weakrefs(PyGC_Head *unreachable,
* the callback pointer intact. Obscure: it also * the callback pointer intact. Obscure: it also
* changes *wrlist. * changes *wrlist.
*/ */
@ -217,7 +231,7 @@ index 0c6f444..87edd5a 100644
if (wr->wr_callback == NULL) if (wr->wr_callback == NULL)
continue; /* no callback */ continue; /* no callback */
@@ -676,7 +681,7 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) @@ -627,7 +700,7 @@ handle_weakrefs(PyGC_Head *unreachable,
*/ */
if (IS_TENTATIVELY_UNREACHABLE(wr)) if (IS_TENTATIVELY_UNREACHABLE(wr))
continue; continue;
@ -226,7 +240,7 @@ index 0c6f444..87edd5a 100644
/* Create a new reference so that wr can't go away /* Create a new reference so that wr can't go away
* before we can process it again. * before we can process it again.
@@ -685,7 +690,8 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) @@ -636,7 +709,8 @@ handle_weakrefs(PyGC_Head *unreachable,
/* Move wr to wrcb_to_call, for the next pass. */ /* Move wr to wrcb_to_call, for the next pass. */
wrasgc = AS_GC(wr); wrasgc = AS_GC(wr);
@ -236,7 +250,7 @@ index 0c6f444..87edd5a 100644
next isn't, so they can't next isn't, so they can't
be the same */ be the same */
gc_list_move(wrasgc, &wrcb_to_call); gc_list_move(wrasgc, &wrcb_to_call);
@@ -701,11 +707,11 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) @@ -652,11 +726,11 @@ handle_weakrefs(PyGC_Head *unreachable,
gc = wrcb_to_call.gc.gc_next; gc = wrcb_to_call.gc.gc_next;
op = FROM_GC(gc); op = FROM_GC(gc);
@ -251,60 +265,12 @@ index 0c6f444..87edd5a 100644
/* copy-paste of weakrefobject.c's handle_callback() */ /* copy-paste of weakrefobject.c's handle_callback() */
temp = PyObject_CallFunctionObjArgs(callback, wr, NULL); temp = PyObject_CallFunctionObjArgs(callback, wr, NULL);
@@ -822,12 +828,14 @@ check_garbage(PyGC_Head *collectable) @@ -759,7 +833,7 @@ delete_garbage(PyGC_Head *collectable, P
for (gc = collectable->gc.gc_next; gc != collectable; PyGC_Head *gc = collectable->gc.gc_next;
gc = gc->gc.gc_next) { PyObject *op = FROM_GC(gc);
_PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc)));
- assert(_PyGCHead_REFS(gc) != 0);
+ PyObject_ASSERT(FROM_GC(gc),
+ _PyGCHead_REFS(gc) != 0);
}
subtract_refs(collectable);
for (gc = collectable->gc.gc_next; gc != collectable;
gc = gc->gc.gc_next) {
- assert(_PyGCHead_REFS(gc) >= 0);
+ PyObject_ASSERT(FROM_GC(gc),
+ _PyGCHead_REFS(gc) >= 0);
if (_PyGCHead_REFS(gc) != 0)
return -1;
}
diff --git a/Objects/object.c b/Objects/object.c
index 559794f..a47d47f 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2022,6 +2022,35 @@ _PyTrash_thread_destroy_chain(void)
}
}
+PyAPI_FUNC(void) - assert(IS_TENTATIVELY_UNREACHABLE(op));
+_PyObject_AssertFailed(PyObject *obj, const char *msg, const char *expr, + PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
+ const char *file, int line, const char *function) if (debug & DEBUG_SAVEALL) {
+{ PyList_Append(garbage, op);
+ fprintf(stderr, }
+ "%s:%d: %s: Assertion \"%s\" failed.\n",
+ file, line, function, expr);
+ if (msg) {
+ fprintf(stderr, "%s\n", msg);
+ }
+
+ fflush(stderr);
+
+ if (obj) {
+ /* This might succeed or fail, but we're about to abort, so at least
+ try to provide any extra info we can: */
+ _PyObject_Dump(obj);
+ }
+ else {
+ fprintf(stderr, "NULL object\n");
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+
+ /* Terminate the process: */
+ abort();
+}
+
#ifndef Py_TRACE_REFS
/* For Py_LIMITED_API, we need an out-of-line version of _Py_Dealloc.
Define this here, so we can undefine the macro. */

11
SOURCES/00180-python-add-support-for-ppc64p7.patch

@ -1,13 +1,12 @@
diff --git a/config.sub b/config.sub diff -r de35eae9048a config.sub
index 40ea5df..932128b 100755 --- a/config.sub Wed Apr 24 23:33:20 2013 +0200
--- a/config.sub +++ b/config.sub Thu Apr 25 08:51:00 2013 +0200
+++ b/config.sub @@ -1008,7 +1008,7 @@
@@ -1045,7 +1045,7 @@ case $basic_machine in
;; ;;
ppc64) basic_machine=powerpc64-unknown ppc64) basic_machine=powerpc64-unknown
;; ;;
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64le | powerpc64little) ppc64le | powerpc64little | ppc64-le | powerpc64-little)
basic_machine=powerpc64le-unknown basic_machine=powerpc64le-unknown

353
SOURCES/00209-pep466-backport-hmac.compare_digest.patch

@ -0,0 +1,353 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1399849904 25200
# Node ID b40f1a00b13460cc089450028280c4e52dd24a64
# Parent 951775c68b1b7782750c213b0fce1f61d46b2f51
backport hmac.compare_digest to partially implement PEP 466 (closes #21306)

Backport from Alex Gaynor.

diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst
--- a/Doc/library/hmac.rst
+++ b/Doc/library/hmac.rst
@@ -38,6 +38,13 @@ An HMAC object has the following methods
This string will be the same length as the *digest_size* of the digest given to
the constructor. It may contain non-ASCII characters, including NUL bytes.
+ .. warning::
+
+ When comparing the output of :meth:`digest` to an externally-supplied
+ digest during a verification routine, it is recommended to use the
+ :func:`compare_digest` function instead of the ``==`` operator
+ to reduce the vulnerability to timing attacks.
+
.. method:: HMAC.hexdigest()
@@ -45,6 +52,13 @@ An HMAC object has the following methods
containing only hexadecimal digits. This may be used to exchange the value
safely in email or other non-binary environments.
+ .. warning::
+
+ When comparing the output of :meth:`hexdigest` to an externally-supplied
+ digest during a verification routine, it is recommended to use the
+ :func:`compare_digest` function instead of the ``==`` operator
+ to reduce the vulnerability to timing attacks.
+
.. method:: HMAC.copy()
@@ -52,6 +66,25 @@ An HMAC object has the following methods
compute the digests of strings that share a common initial substring.
+This module also provides the following helper function:
+
+.. function:: compare_digest(a, b)
+
+ Return ``a == b``. This function uses an approach designed to prevent
+ timing analysis by avoiding content-based short circuiting behaviour,
+ making it appropriate for cryptography. *a* and *b* must both be of the
+ same type: either :class:`unicode` or a :term:`bytes-like object`.
+
+ .. note::
+
+ If *a* and *b* are of different lengths, or if an error occurs,
+ a timing attack could theoretically reveal information about the
+ types and lengths of *a* and *b*--but not their values.
+
+
+ .. versionadded:: 2.7.7
+
+
.. seealso::
Module :mod:`hashlib`
diff --git a/Lib/hmac.py b/Lib/hmac.py
--- a/Lib/hmac.py
+++ b/Lib/hmac.py
@@ -5,6 +5,9 @@ Implements the HMAC algorithm as describ
import warnings as _warnings
+from operator import _compare_digest as compare_digest
+
+
trans_5C = "".join ([chr (x ^ 0x5C) for x in xrange(256)])
trans_36 = "".join ([chr (x ^ 0x36) for x in xrange(256)])
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
--- a/Lib/test/test_hmac.py
+++ b/Lib/test/test_hmac.py
@@ -302,12 +302,122 @@ class CopyTestCase(unittest.TestCase):
self.assertTrue(h1.hexdigest() == h2.hexdigest(),
"Hexdigest of copy doesn't match original hexdigest.")
+
+class CompareDigestTestCase(unittest.TestCase):
+
+ def test_compare_digest(self):
+ # Testing input type exception handling
+ a, b = 100, 200
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = 100, b"foobar"
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = b"foobar", 200
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = u"foobar", b"foobar"
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = b"foobar", u"foobar"
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+
+ # Testing bytes of different lengths
+ a, b = b"foobar", b"foo"
+ self.assertFalse(hmac.compare_digest(a, b))
+ a, b = b"\xde\xad\xbe\xef", b"\xde\xad"
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ # Testing bytes of same lengths, different values
+ a, b = b"foobar", b"foobaz"
+ self.assertFalse(hmac.compare_digest(a, b))
+ a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea"
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ # Testing bytes of same lengths, same values
+ a, b = b"foobar", b"foobar"
+ self.assertTrue(hmac.compare_digest(a, b))
+ a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef"
+ self.assertTrue(hmac.compare_digest(a, b))
+
+ # Testing bytearrays of same lengths, same values
+ a, b = bytearray(b"foobar"), bytearray(b"foobar")
+ self.assertTrue(hmac.compare_digest(a, b))
+
+ # Testing bytearrays of diffeent lengths
+ a, b = bytearray(b"foobar"), bytearray(b"foo")
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ # Testing bytearrays of same lengths, different values
+ a, b = bytearray(b"foobar"), bytearray(b"foobaz")
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ # Testing byte and bytearray of same lengths, same values
+ a, b = bytearray(b"foobar"), b"foobar"
+ self.assertTrue(hmac.compare_digest(a, b))
+ self.assertTrue(hmac.compare_digest(b, a))
+
+ # Testing byte bytearray of diffeent lengths
+ a, b = bytearray(b"foobar"), b"foo"
+ self.assertFalse(hmac.compare_digest(a, b))
+ self.assertFalse(hmac.compare_digest(b, a))
+
+ # Testing byte and bytearray of same lengths, different values
+ a, b = bytearray(b"foobar"), b"foobaz"
+ self.assertFalse(hmac.compare_digest(a, b))
+ self.assertFalse(hmac.compare_digest(b, a))
+
+ # Testing str of same lengths
+ a, b = "foobar", "foobar"
+ self.assertTrue(hmac.compare_digest(a, b))
+
+ # Testing str of diffeent lengths
+ a, b = "foo", "foobar"
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ # Testing bytes of same lengths, different values
+ a, b = "foobar", "foobaz"
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ # Testing error cases
+ a, b = u"foobar", b"foobar"
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = b"foobar", u"foobar"
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = b"foobar", 1
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = 100, 200
+ self.assertRaises(TypeError, hmac.compare_digest, a, b)
+ a, b = "fooä", "fooä"
+ self.assertTrue(hmac.compare_digest(a, b))
+
+ # subclasses are supported by ignore __eq__
+ class mystr(str):
+ def __eq__(self, other):
+ return False
+
+ a, b = mystr("foobar"), mystr("foobar")
+ self.assertTrue(hmac.compare_digest(a, b))
+ a, b = mystr("foobar"), "foobar"
+ self.assertTrue(hmac.compare_digest(a, b))
+ a, b = mystr("foobar"), mystr("foobaz")
+ self.assertFalse(hmac.compare_digest(a, b))
+
+ class mybytes(bytes):
+ def __eq__(self, other):
+ return False
+
+ a, b = mybytes(b"foobar"), mybytes(b"foobar")
+ self.assertTrue(hmac.compare_digest(a, b))
+ a, b = mybytes(b"foobar"), b"foobar"
+ self.assertTrue(hmac.compare_digest(a, b))
+ a, b = mybytes(b"foobar"), mybytes(b"foobaz")
+ self.assertFalse(hmac.compare_digest(a, b))
+
+
def test_main():
test_support.run_unittest(
TestVectorsTestCase,
ConstructorTestCase,
SanityTestCase,
- CopyTestCase
+ CopyTestCase,
+ CompareDigestTestCase,
)
if __name__ == "__main__":
diff --git a/Modules/operator.c b/Modules/operator.c
--- a/Modules/operator.c
+++ b/Modules/operator.c
@@ -235,6 +235,132 @@ op_delslice(PyObject *s, PyObject *a)
#define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \
{#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)},
+
+
+/* compare_digest **********************************************************/
+
+/*
+ * timing safe compare
+ *
+ * Returns 1 of the strings are equal.
+ * In case of len(a) != len(b) the function tries to keep the timing
+ * dependent on the length of b. CPU cache locally may still alter timing
+ * a bit.
+ */
+static int
+_tscmp(const unsigned char *a, const unsigned char *b,
+ Py_ssize_t len_a, Py_ssize_t len_b)
+{
+ /* The volatile type declarations make sure that the compiler has no
+ * chance to optimize and fold the code in any way that may change
+ * the timing.
+ */
+ volatile Py_ssize_t length;
+ volatile const unsigned char *left;
+ volatile const unsigned char *right;
+ Py_ssize_t i;
+ unsigned char result;
+
+ /* loop count depends on length of b */
+ length = len_b;
+ left = NULL;
+ right = b;
+
+ /* don't use else here to keep the amount of CPU instructions constant,
+ * volatile forces re-evaluation
+ * */
+ if (len_a == length) {
+ left = *((volatile const unsigned char**)&a);
+ result = 0;
+ }
+ if (len_a != length) {
+ left = b;
+ result = 1;
+ }
+
+ for (i=0; i < length; i++) {
+ result |= *left++ ^ *right++;
+ }
+
+ return (result == 0);
+}
+
+PyDoc_STRVAR(compare_digest__doc__,
+"compare_digest(a, b) -> bool\n"
+"\n"
+"Return 'a == b'. This function uses an approach designed to prevent\n"
+"timing analysis, making it appropriate for cryptography.\n"
+"a and b must both be of the same type: either str (ASCII only),\n"
+"or any type that supports the buffer protocol (e.g. bytes).\n"
+"\n"
+"Note: If a and b are of different lengths, or if an error occurs,\n"
+"a timing attack could theoretically reveal information about the\n"
+"types and lengths of a and b--but not their values.\n");
+
+static PyObject*
+compare_digest(PyObject *self, PyObject *args)
+{
+ PyObject *a, *b;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "OO:compare_digest", &a, &b)) {
+ return NULL;
+ }
+
+ /* Unicode string */
+ if (PyUnicode_Check(a) && PyUnicode_Check(b)) {
+ rc = _tscmp(PyUnicode_AS_DATA(a),
+ PyUnicode_AS_DATA(b),
+ PyUnicode_GET_DATA_SIZE(a),
+ PyUnicode_GET_DATA_SIZE(b));
+ }
+ /* fallback to buffer interface for bytes, bytesarray and other */
+ else {
+ Py_buffer view_a;
+ Py_buffer view_b;
+
+ if ((PyObject_CheckBuffer(a) == 0) & (PyObject_CheckBuffer(b) == 0)) {
+ PyErr_Format(PyExc_TypeError,
+ "unsupported operand types(s) or combination of types: "
+ "'%.100s' and '%.100s'",
+ Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name);
+ return NULL;
+ }
+
+ if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) {
+ return NULL;
+ }
+ if (view_a.ndim > 1) {
+ PyErr_SetString(PyExc_BufferError,
+ "Buffer must be single dimension");
+ PyBuffer_Release(&view_a);
+ return NULL;
+ }
+
+ if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) {
+ PyBuffer_Release(&view_a);
+ return NULL;
+ }
+ if (view_b.ndim > 1) {
+ PyErr_SetString(PyExc_BufferError,
+ "Buffer must be single dimension");
+ PyBuffer_Release(&view_a);
+ PyBuffer_Release(&view_b);
+ return NULL;
+ }
+
+ rc = _tscmp((const unsigned char*)view_a.buf,
+ (const unsigned char*)view_b.buf,
+ view_a.len,
+ view_b.len);
+
+ PyBuffer_Release(&view_a);
+ PyBuffer_Release(&view_b);
+ }
+
+ return PyBool_FromLong(rc);
+}
+
static struct PyMethodDef operator_methods[] = {
spam1o(isCallable,
@@ -318,6 +444,8 @@ spam2(ne,__ne__, "ne(a, b) -- Same as a!
spam2(gt,__gt__, "gt(a, b) -- Same as a>b.")
spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.")
+ {"_compare_digest", (PyCFunction)compare_digest, METH_VARARGS,
+ compare_digest__doc__},
{NULL, NULL} /* sentinel */
};

489
SOURCES/00210-pep466-backport-hashlib.pbkdf2_hmac.patch

@ -0,0 +1,489 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1401567982 25200
# Node ID e4da3ba9dcac4374ca0ccc46a48c32be6f951038
# Parent 8fa8c290c165dccd613632b69a816623b51e801e
backport hashlib.pbkdf2_hmac per PEP 466 (closes #21304)

Backport by Alex Gaynor.

diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst
--- a/Doc/library/hashlib.rst
+++ b/Doc/library/hashlib.rst
@@ -135,6 +135,46 @@ A hash object has the following methods:
compute the digests of strings that share a common initial substring.
+Key Derivation Function
+-----------------------
+
+Key derivation and key stretching algorithms are designed for secure password
+hashing. Naive algorithms such as ``sha1(password)`` are not resistant against
+brute-force attacks. A good password hashing function must be tunable, slow, and
+include a `salt <https://en.wikipedia.org/wiki/Salt_%28cryptography%29>`_.
+
+
+.. function:: pbkdf2_hmac(name, password, salt, rounds, dklen=None)
+
+ The function provides PKCS#5 password-based key derivation function 2. It
+ uses HMAC as pseudorandom function.
+
+ The string *name* is the desired name of the hash digest algorithm for
+ HMAC, e.g. 'sha1' or 'sha256'. *password* and *salt* are interpreted as
+ buffers of bytes. Applications and libraries should limit *password* to
+ a sensible value (e.g. 1024). *salt* should be about 16 or more bytes from
+ a proper source, e.g. :func:`os.urandom`.
+
+ The number of *rounds* should be chosen based on the hash algorithm and
+ computing power. As of 2013, at least 100,000 rounds of SHA-256 is suggested.
+
+ *dklen* is the length of the derived key. If *dklen* is ``None`` then the
+ digest size of the hash algorithm *name* is used, e.g. 64 for SHA-512.
+
+ >>> import hashlib, binascii
+ >>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000)
+ >>> binascii.hexlify(dk)
+ b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'
+
+ .. versionadded:: 2.7.8
+
+ .. note::
+
+ A fast implementation of *pbkdf2_hmac* is available with OpenSSL. The
+ Python implementation uses an inline version of :mod:`hmac`. It is about
+ three times slower and doesn't release the GIL.
+
+
.. seealso::

Module :mod:`hmac`
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
--- a/Lib/hashlib.py
+++ b/Lib/hashlib.py
@@ -77,7 +77,7 @@ __always_supported = ('md5', 'sha1', 'sh
algorithms = __always_supported
-__all__ = __always_supported + ('new', 'algorithms')
+__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac')
def __get_openssl_constructor(name):
@@ -123,6 +123,72 @@ for __func_name in __always_supported:
import logging
logging.exception('code for hash %s was not found.', __func_name)
+try:
+ # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
+ from _hashlib import pbkdf2_hmac
+except ImportError:
+ import binascii
+ import struct
+
+ _trans_5C = b"".join(chr(x ^ 0x5C) for x in range(256))
+ _trans_36 = b"".join(chr(x ^ 0x36) for x in range(256))
+
+ def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
+ """Password based key derivation function 2 (PKCS #5 v2.0)
+
+ This Python implementations based on the hmac module about as fast
+ as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
+ for long passwords.
+ """
+ if not isinstance(hash_name, str):
+ raise TypeError(hash_name)
+
+ if not isinstance(password, (bytes, bytearray)):
+ password = bytes(buffer(password))
+ if not isinstance(salt, (bytes, bytearray)):
+ salt = bytes(buffer(salt))
+
+ # Fast inline HMAC implementation
+ inner = new(hash_name)
+ outer = new(hash_name)
+ blocksize = getattr(inner, 'block_size', 64)
+ if len(password) > blocksize:
+ password = new(hash_name, password).digest()
+ password = password + b'\x00' * (blocksize - len(password))
+ inner.update(password.translate(_trans_36))
+ outer.update(password.translate(_trans_5C))
+
+ def prf(msg, inner=inner, outer=outer):
+ # PBKDF2_HMAC uses the password as key. We can re-use the same
+ # digest objects and and just update copies to skip initialization.
+ icpy = inner.copy()
+ ocpy = outer.copy()
+ icpy.update(msg)
+ ocpy.update(icpy.digest())
+ return ocpy.digest()
+
+ if iterations < 1:
+ raise ValueError(iterations)
+ if dklen is None:
+ dklen = outer.digest_size
+ if dklen < 1:
+ raise ValueError(dklen)
+
+ hex_format_string = "%%0%ix" % (new(hash_name).digest_size * 2)
+
+ dkey = b''
+ loop = 1
+ while len(dkey) < dklen:
+ prev = prf(salt + struct.pack(b'>I', loop))
+ rkey = int(binascii.hexlify(prev), 16)
+ for i in xrange(iterations - 1):
+ prev = prf(prev)
+ rkey ^= int(binascii.hexlify(prev), 16)
+ loop += 1
+ dkey += binascii.unhexlify(hex_format_string % rkey)
+
+ return dkey[:dklen]
+
# Cleanup locals()
del __always_supported, __func_name, __get_hash
del __hash_new, __get_openssl_constructor
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -16,6 +16,8 @@ except ImportError:
threading = None
import unittest
import warnings
+from binascii import unhexlify
+
from test import test_support
from test.test_support import _4G, precisionbigmemtest
@@ -436,8 +438,72 @@ class HashLibTestCase(unittest.TestCase)
+class KDFTests(unittest.TestCase):
+ pbkdf2_test_vectors = [
+ (b'password', b'salt', 1, None),
+ (b'password', b'salt', 2, None),
+ (b'password', b'salt', 4096, None),
+ # too slow, it takes over a minute on a fast CPU.
+ #(b'password', b'salt', 16777216, None),
+ (b'passwordPASSWORDpassword', b'saltSALTsaltSALTsaltSALTsaltSALTsalt',
+ 4096, -1),
+ (b'pass\0word', b'sa\0lt', 4096, 16),
+ ]
+
+ pbkdf2_results = {
+ "sha1": [
+ # offical test vectors from RFC 6070
+ (unhexlify('0c60c80f961f0e71f3a9b524af6012062fe037a6'), None),
+ (unhexlify('ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'), None),
+ (unhexlify('4b007901b765489abead49d926f721d065a429c1'), None),
+ #(unhexlify('eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'), None),
+ (unhexlify('3d2eec4fe41c849b80c8d83662c0e44a8b291a964c'
+ 'f2f07038'), 25),
+ (unhexlify('56fa6aa75548099dcc37d7f03425e0c3'), None),],
+ "sha256": [
+ (unhexlify('120fb6cffcf8b32c43e7225256c4f837'
+ 'a86548c92ccc35480805987cb70be17b'), None),
+ (unhexlify('ae4d0c95af6b46d32d0adff928f06dd0'
+ '2a303f8ef3c251dfd6e2d85a95474c43'), None),
+ (unhexlify('c5e478d59288c841aa530db6845c4c8d'
+ '962893a001ce4e11a4963873aa98134a'), None),
+ #(unhexlify('cf81c66fe8cfc04d1f31ecb65dab4089'
+ # 'f7f179e89b3b0bcb17ad10e3ac6eba46'), None),
+ (unhexlify('348c89dbcbd32b2f32d814b8116e84cf2b17'
+ '347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9'), 40),
+ (unhexlify('89b69d0516f829893c696226650a8687'), None),],
+ "sha512": [
+ (unhexlify('867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5'
+ 'd513554e1c8cf252c02d470a285a0501bad999bfe943c08f'
+ '050235d7d68b1da55e63f73b60a57fce'), None),
+ (unhexlify('e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f004071'
+ '3f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82'
+ 'be67335c77a6068e04112754f27ccf4e'), None),
+ (unhexlify('d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f8'
+ '7f6902e072f457b5143f30602641b3d55cd335988cb36b84'
+ '376060ecd532e039b742a239434af2d5'), None),
+ (unhexlify('8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b8'
+ '68c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30'
+ '225c583a186cd82bd4daea9724a3d3b8'), 64),
+ (unhexlify('9d9e9c4cd21fe4be24d5b8244c759665'), None),],
+ }
+
+ def test_pbkdf2_hmac(self):
+ for digest_name, results in self.pbkdf2_results.items():
+ for i, vector in enumerate(self.pbkdf2_test_vectors):
+ password, salt, rounds, dklen = vector
+ expected, overwrite_dklen = results[i]
+ if overwrite_dklen:
+ dklen = overwrite_dklen
+ out = hashlib.pbkdf2_hmac(
+ digest_name, password, salt, rounds, dklen)
+ self.assertEqual(out, expected,
+ (digest_name, password, salt, rounds, dklen))
+
+
+
def test_main():
- test_support.run_unittest(HashLibTestCase)
+ test_support.run_unittest(HashLibTestCase, KDFTests)
if __name__ == "__main__":
test_main()
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -39,6 +39,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/hmac.h>
#define MUNCH_SIZE INT_MAX
@@ -563,6 +564,226 @@ EVP_new(PyObject *self, PyObject *args,
return ret_obj;
}
+
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10000000 && !defined(OPENSSL_NO_HMAC) \
+ && !defined(OPENSSL_NO_SHA))
+
+#define PY_PBKDF2_HMAC 1
+
+/* Improved implementation of PKCS5_PBKDF2_HMAC()
+ *
+ * PKCS5_PBKDF2_HMAC_fast() hashes the password exactly one time instead of
+ * `iter` times. Today (2013) the iteration count is typically 100,000 or
+ * more. The improved algorithm is not subject to a Denial-of-Service
+ * vulnerability with overly large passwords.
+ *
+ * Also OpenSSL < 1.0 don't provide PKCS5_PBKDF2_HMAC(), only
+ * PKCS5_PBKDF2_SHA1.
+ */
+static int
+PKCS5_PBKDF2_HMAC_fast(const char *pass, int passlen,
+ const unsigned char *salt, int saltlen,
+ int iter, const EVP_MD *digest,
+ int keylen, unsigned char *out)
+{
+ unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
+ int cplen, j, k, tkeylen, mdlen;
+ unsigned long i = 1;
+ HMAC_CTX hctx_tpl, hctx;
+
+ mdlen = EVP_MD_size(digest);
+ if (mdlen < 0)
+ return 0;
+
+ HMAC_CTX_init(&hctx_tpl);
+ HMAC_CTX_init(&hctx);
+ p = out;
+ tkeylen = keylen;
+ if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 0;
+ }
+ while(tkeylen) {
+ if(tkeylen > mdlen)
+ cplen = mdlen;
+ else
+ cplen = tkeylen;
+ /* We are unlikely to ever use more than 256 blocks (5120 bits!)
+ * but just in case...
+ */
+ itmp[0] = (unsigned char)((i >> 24) & 0xff);
+ itmp[1] = (unsigned char)((i >> 16) & 0xff);
+ itmp[2] = (unsigned char)((i >> 8) & 0xff);
+ itmp[3] = (unsigned char)(i & 0xff);
+ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 0;
+ }
+ if (!HMAC_Update(&hctx, salt, saltlen)
+ || !HMAC_Update(&hctx, itmp, 4)
+ || !HMAC_Final(&hctx, digtmp, NULL)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ HMAC_CTX_cleanup(&hctx);
+ return 0;
+ }
+ HMAC_CTX_cleanup(&hctx);
+ memcpy(p, digtmp, cplen);
+ for (j = 1; j < iter; j++) {
+ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 0;
+ }
+ if (!HMAC_Update(&hctx, digtmp, mdlen)
+ || !HMAC_Final(&hctx, digtmp, NULL)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ HMAC_CTX_cleanup(&hctx);
+ return 0;
+ }
+ HMAC_CTX_cleanup(&hctx);
+ for (k = 0; k < cplen; k++) {
+ p[k] ^= digtmp[k];
+ }
+ }
+ tkeylen-= cplen;
+ i++;
+ p+= cplen;
+ }
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 1;
+}
+
+/* LCOV_EXCL_START */
+static PyObject *
+_setException(PyObject *exc)
+{
+ unsigned long errcode;
+ const char *lib, *func, *reason;
+
+ errcode = ERR_peek_last_error();
+ if (!errcode) {
+ PyErr_SetString(exc, "unknown reasons");
+ return NULL;
+ }
+ ERR_clear_error();
+
+ lib = ERR_lib_error_string(errcode);
+ func = ERR_func_error_string(errcode);
+ reason = ERR_reason_error_string(errcode);
+
+ if (lib && func) {
+ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason);
+ }
+ else if (lib) {
+ PyErr_Format(exc, "[%s] %s", lib, reason);
+ }
+ else {
+ PyErr_SetString(exc, reason);
+ }
+ return NULL;
+}
+/* LCOV_EXCL_STOP */
+
+PyDoc_STRVAR(pbkdf2_hmac__doc__,
+"pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) -> key\n\
+\n\
+Password based key derivation function 2 (PKCS #5 v2.0) with HMAC as\n\
+pseudorandom function.");
+
+static PyObject *
+pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)
+{
+ static char *kwlist[] = {"hash_name", "password", "salt", "iterations",
+ "dklen", NULL};
+ PyObject *key_obj = NULL, *dklen_obj = Py_None;
+ char *name, *key;
+ Py_buffer password, salt;
+ long iterations, dklen;
+ int retval;
+ const EVP_MD *digest;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ss*s*l|O:pbkdf2_hmac",
+ kwlist, &name, &password, &salt,
+ &iterations, &dklen_obj)) {
+ return NULL;
+ }
+
+ digest = EVP_get_digestbyname(name);
+ if (digest == NULL) {
+ PyErr_SetString(PyExc_ValueError, "unsupported hash type");
+ goto end;
+ }
+
+ if (password.len > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "password is too long.");
+ goto end;
+ }
+
+ if (salt.len > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "salt is too long.");
+ goto end;
+ }
+
+ if (iterations < 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "iteration value must be greater than 0.");
+ goto end;
+ }
+ if (iterations > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "iteration value is too great.");
+ goto end;
+ }
+
+ if (dklen_obj == Py_None) {
+ dklen = EVP_MD_size(digest);
+ } else {
+ dklen = PyLong_AsLong(dklen_obj);
+ if ((dklen == -1) && PyErr_Occurred()) {
+ goto end;
+ }
+ }
+ if (dklen < 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "key length must be greater than 0.");
+ goto end;
+ }
+ if (dklen > INT_MAX) {
+ /* INT_MAX is always smaller than dkLen max (2^32 - 1) * hLen */
+ PyErr_SetString(PyExc_OverflowError,
+ "key length is too great.");
+ goto end;
+ }
+
+ key_obj = PyBytes_FromStringAndSize(NULL, dklen);
+ if (key_obj == NULL) {
+ goto end;
+ }
+ key = PyBytes_AS_STRING(key_obj);
+
+ Py_BEGIN_ALLOW_THREADS
+ retval = PKCS5_PBKDF2_HMAC_fast((char*)password.buf, (int)password.len,
+ (unsigned char *)salt.buf, (int)salt.len,
+ iterations, digest, dklen,
+ (unsigned char *)key);
+ Py_END_ALLOW_THREADS
+
+ if (!retval) {
+ Py_CLEAR(key_obj);
+ _setException(PyExc_ValueError);
+ goto end;
+ }
+
+ end:
+ PyBuffer_Release(&password);
+ PyBuffer_Release(&salt);
+ return key_obj;
+}
+
+#endif
+
/*
* This macro and function generates a family of constructor function
* definitions for specific hash algorithms. These constructors are much
@@ -690,6 +911,10 @@ static struct PyMethodDef EVP_functions[
CONSTRUCTOR_METH_DEF(sha384),
CONSTRUCTOR_METH_DEF(sha512),
#endif
+#ifdef PY_PBKDF2_HMAC
+ {"pbkdf2_hmac", (PyCFunction)pbkdf2_hmac, METH_VARARGS|METH_KEYWORDS,
+ pbkdf2_hmac__doc__},
+#endif
{NULL, NULL} /* Sentinel */
};
diff -up Python-2.7.5/Lib/test/test_hmac.py.cod Python-2.7.5/Lib/test/test_hmac.py
--- Python-2.7.5/Lib/test/test_hmac.py.cod 2015-02-23 10:37:13.448594606 +0100
+++ Python-2.7.5/Lib/test/test_hmac.py 2015-02-23 10:37:27.581717509 +0100
@@ -1,3 +1,5 @@
+# coding: utf-8
+
import hmac
import hashlib
import unittest

67
SOURCES/00211-pep466-UTF-7-decoder-fix-illegal-unicode.patch

@ -0,0 +1,67 @@

# HG changeset patch
# User Serhiy Storchaka <storchaka@gmail.com>
# Date 1382204269 -10800
# Node ID 214c0aac7540947d88a38ff0061734547ef86710
# Parent c207ac413457a1b834e4b7dcf1a6836cd6e036e3
Issue #19279: UTF-7 decoder no more produces illegal unicode strings.

diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -611,6 +611,35 @@ class UTF7Test(ReadTest):
]
)
+ def test_errors(self):
+ tests = [
+ ('a\xffb', u'a\ufffdb'),
+ ('a+IK', u'a\ufffd'),
+ ('a+IK-b', u'a\ufffdb'),
+ ('a+IK,b', u'a\ufffdb'),
+ ('a+IKx', u'a\u20ac\ufffd'),
+ ('a+IKx-b', u'a\u20ac\ufffdb'),
+ ('a+IKwgr', u'a\u20ac\ufffd'),
+ ('a+IKwgr-b', u'a\u20ac\ufffdb'),
+ ('a+IKwgr,', u'a\u20ac\ufffd'),
+ ('a+IKwgr,-b', u'a\u20ac\ufffd-b'),
+ ('a+IKwgrB', u'a\u20ac\u20ac\ufffd'),
+ ('a+IKwgrB-b', u'a\u20ac\u20ac\ufffdb'),
+ ('a+/,+IKw-b', u'a\ufffd\u20acb'),
+ ('a+//,+IKw-b', u'a\ufffd\u20acb'),
+ ('a+///,+IKw-b', u'a\uffff\ufffd\u20acb'),
+ ('a+////,+IKw-b', u'a\uffff\ufffd\u20acb'),
+ ]
+ for raw, expected in tests:
+ self.assertRaises(UnicodeDecodeError, codecs.utf_7_decode,
+ raw, 'strict', True)
+ self.assertEqual(raw.decode('utf-7', 'replace'), expected)
+
+ def test_nonbmp(self):
+ self.assertEqual(u'\U000104A0'.encode(self.encoding), '+2AHcoA-')
+ self.assertEqual(u'\ud801\udca0'.encode(self.encoding), '+2AHcoA-')
+ self.assertEqual('+2AHcoA-'.decode(self.encoding), u'\U000104A0')
+
class UTF16ExTest(unittest.TestCase):
def test_errors(self):
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -1671,6 +1671,7 @@ PyObject *PyUnicode_DecodeUTF7Stateful(c
(base64buffer >> (base64bits-16));
base64bits -= 16;
base64buffer &= (1 << base64bits) - 1; /* clear high bits */
+ assert(outCh <= 0xffff);
if (surrogate) {
/* expecting a second surrogate */
if (outCh >= 0xDC00 && outCh <= 0xDFFF) {
@@ -1737,6 +1738,7 @@ PyObject *PyUnicode_DecodeUTF7Stateful(c
inShift = 1;
shiftOutStart = p;
base64bits = 0;
+ base64buffer = 0;
}
}
else if (DECODE_DIRECT(ch)) { /* character decodes as itself */

40
SOURCES/00212-pep466-pyunicode_fromformat-raise-overflow.patch

@ -0,0 +1,40 @@

# HG changeset patch
# User Serhiy Storchaka <storchaka@gmail.com>
# Date 1372008129 -10800
# Node ID 2f1e8b7fa534b147280fdc9b92e44a7c7305338a
# Parent 8f0adcb66633ee97e4f7bdeee2104268113b86c3
Issue #18184: PyUnicode_FromFormat() and PyUnicode_FromFormatV() now raise
OverflowError when an argument of %c format is out of range.

diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -740,8 +740,25 @@ PyUnicode_FromFormatV(const char *format
switch (*f) {
case 'c':
- (void)va_arg(count, int);
+ {
+ int ordinal = va_arg(count, int);
+#ifdef Py_UNICODE_WIDE
+ if (ordinal < 0 || ordinal > 0x10ffff) {
+ PyErr_SetString(PyExc_OverflowError,
+ "%c arg not in range(0x110000) "
+ "(wide Python build)");
+ goto fail;
+ }
+#else
+ if (ordinal < 0 || ordinal > 0xffff) {
+ PyErr_SetString(PyExc_OverflowError,
+ "%c arg not in range(0x10000) "
+ "(narrow Python build)");
+ goto fail;
+ }
+#endif
/* fall through... */
+ }
case '%':
n++;
break;

176
SOURCES/00213-pep466-pyunicode_fromformat-fix-formats.patch

@ -0,0 +1,176 @@

# HG changeset patch
# User Victor Stinner <victor.stinner@gmail.com>
# Date 1406673545 -7200
# Node ID 263701e0b77e3160bc6a835087f838bd6b24092a
# Parent 6c47c6d2033e20e9b35f1d22e0e797961d6e680f
Issue #22023: Fix %S, %R and %V formats of PyUnicode_FromFormat().

diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -690,7 +690,12 @@ makefmt(char *fmt, int longflag, int siz
*fmt = '\0';
}
-#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;}
+#define appendstring(string) \
+ do { \
+ for (copy = string;*copy; copy++) { \
+ *s++ = (unsigned char)*copy; \
+ } \
+ } while (0)
PyObject *
PyUnicode_FromFormatV(const char *format, va_list vargs)
@@ -845,7 +850,7 @@ PyUnicode_FromFormatV(const char *format
str = PyObject_Str(obj);
if (!str)
goto fail;
- n += PyUnicode_GET_SIZE(str);
+ n += PyString_GET_SIZE(str);
/* Remember the str and switch to the next slot */
*callresult++ = str;
break;
@@ -1006,15 +1011,10 @@ PyUnicode_FromFormatV(const char *format
case 'S':
case 'R':
{
- Py_UNICODE *ucopy;
- Py_ssize_t usize;
- Py_ssize_t upos;
+ const char *str = PyString_AS_STRING(*callresult);
/* unused, since we already have the result */
(void) va_arg(vargs, PyObject *);
- ucopy = PyUnicode_AS_UNICODE(*callresult);
- usize = PyUnicode_GET_SIZE(*callresult);
- for (upos = 0; upos<usize;)
- *s++ = ucopy[upos++];
+ appendstring(str);
/* We're done with the unicode()/repr() => forget it */
Py_DECREF(*callresult);
/* switch to next unicode()/repr() result */

diff -up Python-2.7.5/Lib/test/test_unicode.py.uni Python-2.7.5/Lib/test/test_unicode.py
--- Python-2.7.5/Lib/test/test_unicode.py.uni 2015-02-24 13:37:01.704739438 +0100
+++ Python-2.7.5/Lib/test/test_unicode.py 2015-02-24 13:38:38.439482167 +0100
@@ -1633,6 +1633,119 @@ class UnicodeTest(
self.assertEqual("%s" % u, u'__unicode__ overridden')
self.assertEqual("{}".format(u), '__unicode__ overridden')
+ # Test PyUnicode_FromFormat()
+ def test_from_format(self):
+ test_support.import_module('ctypes')
+ from ctypes import (
+ pythonapi, py_object, sizeof,
+ c_int, c_long, c_longlong, c_ssize_t,
+ c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p)
+ if sys.maxunicode == 0xffff:
+ name = "PyUnicodeUCS2_FromFormat"
+ else:
+ name = "PyUnicodeUCS4_FromFormat"
+ _PyUnicode_FromFormat = getattr(pythonapi, name)
+ _PyUnicode_FromFormat.restype = py_object
+
+ def PyUnicode_FromFormat(format, *args):
+ cargs = tuple(
+ py_object(arg) if isinstance(arg, unicode) else arg
+ for arg in args)
+ return _PyUnicode_FromFormat(format, *cargs)
+
+ def check_format(expected, format, *args):
+ text = PyUnicode_FromFormat(format, *args)
+ self.assertEqual(expected, text)
+
+ # ascii format, non-ascii argument
+ check_format(u'ascii\x7f=unicode\xe9',
+ b'ascii\x7f=%U', u'unicode\xe9')
+
+ # non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV()
+ # raises an error
+ #self.assertRaisesRegex(ValueError,
+ # '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format '
+ # 'string, got a non-ASCII byte: 0xe9$',
+ # PyUnicode_FromFormat, b'unicode\xe9=%s', u'ascii')
+
+ # test "%c"
+ check_format(u'\uabcd',
+ b'%c', c_int(0xabcd))
+ if sys.maxunicode > 0xffff:
+ check_format(u'\U0010ffff',
+ b'%c', c_int(0x10ffff))
+ with self.assertRaises(OverflowError):
+ PyUnicode_FromFormat(b'%c', c_int(0x110000))
+ # Issue #18183
+ if sys.maxunicode > 0xffff:
+ check_format(u'\U00010000\U00100000',
+ b'%c%c', c_int(0x10000), c_int(0x100000))
+
+ # test "%"
+ check_format(u'%',
+ b'%')
+ check_format(u'%',
+ b'%%')
+ check_format(u'%s',
+ b'%%s')
+ check_format(u'[%]',
+ b'[%%]')
+ check_format(u'%abc',
+ b'%%%s', b'abc')
+
+ # test %S
+ check_format(u"repr=abc",
+ b'repr=%S', u'abc')
+
+ # test %R
+ check_format(u"repr=u'abc'",
+ b'repr=%R', u'abc')
+
+ # test integer formats (%i, %d, %u)
+ check_format(u'010',
+ b'%03i', c_int(10))
+ check_format(u'0010',
+ b'%0.4i', c_int(10))
+ check_format(u'-123',
+ b'%i', c_int(-123))
+
+ check_format(u'-123',
+ b'%d', c_int(-123))
+ check_format(u'-123',
+ b'%ld', c_long(-123))
+ check_format(u'-123',
+ b'%zd', c_ssize_t(-123))
+
+ check_format(u'123',
+ b'%u', c_uint(123))
+ check_format(u'123',
+ b'%lu', c_ulong(123))
+ check_format(u'123',
+ b'%zu', c_size_t(123))
+
+ # test long output
+ PyUnicode_FromFormat(b'%p', c_void_p(-1))
+
+ # test %V
+ check_format(u'repr=abc',
+ b'repr=%V', u'abc', b'xyz')
+ check_format(u'repr=\xe4\xba\xba\xe6\xb0\x91',
+ b'repr=%V', None, b'\xe4\xba\xba\xe6\xb0\x91')
+ check_format(u'repr=abc\xff',
+ b'repr=%V', None, b'abc\xff')
+
+ # not supported: copy the raw format string. these tests are just here
+ # to check for crashs and should not be considered as specifications
+ check_format(u'%s',
+ b'%1%s', b'abc')
+ check_format(u'%1abc',
+ b'%1abc')
+ check_format(u'%+i',
+ b'%+i', c_int(10))
+ check_format(u'%s',
+ b'%.%s', b'abc')
+
+
def test_encode_decimal(self):
from _testcapi import unicode_encodedecimal
self.assertEqual(unicode_encodedecimal(u'123'),

13082
SOURCES/00214-pep466-backport-py3-ssl-changes.patch

File diff suppressed because it is too large Load Diff

26
SOURCES/00215-pep466-reflect-openssl-settings-ssltests.patch

@ -0,0 +1,26 @@
diff -up Python-2.7.5/Lib/test/test_ssl.py.ssl2 Python-2.7.5/Lib/test/test_ssl.py
--- Python-2.7.5/Lib/test/test_ssl.py.ssl2 2015-03-04 12:19:26.345387741 +0100
+++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-04 12:32:43.485702679 +0100
@@ -689,7 +689,8 @@ class ContextTests(unittest.TestCase):
@skip_if_broken_ubuntu_ssl
def test_options(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
- # OP_ALL | OP_NO_SSLv2 is the default value
+ self.assertEqual(ssl.OP_ALL, ctx.options)
+ ctx.options |= ssl.OP_NO_SSLv2
self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2,
ctx.options)
ctx.options |= ssl.OP_NO_SSLv3
@@ -2142,9 +2143,9 @@ else:
# No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
client_options=ssl.OP_NO_SSLv2)
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True,
client_options=ssl.OP_NO_SSLv3)
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True,
client_options=ssl.OP_NO_TLSv1)

@skip_if_broken_ubuntu_ssl

72
SOURCES/00216-pep466-fix-load-verify-locs-unicode.patch

@ -0,0 +1,72 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1409232801 14400
# Node ID 97081a80f487841d81aeed55d398a1dba1faca00
# Parent 3ae399c6ecf685086ebf07e17717955f21e14cb8
fix load_verify_locations on unicode paths (closes #22244)

diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -850,11 +850,14 @@ class ContextTests(unittest.TestCase):
ctx.load_verify_locations(cafile=CERTFILE, capath=None)
ctx.load_verify_locations(BYTES_CERTFILE)
ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None)
+ ctx.load_verify_locations(cafile=BYTES_CERTFILE.decode('utf-8'))
self.assertRaises(TypeError, ctx.load_verify_locations)
self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None)
with self.assertRaises(IOError) as cm:
ctx.load_verify_locations(WRONGCERT)
self.assertEqual(cm.exception.errno, errno.ENOENT)
+ with self.assertRaises(IOError):
+ ctx.load_verify_locations(u'')
with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"):
ctx.load_verify_locations(BADCERT)
ctx.load_verify_locations(CERTFILE, CAPATH)
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2628,17 +2628,33 @@ load_verify_locations(PySSLContext *self
}
if (cafile) {
- cafile_bytes = PyString_AsEncodedObject(
- cafile, Py_FileSystemDefaultEncoding, "strict");
- if (!cafile_bytes) {
- goto error;
+ if (PyString_Check(cafile)) {
+ Py_INCREF(cafile);
+ cafile_bytes = cafile;
+ } else {
+ PyObject *u = PyUnicode_FromObject(cafile);
+ if (!u)
+ goto error;
+ cafile_bytes = PyUnicode_AsEncodedString(
+ u, Py_FileSystemDefaultEncoding, NULL);
+ Py_DECREF(u);
+ if (!cafile_bytes)
+ goto error;
}
}
if (capath) {
- capath_bytes = PyString_AsEncodedObject(
- capath, Py_FileSystemDefaultEncoding, "strict");
- if (!capath_bytes) {
- goto error;
+ if (PyString_Check(capath)) {
+ Py_INCREF(capath);
+ capath_bytes = capath;
+ } else {
+ PyObject *u = PyUnicode_FromObject(capath);
+ if (!u)
+ goto error;
+ capath_bytes = PyUnicode_AsEncodedString(
+ u, Py_FileSystemDefaultEncoding, NULL);
+ Py_DECREF(u);
+ if (!capath_bytes)
+ goto error;
}
}

189
SOURCES/00217-pep466-backport-hashlib-algorithm-consts.patch

@ -0,0 +1,189 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1409233289 14400
# Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5
# Parent 97081a80f487841d81aeed55d398a1dba1faca00
PEP 466: backport hashlib algorithm constants (closes #21307)

diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst
--- a/Doc/library/hashlib.rst
+++ b/Doc/library/hashlib.rst
@@ -88,6 +88,24 @@ This module provides the following const
.. versionadded:: 2.7
+.. data:: algorithms_guaranteed
+
+ A set containing the names of the hash algorithms guaranteed to be supported
+ by this module on all platforms.
+
+ .. versionadded:: 2.7.9
+
+.. data:: algorithms_available
+
+ A set containing the names of the hash algorithms that are available in the
+ running Python interpreter. These names will be recognized when passed to
+ :func:`new`. :attr:`algorithms_guaranteed` will always be a subset. The
+ same algorithm may appear multiple times in this set under different names
+ (thanks to OpenSSL).
+
+ .. versionadded:: 2.7.9
+
+
The following values are provided as constant attributes of the hash objects
returned by the constructors:
diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py
--- Python-2.7.5/Lib/hashlib.py.hash 2015-03-04 17:05:57.496598686 +0100
+++ Python-2.7.5/Lib/hashlib.py 2015-03-04 17:11:34.872739103 +0100
@@ -18,8 +18,9 @@ than using new():
md5(), sha1(), sha224(), sha256(), sha384(), and sha512()
-More algorithms may be available on your platform but the above are
-guaranteed to exist.
+More algorithms may be available on your platform but the above are guaranteed
+to exist. See the algorithms_guaranteed and algorithms_available attributes
+to find out what algorithm names can be passed to new().
NOTE: If you want the adler32 or crc32 hash functions they are available in
the zlib module.
@@ -75,9 +76,14 @@ More condensed:
# always available algorithm is added.
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
+algorithms_guaranteed = set(__always_supported)
+algorithms_available = set(__always_supported)
+
algorithms = __always_supported
-__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac')
+__all__ = __always_supported + ('new', 'algorithms_guaranteed',
+ 'algorithms_available', 'algorithms',
+ 'pbkdf2_hmac')
def __get_openssl_constructor(name):
@@ -110,6 +116,8 @@ try:
import _hashlib
new = __hash_new
__get_hash = __get_openssl_constructor
+ algorithms_available = algorithms_available.union(
+ _hashlib.openssl_md_meth_names)
except ImportError:
# We don't build the legacy modules
raise
diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c
--- Python-2.7.5/Modules/_hashopenssl.c.hash 2015-03-04 17:06:18.246791837 +0100
+++ Python-2.7.5/Modules/_hashopenssl.c 2015-03-04 17:16:17.696369000 +0100
@@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar
#endif
+/* State for our callback function so that it can accumulate a result. */
+typedef struct _internal_name_mapper_state {
+ PyObject *set;
+ int error;
+} _InternalNameMapperState;
+
+
+/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */
+static void
+_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg)
+{
+ _InternalNameMapperState *state = (_InternalNameMapperState *)arg;
+ PyObject *py_name;
+
+ assert(state != NULL);
+ if (openssl_obj_name == NULL)
+ return;
+ /* Ignore aliased names, they pollute the list and OpenSSL appears to
+ * have a its own definition of alias as the resulting list still
+ * contains duplicate and alternate names for several algorithms. */
+ if (openssl_obj_name->alias)
+ return;
+
+ py_name = PyString_FromString(openssl_obj_name->name);
+ if (py_name == NULL) {
+ state->error = 1;
+ } else {
+ if (PySet_Add(state->set, py_name) != 0) {
+ state->error = 1;
+ }
+ Py_DECREF(py_name);
+ }
+}
+
+
+/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */
+static PyObject*
+generate_hash_name_list(void)
+{
+ _InternalNameMapperState state;
+ state.set = PyFrozenSet_New(NULL);
+ if (state.set == NULL)
+ return NULL;
+ state.error = 0;
+
+ OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state);
+
+ if (state.error) {
+ Py_DECREF(state.set);
+ return NULL;
+ }
+ return state.set;
+}
+
+
/*
* This macro and function generates a family of constructor function
* definitions for specific hash algorithms. These constructors are much
@@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[
PyMODINIT_FUNC
init_hashlib(void)
{
- PyObject *m;
+ PyObject *m, *openssl_md_meth_names;
SSL_load_error_strings();
SSL_library_init();
- OpenSSL_add_all_digests();
+ ERR_load_crypto_strings();
Py_TYPE(&EVPtype) = &PyType_Type;
if (PyType_Ready(&EVPtype) < 0)
@@ -938,6 +993,14 @@ init_hashlib(void)
if (m == NULL)
return;
+ openssl_md_meth_names = generate_hash_name_list();
+ if (openssl_md_meth_names == NULL) {
+ return;
+ }
+ if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) {
+ return;
+ }
+
#if HASH_OBJ_CONSTRUCTOR
Py_INCREF(&EVPtype);
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype);
diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py
--- Python-2.7.5/Lib/test/test_hashlib.py.hash 2015-03-04 18:04:57.823553474 +0100
+++ Python-2.7.5/Lib/test/test_hashlib.py 2015-03-04 18:06:39.395499123 +0100
@@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase)
tuple([_algo for _algo in self.supported_hash_names if
_algo.islower()]))
+ def test_algorithms_guaranteed(self):
+ self.assertEqual(hashlib.algorithms_guaranteed,
+ set(_algo for _algo in self.supported_hash_names
+ if _algo.islower()))
+
+ def test_algorithms_available(self):
+ self.assertTrue(set(hashlib.algorithms_guaranteed).
+ issubset(hashlib.algorithms_available))
+
def test_unknown_hash(self):
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
self.assertRaises(TypeError, hashlib.new, 1)

165
SOURCES/00218-pep466-backport-urandom-pers-fd.patch

@ -0,0 +1,165 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1409243400 14400
# Node ID 3e7f8855078855a9409bc2c1372de89cb021d6c8
# Parent 3f73c44b1fd1d442d6841493328e9756fb5e7ef5
PEP 466: backport persistent urandom fd (closes #21305)

Patch from Alex Gaynor.

diff --git a/Python/pythonrun.c b/Python/pythonrun.c
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -536,6 +536,7 @@ Py_Finalize(void)
PyInt_Fini();
PyFloat_Fini();
PyDict_Fini();
+ _PyRandom_Fini();
#ifdef Py_USING_UNICODE
/* Cleanup Unicode implementation */
diff -up Python-2.7.5/Include/pythonrun.h.urandom Python-2.7.5/Include/pythonrun.h
--- Python-2.7.5/Include/pythonrun.h.urandom 2015-03-06 08:16:47.638584015 +0100
+++ Python-2.7.5/Include/pythonrun.h 2015-03-06 08:21:48.009485462 +0100
@@ -145,6 +145,7 @@ PyAPI_FUNC(void) PyInt_Fini(void);
PyAPI_FUNC(void) PyFloat_Fini(void);
PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
PyAPI_FUNC(void) PyByteArray_Fini(void);
+PyAPI_FUNC(void) _PyRandom_Fini(void);
/* Stuff with no proper home (yet) */
PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *);
diff -up Python-2.7.5/Python/random.c.urandom Python-2.7.5/Python/random.c
--- Python-2.7.5/Python/random.c.urandom 2015-03-06 08:22:10.244699950 +0100
+++ Python-2.7.5/Python/random.c 2015-03-06 08:24:57.907317272 +0100
@@ -118,10 +118,16 @@ vms_urandom(unsigned char *buffer, Py_ss
#if !defined(MS_WINDOWS) && !defined(__VMS)
+static struct {
+ int fd;
+ dev_t st_dev;
+ ino_t st_ino;
+} urandom_cache = { -1 };
+
/* Read size bytes from /dev/urandom into buffer.
Call Py_FatalError() on error. */
static void
-dev_urandom_noraise(char *buffer, Py_ssize_t size)
+dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
{
int fd;
Py_ssize_t n;
@@ -156,18 +162,56 @@ dev_urandom_python(char *buffer, Py_ssiz
{
int fd;
Py_ssize_t n;
+ struct stat st;
if (size <= 0)
return 0;
- Py_BEGIN_ALLOW_THREADS
- fd = open("/dev/urandom", O_RDONLY);
- Py_END_ALLOW_THREADS
- if (fd < 0)
- {
- PyErr_SetString(PyExc_NotImplementedError,
- "/dev/urandom (or equivalent) not found");
- return -1;
+ if (urandom_cache.fd >= 0) {
+ /* Does the fd point to the same thing as before? (issue #21207) */
+ if (fstat(urandom_cache.fd, &st)
+ || st.st_dev != urandom_cache.st_dev
+ || st.st_ino != urandom_cache.st_ino) {
+ /* Something changed: forget the cached fd (but don't close it,
+ since it probably points to something important for some
+ third-party code). */
+ urandom_cache.fd = -1;
+ }
+ }
+ if (urandom_cache.fd >= 0)
+ fd = urandom_cache.fd;
+ else {
+ Py_BEGIN_ALLOW_THREADS
+ fd = open("/dev/urandom", O_RDONLY);
+ Py_END_ALLOW_THREADS
+ if (fd < 0)
+ {
+ if (errno == ENOENT || errno == ENXIO ||
+ errno == ENODEV || errno == EACCES)
+ PyErr_SetString(PyExc_NotImplementedError,
+ "/dev/urandom (or equivalent) not found");
+ else
+ PyErr_SetFromErrno(PyExc_OSError);
+ return -1;
+ }
+ if (urandom_cache.fd >= 0) {
+ /* urandom_fd was initialized by another thread while we were
+ not holding the GIL, keep it. */
+ close(fd);
+ fd = urandom_cache.fd;
+ }
+ else {
+ if (fstat(fd, &st)) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ close(fd);
+ return -1;
+ }
+ else {
+ urandom_cache.fd = fd;
+ urandom_cache.st_dev = st.st_dev;
+ urandom_cache.st_ino = st.st_ino;
+ }
+ }
}
Py_BEGIN_ALLOW_THREADS
@@ -191,12 +235,21 @@ dev_urandom_python(char *buffer, Py_ssiz
PyErr_Format(PyExc_RuntimeError,
"Failed to read %zi bytes from /dev/urandom",
size);
- close(fd);
return -1;
}
- close(fd);
return 0;
}
+
+static void
+dev_urandom_close(void)
+{
+ if (urandom_cache.fd >= 0) {
+ close(urandom_cache.fd);
+ urandom_cache.fd = -1;
+ }
+}
+
+
#endif /* !defined(MS_WINDOWS) && !defined(__VMS) */
/* Fill buffer with pseudo-random bytes generated by a linear congruent
@@ -300,8 +353,21 @@ _PyRandom_Init(void)
# ifdef __VMS
vms_urandom((unsigned char *)secret, secret_size, 0);
# else
- dev_urandom_noraise((char*)secret, secret_size);
+ dev_urandom_noraise((unsigned char*)secret, secret_size);
# endif
#endif
}
}
+
+void
+_PyRandom_Fini(void)
+{
+#ifdef MS_WINDOWS
+ if (hCryptProv) {
+ CryptReleaseContext(hCryptProv, 0);
+ hCryptProv = 0;
+ }
+#else
+ dev_urandom_close();
+#endif
+}

91
SOURCES/00219-pep466-fix-referenced-sslwrap.patch

@ -0,0 +1,91 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1412221981 14400
# Node ID 1a36d4e8cf4edfdc4c7d59a40075b8cf00e3ad3c
# Parent 222e0faa5fa9567f657f13fc78a60069142e09ae
fix sslwrap_simple (closes #22523)

Thanks Alex Gaynor.

diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -969,16 +969,16 @@ def get_protocol_name(protocol_code):
# a replacement for the old socket.ssl function
def sslwrap_simple(sock, keyfile=None, certfile=None):
-
"""A replacement for the old socket.ssl function. Designed
for compability with Python 2.5 and earlier. Will disappear in
Python 3.0."""
-
if hasattr(sock, "_sock"):
sock = sock._sock
- ssl_sock = _ssl.sslwrap(sock, 0, keyfile, certfile, CERT_NONE,
- PROTOCOL_SSLv23, None)
+ ctx = SSLContext(PROTOCOL_SSLv23)
+ if keyfile or certfile:
+ ctx.load_cert_chain(certfile, keyfile)
+ ssl_sock = ctx._wrap_socket(sock, server_side=False)
try:
sock.getpeername()
except socket_error:
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -94,6 +94,8 @@ class BasicTests(unittest.TestCase):
pass
else:
raise
+
+
def can_clear_options():
# 0.9.8m or higher
return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15)
@@ -2944,7 +2946,7 @@ def test_main(verbose=False):
if not os.path.exists(filename):
raise support.TestFailed("Can't read certificate file %r" % filename)
- tests = [ContextTests, BasicSocketTests, SSLErrorTests]
+ tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests]
if support.is_resource_enabled('network'):
tests.append(NetworkedTests)
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -517,10 +517,12 @@ newPySSLSocket(PySSLContext *sslctx, PyS
self->socket_type = socket_type;
self->Socket = sock;
Py_INCREF(self->Socket);
- self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL);
- if (self->ssl_sock == NULL) {
- Py_DECREF(self);
- return NULL;
+ if (ssl_sock != Py_None) {
+ self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL);
+ if (self->ssl_sock == NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
}
return self;
}
@@ -2931,8 +2933,12 @@ static int
ssl = SSL_get_app_data(s);
assert(PySSLSocket_Check(ssl));
- ssl_socket = PyWeakref_GetObject(ssl->ssl_sock);
- Py_INCREF(ssl_socket);
+ if (ssl->ssl_sock == NULL) {
+ ssl_socket = Py_None;
+ } else {
+ ssl_socket = PyWeakref_GetObject(ssl->ssl_sock);
+ Py_INCREF(ssl_socket);
+ }
if (ssl_socket == Py_None) {
goto error;
}

673
SOURCES/00220-pep466-allow-passing-ssl-urrlib-httplib.patch

@ -0,0 +1,673 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1416764565 21600
# Node ID 1882157b298a164291d2b3a8b9525eb0902895f6
# Parent 588ebc8fd3daf7307961cd614c4da9525bb67313
allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection

This is basically a backport of issues #9003 and #22366.

diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst
--- a/Doc/library/httplib.rst
+++ b/Doc/library/httplib.rst
@@ -70,12 +70,25 @@ The module provides the following classe
*source_address* was added.
-.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]])
+.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address, context, check_hostname]]]]]])
A subclass of :class:`HTTPConnection` that uses SSL for communication with
- secure servers. Default port is ``443``. *key_file* is the name of a PEM
- formatted file that contains your private key. *cert_file* is a PEM formatted
- certificate chain file.
+ secure servers. Default port is ``443``. If *context* is specified, it must
+ be a :class:`ssl.SSLContext` instance describing the various SSL options.
+
+ *key_file* and *cert_file* are deprecated, please use
+ :meth:`ssl.SSLContext.load_cert_chain` instead, or let
+ :func:`ssl.create_default_context` select the system's trusted CA
+ certificates for you.
+
+ Please read :ref:`ssl-security` for more information on best practices.
+
+ .. note::
+ If *context* is specified and has a :attr:`~ssl.SSLContext.verify_mode`
+ of either :data:`~ssl.CERT_OPTIONAL` or :data:`~ssl.CERT_REQUIRED`, then
+ by default *host* is matched against the host name(s) allowed by the
+ server's certificate. If you want to change that behaviour, you can
+ explicitly set *check_hostname* to False.
.. warning::
This does not do any verification of the server's certificate.
@@ -88,6 +101,9 @@ The module provides the following classe
.. versionchanged:: 2.7
*source_address* was added.
+ .. versionchanged:: 2.7.9
+ *context* and *check_hostname* was added.
+
.. class:: HTTPResponse(sock, debuglevel=0, strict=0)
diff --git a/Lib/test/keycert2.pem b/Lib/test/keycert2.pem
new file mode 100644
--- /dev/null
+++ b/Lib/test/keycert2.pem
@@ -0,0 +1,31 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc
+PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK
+Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r
+s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI
+BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B
+EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf
+tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc
+JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky
+GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg
+wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz
+HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz
+i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l
+gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV
+d5rWoljEfdou
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x
+NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD
+VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv
+dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF
+AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py
+YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP
+i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA
+AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB
+AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA
+QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74
+El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7
+-----END CERTIFICATE-----
diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem
new file mode 100644
--- /dev/null
+++ b/Lib/test/selfsigned_pythontestdotnet.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
+bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
+A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
+b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
+aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
+Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
+Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
+EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl
+bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM
+eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV
+HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97
+vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9
+-----END CERTIFICATE-----
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -8,6 +8,11 @@ import StringIO
import urllib2
from urllib2 import Request, OpenerDirector
+try:
+ import ssl
+except ImportError:
+ ssl = None
+
# XXX
# Request
# CacheFTPHandler (hard to write)
@@ -47,6 +52,14 @@ class TrivialTests(unittest.TestCase):
for string, list in tests:
self.assertEqual(urllib2.parse_http_list(string), list)
+ @unittest.skipUnless(ssl, "ssl module required")
+ def test_cafile_and_context(self):
+ context = ssl.create_default_context()
+ with self.assertRaises(ValueError):
+ urllib2.urlopen(
+ "https://localhost", cafile="/nonexistent/path", context=context
+ )
+
def test_request_headers_dict():
"""
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
--- a/Lib/urllib2.py
+++ b/Lib/urllib2.py
@@ -109,6 +109,14 @@ try:
except ImportError:
from StringIO import StringIO
+# check for SSL
+try:
+ import ssl
+except ImportError:
+ _have_ssl = False
+else:
+ _have_ssl = True
+
from urllib import (unwrap, unquote, splittype, splithost, quote,
addinfourl, splitport, splittag, toBytes,
splitattr, ftpwrapper, splituser, splitpasswd, splitvalue)
@@ -120,11 +128,30 @@ from urllib import localhost, url2pathna
__version__ = sys.version[:3]
_opener = None
-def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
+def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+ cafile=None, capath=None, cadefault=False, context=None):
global _opener
- if _opener is None:
- _opener = build_opener()
- return _opener.open(url, data, timeout)
+ if cafile or capath or cadefault:
+ if context is not None:
+ raise ValueError(
+ "You can't pass both context and any of cafile, capath, and "
+ "cadefault"
+ )
+ if not _have_ssl:
+ raise ValueError('SSL support not available')
+ context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED,
+ cafile=cafile,
+ capath=capath)
+ https_handler = HTTPSHandler(context=context, check_hostname=True)
+ opener = build_opener(https_handler)
+ elif context:
+ https_handler = HTTPSHandler(context=context)
+ opener = build_opener(https_handler)
+ elif _opener is None:
+ _opener = opener = build_opener()
+ else:
+ opener = _opener
+ return opener.open(url, data, timeout)
def install_opener(opener):
global _opener
@@ -1121,7 +1148,7 @@ class AbstractHTTPHandler(BaseHandler):
return request
- def do_open(self, http_class, req):
+ def do_open(self, http_class, req, **http_conn_args):
"""Return an addinfourl object for the request, using http_class.
http_class must implement the HTTPConnection API from httplib.
@@ -1135,7 +1162,8 @@ class AbstractHTTPHandler(BaseHandler):
if not host:
raise URLError('no host given')
- h = http_class(host, timeout=req.timeout) # will parse host:port
+ # will parse host:port
+ h = http_class(host, timeout=req.timeout, **http_conn_args)
h.set_debuglevel(self._debuglevel)
headers = dict(req.unredirected_hdrs)
@@ -1203,8 +1231,14 @@ class HTTPHandler(AbstractHTTPHandler):
if hasattr(httplib, 'HTTPS'):
class HTTPSHandler(AbstractHTTPHandler):
+ def __init__(self, debuglevel=0, context=None, check_hostname=None):
+ AbstractHTTPHandler.__init__(self, debuglevel)
+ self._context = context
+ self._check_hostname = check_hostname
+
def https_open(self, req):
- return self.do_open(httplib.HTTPSConnection, req)
+ return self.do_open(httplib.HTTPSConnection, req,
+ context=self._context, check_hostname=self._check_hostname)
https_request = AbstractHTTPHandler.do_request_
diff -up Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx Python-2.7.5/Lib/test/test_urllib2_localnet.py
--- Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx 2015-03-30 10:13:48.351310552 +0200
+++ Python-2.7.5/Lib/test/test_urllib2_localnet.py 2015-03-30 10:14:54.715713679 +0200
@@ -1,5 +1,6 @@
#!/usr/bin/env python
+import os
import urlparse
import urllib2
import BaseHTTPServer
@@ -11,6 +12,17 @@ from test import test_support
mimetools = test_support.import_module('mimetools', deprecated=True)
threading = test_support.import_module('threading')
+try:
+ import ssl
+except ImportError:
+ ssl = None
+
+here = os.path.dirname(__file__)
+# Self-signed cert file for 'localhost'
+CERT_localhost = os.path.join(here, 'keycert.pem')
+# Self-signed cert file for 'fakehostname'
+CERT_fakehostname = os.path.join(here, 'keycert2.pem')
+
# Loopback http server infrastructure
class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
@@ -25,7 +37,7 @@ class LoopbackHttpServer(BaseHTTPServer.
# Set the timeout of our listening socket really low so
# that we can stop the server easily.
- self.socket.settimeout(1.0)
+ self.socket.settimeout(0.1)
def get_request(self):
"""BaseHTTPServer method, overridden."""
@@ -354,6 +366,19 @@ class TestUrlopen(BaseTestCase):
urllib2.install_opener(opener)
super(TestUrlopen, self).setUp()
+ def urlopen(self, url, data=None, **kwargs):
+ l = []
+ f = urllib2.urlopen(url, data, **kwargs)
+ try:
+ # Exercise various methods
+ l.extend(f.readlines(200))
+ l.append(f.readline())
+ l.append(f.read(1024))
+ l.append(f.read())
+ finally:
+ f.close()
+ return b"".join(l)
+
def start_server(self, responses):
handler = GetRequestHandler(responses)
@@ -364,6 +389,16 @@ class TestUrlopen(BaseTestCase):
handler.port = port
return handler
+ def start_https_server(self, responses=None, **kwargs):
+ if not hasattr(urllib2, 'HTTPSHandler'):
+ self.skipTest('ssl support required')
+ from test.ssl_servers import make_https_server
+ if responses is None:
+ responses = [(200, [], b"we care a bit")]
+ handler = GetRequestHandler(responses)
+ server = make_https_server(self, handler_class=handler, **kwargs)
+ handler.port = server.port
+ return handler
def test_redirection(self):
expected_response = 'We got here...'
@@ -434,6 +469,28 @@ class TestUrlopen(BaseTestCase):
finally:
self.server.stop()
+ def test_https(self):
+ handler = self.start_https_server()
+ context = ssl.create_default_context(cafile=CERT_localhost)
+ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context)
+ self.assertEqual(data, b"we care a bit")
+
+ def test_https_with_cafile(self):
+ handler = self.start_https_server(certfile=CERT_localhost)
+ import ssl
+ # Good cert
+ data = self.urlopen("https://localhost:%s/bizarre" % handler.port,
+ cafile=CERT_localhost)
+ self.assertEqual(data, b"we care a bit")
+ # Bad cert
+ with self.assertRaises(urllib2.URLError) as cm:
+ self.urlopen("https://localhost:%s/bizarre" % handler.port,
+ cafile=CERT_fakehostname)
+ # Good cert, but mismatching hostname
+ handler = self.start_https_server(certfile=CERT_fakehostname)
+ with self.assertRaises(ssl.CertificateError) as cm:
+ self.urlopen("https://localhost:%s/bizarre" % handler.port,
+ cafile=CERT_fakehostname)
def test_sending_headers(self):
handler = self.start_server([(200, [], "we don't care")])
diff -up Python-2.7.5/Doc/library/urllib2.rst.ctx Python-2.7.5/Doc/library/urllib2.rst
--- Python-2.7.5/Doc/library/urllib2.rst.ctx 2015-03-30 10:20:15.958747076 +0200
+++ Python-2.7.5/Doc/library/urllib2.rst 2015-03-30 10:30:46.172779366 +0200
@@ -22,13 +22,10 @@ redirections, cookies and more.
The :mod:`urllib2` module defines the following functions:
-.. function:: urlopen(url[, data][, timeout])
+.. function:: urlopen(url[, data[, timeout[, cafile[, capath[, cadefault[, context]]]]])
Open the URL *url*, which can be either a string or a :class:`Request` object.
- .. warning::
- HTTPS requests do not do any verification of the server's certificate.
-
*data* may be a string specifying additional data to send to the server, or
``None`` if no such data is needed. Currently HTTP requests are the only ones
that use *data*; the HTTP request will be a POST instead of a GET when the
@@ -41,7 +38,19 @@ The :mod:`urllib2` module defines the fo
The optional *timeout* parameter specifies a timeout in seconds for blocking
operations like the connection attempt (if not specified, the global default
timeout setting will be used). This actually only works for HTTP, HTTPS and
- FTP connections.
+ FTP connections.
+
+ If *context* is specified, it must be a :class:`ssl.SSLContext` instance
+ describing the various SSL options. See :class:`~httplib.HTTPSConnection` for
+ more details.
+
+ The optional *cafile* and *capath* parameters specify a set of trusted CA
+ certificates for HTTPS requests. *cafile* should point to a single file
+ containing a bundle of CA certificates, whereas *capath* should point to a
+ directory of hashed certificate files. More information can be found in
+ :meth:`ssl.SSLContext.load_verify_locations`.
+
+ The *cadefault* parameter is ignored.
This function returns a file-like object with two additional methods:
@@ -66,7 +75,10 @@ The :mod:`urllib2` module defines the fo
handled through the proxy.
.. versionchanged:: 2.6
- *timeout* was added.
+ *timeout* was added.
+
+ .. versionchanged:: 2.7.9
+ *cafile*, *capath*, *cadefault*, and *context* were added.
.. function:: install_opener(opener)
@@ -280,9 +292,13 @@ The following classes are provided:
A class to handle opening of HTTP URLs.
-.. class:: HTTPSHandler()
+.. class:: HTTPSHandler([debuglevel[, context[, check_hostname]]])
+
+ A class to handle opening of HTTPS URLs. *context* and *check_hostname* have
+ the same meaning as for :class:`httplib.HTTPSConnection`.
- A class to handle opening of HTTPS URLs.
+ .. versionchanged:: 2.7.9
+ *context* and *check_hostname* were added.
.. class:: FileHandler()
diff -up Python-2.7.5/Lib/httplib.py.ctx Python-2.7.5/Lib/httplib.py
--- Python-2.7.5/Lib/httplib.py.ctx 2015-03-30 10:19:52.551521393 +0200
+++ Python-2.7.5/Lib/httplib.py 2015-03-30 10:30:05.045386751 +0200
@@ -1159,21 +1159,44 @@ else:
def __init__(self, host, port=None, key_file=None, cert_file=None,
strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
- source_address=None):
+ source_address=None, context=None, check_hostname=None):
HTTPConnection.__init__(self, host, port, strict, timeout,
source_address)
self.key_file = key_file
self.cert_file = cert_file
+ if context is None:
+ context = ssl.create_default_context()
+ will_verify = context.verify_mode != ssl.CERT_NONE
+ if check_hostname is None:
+ check_hostname = will_verify
+ elif check_hostname and not will_verify:
+ raise ValueError("check_hostname needs a SSL context with "
+ "either CERT_OPTIONAL or CERT_REQUIRED")
+ if key_file or cert_file:
+ context.load_cert_chain(cert_file, key_file)
+ self._context = context
+ self._check_hostname = check_hostname
def connect(self):
"Connect to a host on a given (SSL) port."
- sock = socket.create_connection((self.host, self.port),
- self.timeout, self.source_address)
+ HTTPConnection.connect(self)
+
if self._tunnel_host:
- self.sock = sock
- self._tunnel()
- self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
+ server_hostname = self._tunnel_host
+ else:
+ server_hostname = self.host
+ sni_hostname = server_hostname if ssl.HAS_SNI else None
+
+ self.sock = self._context.wrap_socket(self.sock,
+ server_hostname=sni_hostname)
+ if not self._context.check_hostname and self._check_hostname:
+ try:
+ ssl.match_hostname(self.sock.getpeercert(), server_hostname)
+ except Exception:
+ self.sock.shutdown(socket.SHUT_RDWR)
+ self.sock.close()
+ raise
__all__.append("HTTPSConnection")
diff -up Python-2.7.5/Lib/test/test_httplib.py.ctx Python-2.7.5/Lib/test/test_httplib.py
--- Python-2.7.5/Lib/test/test_httplib.py.ctx 2015-03-30 10:19:12.905139139 +0200
+++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 10:27:41.822017804 +0200
@@ -1,6 +1,7 @@
import httplib
import array
import httplib
+import os
import StringIO
import socket
import errno
@@ -10,6 +11,14 @@ TestCase = unittest.TestCase
from test import test_support
+here = os.path.dirname(__file__)
+# Self-signed cert file for 'localhost'
+CERT_localhost = os.path.join(here, 'keycert.pem')
+# Self-signed cert file for 'fakehostname'
+CERT_fakehostname = os.path.join(here, 'keycert2.pem')
+# Self-signed cert file for self-signed.pythontest.net
+CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem')
+
HOST = test_support.HOST
class FakeSocket:
@@ -493,40 +502,147 @@ class TimeoutTest(TestCase):
httpConn.close()
-class HTTPSTimeoutTest(TestCase):
+class HTTPSTest(TestCase):
# XXX Here should be tests for HTTPS, there isn't any right now!
+ def setUp(self):
+ if not hasattr(httplib, 'HTTPSConnection'):
+ self.skipTest('ssl support required')
+
+ def make_server(self, certfile):
+ from test.ssl_servers import make_https_server
+ return make_https_server(self, certfile=certfile)
def test_attributes(self):
- # simple test to check it's storing it
- if hasattr(httplib, 'HTTPSConnection'):
- h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
- self.assertEqual(h.timeout, 30)
+ # simple test to check it's storing the timeout
+ h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
+ self.assertEqual(h.timeout, 30)
+
+ def test_networked(self):
+ # Default settings: requires a valid cert from a trusted CA
+ import ssl
+ test_support.requires('network')
+ with test_support.transient_internet('self-signed.pythontest.net'):
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
+ with self.assertRaises(ssl.SSLError) as exc_info:
+ h.request('GET', '/')
+ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
+
+ def test_networked_noverification(self):
+ # Switch off cert verification
+ import ssl
+ test_support.requires('network')
+ with test_support.transient_internet('self-signed.pythontest.net'):
+ context = ssl._create_stdlib_context()
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443,
+ context=context)
+ h.request('GET', '/')
+ resp = h.getresponse()
+ self.assertIn('nginx', resp.getheader('server'))
+
+ def test_networked_trusted_by_default_cert(self):
+ # Default settings: requires a valid cert from a trusted CA
+ test_support.requires('network')
+ with test_support.transient_internet('www.python.org'):
+ h = httplib.HTTPSConnection('www.python.org', 443)
+ h.request('GET', '/')
+ resp = h.getresponse()
+ content_type = resp.getheader('content-type')
+ self.assertIn('text/html', content_type)
+
+ def test_networked_good_cert(self):
+ # We feed the server's cert as a validating cert
+ import ssl
+ test_support.requires('network')
+ with test_support.transient_internet('self-signed.pythontest.net'):
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ context.verify_mode = ssl.CERT_REQUIRED
+ context.load_verify_locations(CERT_selfsigned_pythontestdotnet)
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
+ h.request('GET', '/')
+ resp = h.getresponse()
+ server_string = resp.getheader('server')
+ self.assertIn('nginx', server_string)
+
+ def test_networked_bad_cert(self):
+ # We feed a "CA" cert that is unrelated to the server's cert
+ import ssl
+ test_support.requires('network')
+ with test_support.transient_internet('self-signed.pythontest.net'):
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ context.verify_mode = ssl.CERT_REQUIRED
+ context.load_verify_locations(CERT_localhost)
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
+ with self.assertRaises(ssl.SSLError) as exc_info:
+ h.request('GET', '/')
+ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
+
+ def test_local_unknown_cert(self):
+ # The custom cert isn't known to the default trust bundle
+ import ssl
+ server = self.make_server(CERT_localhost)
+ h = httplib.HTTPSConnection('localhost', server.port)
+ with self.assertRaises(ssl.SSLError) as exc_info:
+ h.request('GET', '/')
+ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
+
+ def test_local_good_hostname(self):
+ # The (valid) cert validates the HTTP hostname
+ import ssl
+ server = self.make_server(CERT_localhost)
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ context.verify_mode = ssl.CERT_REQUIRED
+ context.load_verify_locations(CERT_localhost)
+ h = httplib.HTTPSConnection('localhost', server.port, context=context)
+ h.request('GET', '/nonexistent')
+ resp = h.getresponse()
+ self.assertEqual(resp.status, 404)
+
+ def test_local_bad_hostname(self):
+ # The (valid) cert doesn't validate the HTTP hostname
+ import ssl
+ server = self.make_server(CERT_fakehostname)
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ context.verify_mode = ssl.CERT_REQUIRED
+ context.load_verify_locations(CERT_fakehostname)
+ h = httplib.HTTPSConnection('localhost', server.port, context=context)
+ with self.assertRaises(ssl.CertificateError):
+ h.request('GET', '/')
+ # Same with explicit check_hostname=True
+ h = httplib.HTTPSConnection('localhost', server.port, context=context,
+ check_hostname=True)
+ with self.assertRaises(ssl.CertificateError):
+ h.request('GET', '/')
+ # With check_hostname=False, the mismatching is ignored
+ h = httplib.HTTPSConnection('localhost', server.port, context=context,
+ check_hostname=False)
+ h.request('GET', '/nonexistent')
+ resp = h.getresponse()
+ self.assertEqual(resp.status, 404)
- @unittest.skipIf(not hasattr(httplib, 'HTTPS'), 'httplib.HTTPS not available')
def test_host_port(self):
# Check invalid host_port
- # Note that httplib does not accept user:password@ in the host-port.
for hp in ("www.python.org:abc", "user:password@www.python.org"):
- self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp)
+ self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
- for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b",
- 8000),
- ("pypi.python.org:443", "pypi.python.org", 443),
- ("pypi.python.org", "pypi.python.org", 443),
- ("pypi.python.org:", "pypi.python.org", 443),
- ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443)):
- http = httplib.HTTPS(hp)
- c = http._conn
- if h != c.host:
- self.fail("Host incorrectly parsed: %s != %s" % (h, c.host))
- if p != c.port:
- self.fail("Port incorrectly parsed: %s != %s" % (p, c.host))
+ for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
+ "fe80::207:e9ff:fe9b", 8000),
+ ("www.python.org:443", "www.python.org", 443),
+ ("www.python.org:", "www.python.org", 443),
+ ("www.python.org", "www.python.org", 443),
+ ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
+ ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
+ 443)):
+ c = httplib.HTTPSConnection(hp)
+ self.assertEqual(h, c.host)
+ self.assertEqual(p, c.port)
+
+@test_support.reap_threads
def test_main(verbose=None):
test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
- HTTPSTimeoutTest, SourceAddressTest)
+ HTTPSTest, SourceAddressTest)
if __name__ == '__main__':
test_main()
diff -up Python-2.7.5/Lib/test/test_ssl.py.ctx Python-2.7.5/Lib/test/test_ssl.py
--- Python-2.7.5/Lib/test/test_ssl.py.ctx 2015-03-30 10:18:55.677973042 +0200
+++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-30 10:22:02.323772604 +0200
@@ -14,7 +14,7 @@ import os
import errno
import pprint
import tempfile
-import urllib
+import urllib2
import traceback
import weakref
import platform
@@ -2332,9 +2332,10 @@ else:
d1 = f.read()
d2 = ''
# now fetch the same data from the HTTPS server
- url = 'https://%s:%d/%s' % (
- HOST, server.port, os.path.split(CERTFILE)[1])
- f = urllib.urlopen(url)
+ url = 'https://localhost:%d/%s' % (
+ server.port, os.path.split(CERTFILE)[1])
+ context = ssl.create_default_context(cafile=CERTFILE)
+ f = urllib2.urlopen(url, context=context)
try:
dlen = f.info().getheader("content-length")
if dlen and (int(dlen) > 0):

49
SOURCES/00222-add-2014-bit-dh-key.patch

@ -0,0 +1,49 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1427947446 14400
# Node ID 4f2391e866434a94ca6d87dff5ea01fcab91d08a
# Parent 5d88f653187203d85f4cfd4877f093af3919035b
replace 512 bit dh key with a 2014 bit one (closes #23844)

Patch by Cédric Krier.

diff --git a/Lib/test/dh1024.pem b/Lib/test/dh1024.pem
new file mode 100644
--- /dev/null
+++ b/Lib/test/dh1024.pem
@@ -0,0 +1,7 @@
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt
+rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0
+RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC
+-----END DH PARAMETERS-----
+
+Generated with: openssl dhparam -out dh1024.pem 1024
diff --git a/Lib/test/dh512.pem b/Lib/test/dh512.pem
deleted file mode 100644
--- a/Lib/test/dh512.pem
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN DH PARAMETERS-----
-MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak
-XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC
------END DH PARAMETERS-----
-
-These are the 512 bit DH parameters from "Assigned Number for SKIP Protocols"
-(http://www.skip-vpn.org/spec/numbers.html).
-See there for how they were generated.
-Note that g is not a generator, but this is not a problem since p is a safe prime.
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -66,7 +66,7 @@ BADKEY = data_file("badkey.pem")
NOKIACERT = data_file("nokia.pem")
NULLBYTECERT = data_file("nullbytecert.pem")
-DHFILE = data_file("dh512.pem")
+DHFILE = data_file("dh1024.pem")
BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding())

153
SOURCES/00223-pep476-verify-certs-by-default.patch

@ -0,0 +1,153 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1416798122 21600
# Node ID fb83916c3ea12899569e88a7505469a90ab1f674
# Parent c84f36a5f556867c2ec50453dc879a500032d377
pep 476: verify certificates by default (#22417)

diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst
--- a/Doc/library/httplib.rst
+++ b/Doc/library/httplib.rst
@@ -90,9 +90,6 @@ The module provides the following classe
server's certificate. If you want to change that behaviour, you can
explicitly set *check_hostname* to False.
- .. warning::
- This does not do any verification of the server's certificate.
-
.. versionadded:: 2.0
.. versionchanged:: 2.6
@@ -104,6 +101,11 @@ The module provides the following classe
.. versionchanged:: 2.7.9
*context* and *check_hostname* was added.
+ This class now performs all the necessary certificate and hostname checks
+ by default. To revert to the previous, unverified, behavior
+ :func:`ssl._create_unverified_context` can be passed to the *context*
+ parameter.
+
.. class:: HTTPResponse(sock, debuglevel=0, strict=0)
diff --git a/Lib/httplib.py b/Lib/httplib.py
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -1193,7 +1193,7 @@ else:
self.key_file = key_file
self.cert_file = cert_file
if context is None:
- context = ssl.create_default_context()
+ context = ssl._create_default_https_context()
will_verify = context.verify_mode != ssl.CERT_NONE
if check_hostname is None:
check_hostname = will_verify
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -427,8 +427,7 @@ def create_default_context(purpose=Purpo
context.load_default_certs(purpose)
return context
-
-def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None,
+def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None,
check_hostname=False, purpose=Purpose.SERVER_AUTH,
certfile=None, keyfile=None,
cafile=None, capath=None, cadata=None):
@@ -469,6 +468,14 @@ def _create_stdlib_context(protocol=PROT
return context
+# Used by http.client if no context is explicitly passed.
+_create_default_https_context = create_default_context
+
+
+# Backwards compatibility alias, even though it's not a public name.
+_create_stdlib_context = _create_unverified_context
+
+
class SSLSocket(socket):
"""This class implements a subtype of socket.socket that wraps
the underlying OS socket in an SSL context when necessary, and
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1,10 +1,9 @@
import httplib
import array
-import httplib
-import os
import StringIO
import socket
import errno
+import os
import unittest
TestCase = unittest.TestCase
diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -5,6 +5,7 @@ import urllib2
import BaseHTTPServer
import unittest
import hashlib
+import ssl
from test import test_support
@@ -562,15 +563,37 @@ class TestUrlopen(BaseTestCase):
cafile=CERT_localhost)
self.assertEqual(data, b"we care a bit")
# Bad cert
- with self.assertRaises(urllib2.URLError) as cm:
+ with self.assertRaises(urllib2.URLError):
self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_fakehostname)
# Good cert, but mismatching hostname
handler = self.start_https_server(certfile=CERT_fakehostname)
- with self.assertRaises(ssl.CertificateError) as cm:
+ with self.assertRaises(ssl.CertificateError):
self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_fakehostname)
+ def test_https_with_cadefault(self):
+ handler = self.start_https_server(certfile=CERT_localhost)
+ # Self-signed cert should fail verification with system certificate store
+ with self.assertRaises(urllib2.URLError):
+ self.urlopen("https://localhost:%s/bizarre" % handler.port,
+ cadefault=True)
+
+ def test_https_sni(self):
+ if ssl is None:
+ self.skipTest("ssl module required")
+ if not ssl.HAS_SNI:
+ self.skipTest("SNI support required in OpenSSL")
+ sni_name = [None]
+ def cb_sni(ssl_sock, server_name, initial_context):
+ sni_name[0] = server_name
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ context.set_servername_callback(cb_sni)
+ handler = self.start_https_server(context=context, certfile=CERT_localhost)
+ context = ssl.create_default_context(cafile=CERT_localhost)
+ self.urlopen("https://localhost:%s" % handler.port, context=context)
+ self.assertEqual(sni_name[0], "localhost")
+
def test_sending_headers(self):
handler = self.start_server([(200, [], "we don't care")])
diff -up Python-2.7.5/Doc/library/xmlrpclib.rst.ver Python-2.7.5/Doc/library/xmlrpclib.rst
--- Python-2.7.5/Doc/library/xmlrpclib.rst.ver 2015-03-30 13:59:29.243493601 +0200
+++ Python-2.7.5/Doc/library/xmlrpclib.rst 2015-03-30 14:03:40.509532180 +0200
@@ -34,6 +34,10 @@ between conformable Python objects and X
constructed data. If you need to parse untrusted or unauthenticated data see
:ref:`xml-vulnerabilities`.
+.. versionchanged:: 2.7.9
+
+ For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate
+ and hostname checks by default
.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]])

103
SOURCES/00224-pep476-add-toggle-for-cert-verify.patch

@ -0,0 +1,103 @@
diff -up Python-2.7.5/Lib/ssl.py.cert Python-2.7.5/Lib/ssl.py
--- Python-2.7.5/Lib/ssl.py.cert 2015-03-30 14:52:12.172241615 +0200
+++ Python-2.7.5/Lib/ssl.py 2015-03-30 15:16:49.168185354 +0200
@@ -466,8 +466,27 @@ def _create_unverified_context(protocol=
return context
+_cert_verification_config = '/etc/python/cert-verification.cfg'
+
+def _get_verify_status(protocol):
+ context_factory = {
+ 'platform_default': _create_unverified_context,
+ 'enable': create_default_context,
+ 'disable': _create_unverified_context
+ }
+ import ConfigParser
+ try:
+ config = ConfigParser.RawConfigParser()
+ config.read(_cert_verification_config)
+ status = config.get(protocol, 'verify')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ status = 'platform_default'
+ default = context_factory.get('platform_default')
+ return context_factory.get(status, default)
+
+
# Used by http.client if no context is explicitly passed.
-_create_default_https_context = create_default_context
+_create_default_https_context = _get_verify_status('https')
# Backwards compatibility alias, even though it's not a public name.
diff -up Python-2.7.5/Lib/test/test_httplib.py.cert Python-2.7.5/Lib/test/test_httplib.py
--- Python-2.7.5/Lib/test/test_httplib.py.cert 2015-03-30 16:45:30.738794461 +0200
+++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 16:54:48.065062351 +0200
@@ -516,12 +516,24 @@ class HTTPSTest(TestCase):
h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30)
self.assertEqual(h.timeout, 30)
+ def test_networked_default(self):
+ # specific to RHEL
+ # Default settings: doesnt requires a valid cert from a trusted CA
+ test_support.requires('network')
+ with test_support.transient_internet('self-signed.pythontest.net'):
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
+ h.request('GET', '/')
+ resp = h.getresponse()
+ self.assertIn('nginx', resp.getheader('server'))
+
+ # We have to pass safe context to test cert verification
+ # RHEL by default disable cert verification
def test_networked(self):
- # Default settings: requires a valid cert from a trusted CA
import ssl
test_support.requires('network')
with test_support.transient_internet('self-signed.pythontest.net'):
- h = httplib.HTTPSConnection('self-signed.pythontest.net', 443)
+ context = ssl.create_default_context()
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
@@ -542,8 +554,10 @@ class HTTPSTest(TestCase):
def test_networked_trusted_by_default_cert(self):
# Default settings: requires a valid cert from a trusted CA
test_support.requires('network')
+ import ssl
with test_support.transient_internet('www.python.org'):
- h = httplib.HTTPSConnection('www.python.org', 443)
+ context = ssl.create_default_context()
+ h = httplib.HTTPSConnection('www.python.org', 443, context=context)
h.request('GET', '/')
resp = h.getresponse()
content_type = resp.getheader('content-type')
@@ -579,7 +592,8 @@ class HTTPSTest(TestCase):
# The custom cert isn't known to the default trust bundle
import ssl
server = self.make_server(CERT_localhost)
- h = httplib.HTTPSConnection('localhost', server.port)
+ context = ssl.create_default_context()
+ h = httplib.HTTPSConnection('localhost', server.port, context=context)
with self.assertRaises(ssl.SSLError) as exc_info:
h.request('GET', '/')
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
@@ -624,6 +638,9 @@ class HTTPSTest(TestCase):
for hp in ("www.python.org:abc", "user:password@www.python.org"):
self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp)
+ import ssl
+ context = ssl.create_default_context()
+
for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000",
"fe80::207:e9ff:fe9b", 8000),
("www.python.org:443", "www.python.org", 443),
@@ -632,7 +648,7 @@ class HTTPSTest(TestCase):
("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443),
("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b",
443)):
- c = httplib.HTTPSConnection(hp)
+ c = httplib.HTTPSConnection(hp, context=context)
self.assertEqual(h, c.host)
self.assertEqual(p, c.port)

25
SOURCES/00225-cprofile-sort-option.patch

@ -0,0 +1,25 @@
diff -up Python-2.7.5/Lib/cProfile.py.sort Python-2.7.5/Lib/cProfile.py
--- Python-2.7.5/Lib/cProfile.py.sort 2015-02-09 12:45:46.525657065 +0100
+++ Python-2.7.5/Lib/cProfile.py 2015-02-09 12:45:05.266316315 +0100
@@ -161,7 +161,7 @@ def label(code):
# ____________________________________________________________
def main():
- import os, sys
+ import os, pstats, sys
from optparse import OptionParser
usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
parser = OptionParser(usage=usage)
@@ -169,8 +169,9 @@ def main():
parser.add_option('-o', '--outfile', dest="outfile",
help="Save stats to <outfile>", default=None)
parser.add_option('-s', '--sort', dest="sort",
- help="Sort order when printing to stdout, based on pstats.Stats class",
- default=-1)
+ help="Sort order when printing to stdout, based on pstats.Stats class",
+ default=-1,
+ choices=pstats.Stats.sort_arg_dict_default.keys())
if not sys.argv[1:]:
parser.print_usage()

78
SOURCES/00227-accept-none-keyfile-loadcertchain.patch

@ -0,0 +1,78 @@
From c1f4979e7019f6c1ce9e5a02c2e3f8ca146645bc Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Mon, 11 Jul 2016 14:20:01 +0200
Subject: [PATCH] Allow the keyfile argument of SSLContext.load_cert_chain to
be set to None

---
Modules/_ssl.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 38eba1d..1786afd 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2445,8 +2445,8 @@ static PyObject *
load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {"certfile", "keyfile", "password", NULL};
- PyObject *password = NULL;
- char *certfile_bytes = NULL, *keyfile_bytes = NULL;
+ PyObject *keyfile = NULL, *keyfile_bytes = NULL, *password = NULL;
+ char *certfile_bytes = NULL;
pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback;
void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata;
_PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 };
@@ -2455,11 +2455,27 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
errno = 0;
ERR_clear_error();
if (!PyArg_ParseTupleAndKeywords(args, kwds,
- "et|etO:load_cert_chain", kwlist,
+ "et|OO:load_cert_chain", kwlist,
Py_FileSystemDefaultEncoding, &certfile_bytes,
- Py_FileSystemDefaultEncoding, &keyfile_bytes,
- &password))
+ &keyfile, &password))
return NULL;
+
+ if (keyfile && keyfile != Py_None) {
+ if (PyString_Check(keyfile)) {
+ Py_INCREF(keyfile);
+ keyfile_bytes = keyfile;
+ } else {
+ PyObject *u = PyUnicode_FromObject(keyfile);
+ if (!u)
+ goto error;
+ keyfile_bytes = PyUnicode_AsEncodedString(
+ u, Py_FileSystemDefaultEncoding, NULL);
+ Py_DECREF(u);
+ if (!keyfile_bytes)
+ goto error;
+ }
+ }
+
if (password && password != Py_None) {
if (PyCallable_Check(password)) {
pw_info.callable = password;
@@ -2489,7 +2505,7 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
}
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state);
r = SSL_CTX_use_PrivateKey_file(self->ctx,
- keyfile_bytes ? keyfile_bytes : certfile_bytes,
+ keyfile_bytes ? PyBytes_AS_STRING(keyfile_bytes) : certfile_bytes,
SSL_FILETYPE_PEM);
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
if (r != 1) {
@@ -2521,8 +2537,8 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
error:
SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata);
+ Py_XDECREF(keyfile_bytes);
PyMem_Free(pw_info.password);
- PyMem_Free(keyfile_bytes);
PyMem_Free(certfile_bytes);
return NULL;
}
--
2.7.4

260
SOURCES/00228-backport-ssl-version.patch

@ -0,0 +1,260 @@

# HG changeset patch
# User Alex Gaynor <alex.gaynor@gmail.com>
# Date 1409862802 25200
# Node ID 16c86a6bdbe2a545dd2de02dc9f347c2b3ae7220
# Parent f17ab9fed3b03191df975ecdde2cc07cee915319
Issue #20421: Add a .version() method to SSL sockets exposing the actual protocol version in use.

Backport from default.

diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -867,10 +867,10 @@ SSL sockets also have the following addi
.. method:: SSLSocket.selected_npn_protocol()
- Returns the protocol that was selected during the TLS/SSL handshake. If
- :meth:`SSLContext.set_npn_protocols` was not called, or if the other party
- does not support NPN, or if the handshake has not yet happened, this will
- return ``None``.
+ Returns the higher-level protocol that was selected during the TLS/SSL
+ handshake. If :meth:`SSLContext.set_npn_protocols` was not called, or
+ if the other party does not support NPN, or if the handshake has not yet
+ happened, this will return ``None``.
.. versionadded:: 2.7.9
@@ -882,6 +882,16 @@ SSL sockets also have the following addi
returned socket should always be used for further communication with the
other side of the connection, rather than the original socket.
+.. method:: SSLSocket.version()
+
+ Return the actual SSL protocol version negotiated by the connection
+ as a string, or ``None`` is no secure connection is established.
+ As of this writing, possible return values include ``"SSLv2"``,
+ ``"SSLv3"``, ``"TLSv1"``, ``"TLSv1.1"`` and ``"TLSv1.2"``.
+ Recent OpenSSL versions may define more return values.
+
+ .. versionadded:: 3.5
+
.. attribute:: SSLSocket.context
The :class:`SSLContext` object this SSL socket is tied to. If the SSL
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -862,6 +862,15 @@ class SSLSocket(socket):
return None
return self._sslobj.tls_unique_cb()
+ def version(self):
+ """
+ Return a string identifying the protocol version used by the
+ current SSL channel, or None if there is no established channel.
+ """
+ if self._sslobj is None:
+ return None
+ return self._sslobj.version()
+
def wrap_socket(sock, keyfile=None, certfile=None,
server_side=False, cert_reqs=CERT_NONE,
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -1904,7 +1904,8 @@ else:
'compression': s.compression(),
'cipher': s.cipher(),
'peercert': s.getpeercert(),
- 'client_npn_protocol': s.selected_npn_protocol()
+ 'client_npn_protocol': s.selected_npn_protocol(),
+ 'version': s.version(),
})
s.close()
stats['server_npn_protocols'] = server.selected_protocols
@@ -1912,6 +1913,13 @@ else:
def try_protocol_combo(server_protocol, client_protocol, expect_success,
certsreqs=None, server_options=0, client_options=0):
+ """
+ Try to SSL-connect using *client_protocol* to *server_protocol*.
+ If *expect_success* is true, assert that the connection succeeds,
+ if it's false, assert that the connection fails.
+ Also, if *expect_success* is a string, assert that it is the protocol
+ version actually used by the connection.
+ """
if certsreqs is None:
certsreqs = ssl.CERT_NONE
certtype = {
@@ -1941,8 +1949,8 @@ else:
ctx.load_cert_chain(CERTFILE)
ctx.load_verify_locations(CERTFILE)
try:
- server_params_test(client_context, server_context,
- chatty=False, connectionchatty=False)
+ stats = server_params_test(client_context, server_context,
+ chatty=False, connectionchatty=False)
# Protocol mismatch can result in either an SSLError, or a
# "Connection reset by peer" error.
except ssl.SSLError:
@@ -1957,6 +1965,10 @@ else:
"Client protocol %s succeeded with server protocol %s!"
% (ssl.get_protocol_name(client_protocol),
ssl.get_protocol_name(server_protocol)))
+ elif (expect_success is not True
+ and expect_success != stats['version']):
+ raise AssertionError("version mismatch: expected %r, got %r"
+ % (expect_success, stats['version']))
class ThreadedTests(unittest.TestCase):
@@ -2186,17 +2198,17 @@ else:
sys.stdout.write(
" SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
% str(x))
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3')
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1')
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
# Server with specific SSL options
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False,
@@ -2213,9 +2225,9 @@ else:
"""Connecting to an SSLv3 server with various client options"""
if support.verbose:
sys.stdout.write("\n")
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3')
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL)
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED)
if hasattr(ssl, 'PROTOCOL_SSLv2'):
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False,
@@ -2223,7 +2235,7 @@ else:
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
if no_sslv2_implies_sslv3_hello():
# No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, True,
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, 'SSLv3',
client_options=ssl.OP_NO_SSLv2)
@skip_if_broken_ubuntu_ssl
@@ -2231,9 +2243,9 @@ else:
"""Connecting to a TLSv1 server with various client options"""
if support.verbose:
sys.stdout.write("\n")
- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1')
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL)
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED)
if hasattr(ssl, 'PROTOCOL_SSLv2'):
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
@@ -2248,14 +2260,14 @@ else:
Testing against older TLS versions."""
if support.verbose:
sys.stdout.write("\n")
- try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, True)
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
if hasattr(ssl, 'PROTOCOL_SSLv2'):
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv23, False,
client_options=ssl.OP_NO_TLSv1_1)
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, True)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1')
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False)
@@ -2268,7 +2280,7 @@ else:
Testing against older TLS versions."""
if support.verbose:
sys.stdout.write("\n")
- try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, True,
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2',
server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,
client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,)
if hasattr(ssl, 'PROTOCOL_SSLv2'):
@@ -2277,7 +2289,7 @@ else:
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv23, False,
client_options=ssl.OP_NO_TLSv1_2)
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, True)
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2')
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False)
@@ -2619,6 +2631,21 @@ else:
s.connect((HOST, server.port))
self.assertIn("no shared cipher", str(server.conn_errors[0]))
+ def test_version_basic(self):
+ """
+ Basic tests for SSLSocket.version().
+ More tests are done in the test_protocol_*() methods.
+ """
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ with ThreadedEchoServer(CERTFILE,
+ ssl_version=ssl.PROTOCOL_TLSv1,
+ chatty=False) as server:
+ with closing(context.wrap_socket(socket.socket())) as s:
+ self.assertIs(s.version(), None)
+ s.connect((HOST, server.port))
+ self.assertEqual(s.version(), "TLSv1")
+ self.assertIs(s.version(), None)
+
@unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
def test_default_ecdh_curve(self):
# Issue #21015: elliptic curve-based Diffie Hellman key exchange
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -1384,6 +1384,18 @@ static PyObject *PySSL_cipher (PySSLSock
return NULL;
}
+static PyObject *PySSL_version(PySSLSocket *self)
+{
+ const char *version;
+
+ if (self->ssl == NULL)
+ Py_RETURN_NONE;
+ version = SSL_get_version(self->ssl);
+ if (!strcmp(version, "unknown"))
+ Py_RETURN_NONE;
+ return PyUnicode_FromString(version);
+}
+
#ifdef OPENSSL_NPN_NEGOTIATED
static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) {
const unsigned char *out;
@@ -1907,6 +1919,7 @@ static PyMethodDef PySSLMethods[] = {
{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
PySSL_peercert_doc},
{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
+ {"version", (PyCFunction)PySSL_version, METH_NOARGS},
#ifdef OPENSSL_NPN_NEGOTIATED
{"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS},
#endif

48
SOURCES/00229-Expect-a-failure-when-trying-to-connect-with-SSLv2-c.patch

@ -0,0 +1,48 @@
From a1d7acf899fccd0eda10e011e2d11d1d81c2d9e6 Mon Sep 17 00:00:00 2001
From: Robert Kuska <rkuska@redhat.com>
Date: Wed, 9 Mar 2016 20:16:17 +0100
Subject: [PATCH] Expect a failure when trying to connect with SSLv2 client to
SSLv23 server. Default value of options in tests enchanced to reflect SSLv2
being disabled

---
Lib/test/test_ssl.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 11122db..b2ba186 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -691,7 +691,7 @@ class ContextTests(unittest.TestCase):
@skip_if_broken_ubuntu_ssl
def test_options(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
- self.assertEqual(ssl.OP_ALL, ctx.options)
+ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ctx.options)
ctx.options |= ssl.OP_NO_SSLv2
self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2,
ctx.options)
@@ -2152,17 +2152,17 @@ else:
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
# SSLv23 client with specific SSL options
if no_sslv2_implies_sslv3_hello():
# No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
client_options=ssl.OP_NO_SSLv2)
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True,
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
client_options=ssl.OP_NO_SSLv3)
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True,
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
client_options=ssl.OP_NO_TLSv1)
@skip_if_broken_ubuntu_ssl
--
2.5.0

18
SOURCES/00230-force-all-child-threads-to-terminate-in-TestForkInThread.patch

@ -0,0 +1,18 @@
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index 413889a..fb312aa 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -237,7 +237,12 @@ class TestForkInThread(unittest.TestCase):
if pid == 0: # child
os.close(self.read_fd)
os.write(self.write_fd, "OK")
- sys.exit(0)
+ # Exiting the thread normally in the child process can leave
+ # any additional threads (such as the one started by
+ # importing _tkinter) still running, and this can prevent
+ # the half-zombie child process from being cleaned up. See
+ # Issue #26456.
+ os._exit(0)
else: # parent
os.close(self.write_fd)

11
SOURCES/00231-Initialize-OpenSSL_add_all_digests-in-_hashlib.patch

@ -0,0 +1,11 @@
diff -up Python-2.7.5/Modules/_hashopenssl.c.digest Python-2.7.5/Modules/_hashopenssl.c
--- Python-2.7.5/Modules/_hashopenssl.c.digest 2016-01-05 10:53:02.947312688 +0100
+++ Python-2.7.5/Modules/_hashopenssl.c 2016-01-05 10:53:15.504431960 +0100
@@ -984,6 +984,7 @@ init_hashlib(void)
SSL_load_error_strings();
SSL_library_init();
ERR_load_crypto_strings();
+ OpenSSL_add_all_digests();
Py_TYPE(&EVPtype) = &PyType_Type;
if (PyType_Ready(&EVPtype) < 0)

9
SOURCES/00232-man-page-date-macro-removal.patch

@ -0,0 +1,9 @@
diff -r 62e3b7af0697 -r db8d7f376d24 Misc/python.man
--- a/Misc/python.man Mon Mar 21 10:38:58 2016 +0100
+++ b/Misc/python.man Mon Mar 21 13:54:28 2016 +0100
@@ -1,4 +1,4 @@
-.TH PYTHON "1" "$Date$"
+.TH PYTHON "1"
.\" To view this file while editing, run it through groff:
.\" groff -Tascii -man python.man | less

2274
SOURCES/00233-Computed-Goto-dispatch.patch

File diff suppressed because it is too large Load Diff

137
SOURCES/00234-PEP493-updated-implementation.patch

@ -0,0 +1,137 @@
@@ -, +, @@
---
Lib/ssl.py | 53 ++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 38 insertions(+), 15 deletions(-)
--- a/Lib/ssl.py
+++ a/Lib/ssl.py
@@ -466,24 +466,47 @@ def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None,
return context
+_https_verify_envvar = 'PYTHONHTTPSVERIFY'
_cert_verification_config = '/etc/python/cert-verification.cfg'
-def _get_verify_status(protocol):
- context_factory = {
- 'platform_default': _create_unverified_context,
- 'enable': create_default_context,
- 'disable': _create_unverified_context
- }
- import ConfigParser
- try:
- config = ConfigParser.RawConfigParser()
- config.read(_cert_verification_config)
- status = config.get(protocol, 'verify')
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
- status = 'platform_default'
- default = context_factory.get('platform_default')
- return context_factory.get(status, default)
+# To provide same function name as specified in PEP493 with keeping
+# the old name as defined in our previous patch
+_get_https_context_factory = lambda: _get_verify_status('https')
+def _get_verify_status(protocol):
+ # See https://www.python.org/dev/peps/pep-0493/#recommendation-for-combined-feature-backports
+ # Check for an environmental override of the default behaviour
+ if not sys.flags.ignore_environment:
+ config_setting = os.environ.get(_https_verify_envvar)
+ if config_setting is not None:
+ if config_setting == '0':
+ return _create_unverified_context
+ return create_default_context
+
+ # Check for a system-wide override of the default behaviour
+ context_factory = {
+ 'platform_default': create_default_context,
+ 'enable': create_default_context,
+ 'disable': _create_unverified_context
+ }
+ import ConfigParser
+ try:
+ config = ConfigParser.RawConfigParser()
+ config.read(_cert_verification_config)
+ status = config.get(protocol, 'verify')
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ status = 'platform_default'
+ default = context_factory.get('platform_default')
+ return context_factory.get(status, default)
+
+# See https://www.python.org/dev/peps/pep-0493/#feature-configuration-api
+def _https_verify_certificates(enable=True):
+ """Verify server HTTPS certificates by default?"""
+ global _create_default_https_context
+ if enable:
+ _create_default_https_context = create_default_context
+ else:
+ _create_default_https_context = _create_unverified_context
# Used by http.client if no context is explicitly passed.
_create_default_https_context = _get_verify_status('https')
--- a/Lib/test/test_ssl.py Thu Jan 14 21:57:57 2016 -0800
+++ a/Lib/test/test_ssl.py Fri Jan 15 17:41:37 2016 +1000
@@ -4,6 +4,7 @@
import sys
import unittest
from test import test_support as support
+from test.script_helper import assert_python_ok
import asyncore
import socket
import select
@@ -1149,6 +1149,57 @@
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
+ def test__https_verify_certificates(self):
+ # Unit test to check the contect factory mapping
+ # The factories themselves are tested above
+ # This test will fail by design if run under PYTHONHTTPSVERIFY=0
+ # (as will various test_httplib tests)
+
+ # Uses a fresh SSL module to avoid affecting the real one
+ local_ssl = support.import_fresh_module("ssl")
+ # Certificate verification is enabled by default
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl.create_default_context)
+ # Turn default verification off
+ local_ssl._https_verify_certificates(enable=False)
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl._create_unverified_context)
+ # And back on
+ local_ssl._https_verify_certificates(enable=True)
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl.create_default_context)
+ # The default behaviour is to enable
+ local_ssl._https_verify_certificates(enable=False)
+ local_ssl._https_verify_certificates()
+ self.assertIs(local_ssl._create_default_https_context,
+ local_ssl.create_default_context)
+
+ def test__https_verify_envvar(self):
+ # Unit test to check the PYTHONHTTPSVERIFY handling
+ # Need to use a subprocess so it can still be run under -E
+ https_is_verified = """import ssl, sys; \
+ status = "Error: _create_default_https_context does not verify certs" \
+ if ssl._create_default_https_context is \
+ ssl._create_unverified_context \
+ else None; \
+ sys.exit(status)"""
+ https_is_not_verified = """import ssl, sys; \
+ status = "Error: _create_default_https_context verifies certs" \
+ if ssl._create_default_https_context is \
+ ssl.create_default_context \
+ else None; \
+ sys.exit(status)"""
+ extra_env = {}
+ # Omitting it leaves verification on
+ assert_python_ok("-c", https_is_verified, **extra_env)
+ # Setting it to zero turns verification off
+ extra_env[ssl._https_verify_envvar] = "0"
+ assert_python_ok("-c", https_is_not_verified, **extra_env)
+ # Any other value should also leave it on
+ for setting in ("", "1", "enabled", "foo"):
+ extra_env[ssl._https_verify_envvar] = setting
+ assert_python_ok("-c", https_is_verified, **extra_env)
+
def test_check_hostname(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
self.assertFalse(ctx.check_hostname)

226
SOURCES/00235-JSON-decoder-lone-surrogates-fix.patch

@ -0,0 +1,226 @@
From 90986ef48c0df602ab38aa831a24e99e9ed61e7e Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Mon, 4 Apr 2016 15:55:28 +0200
Subject: [PATCH] JSON decoder now accepts lone surrogates

---
Lib/json/decoder.py | 35 ++++++++++++------------
Lib/json/tests/test_scanstring.py | 56 ++++++++++++++++++++++++++++++++++++---
Modules/_json.c | 49 +++++++++-------------------------
3 files changed, 83 insertions(+), 57 deletions(-)

diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py
index dfcc628..1b43238 100644
--- a/Lib/json/decoder.py
+++ b/Lib/json/decoder.py
@@ -62,6 +62,16 @@ BACKSLASH = {

DEFAULT_ENCODING = "utf-8"

+def _decode_uXXXX(s, pos):
+ esc = s[pos + 1:pos + 5]
+ if len(esc) == 4 and esc[1] not in 'xX':
+ try:
+ return int(esc, 16)
+ except ValueError:
+ pass
+ msg = "Invalid \\uXXXX escape"
+ raise ValueError(errmsg(msg, s, pos))
+
def py_scanstring(s, end, encoding=None, strict=True,
_b=BACKSLASH, _m=STRINGCHUNK.match):
"""Scan the string s for a JSON string. End is the index of the
@@ -116,25 +126,16 @@ def py_scanstring(s, end, encoding=None, strict=True,
end += 1
else:
# Unicode escape sequence
- esc = s[end + 1:end + 5]
- next_end = end + 5
- if len(esc) != 4:
- msg = "Invalid \\uXXXX escape"
- raise ValueError(errmsg(msg, s, end))
- uni = int(esc, 16)
+ uni = _decode_uXXXX(s, end)
+ end += 5
# Check for surrogate pair on UCS-4 systems
- if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
- msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
- if not s[end + 5:end + 7] == '\\u':
- raise ValueError(errmsg(msg, s, end))
- esc2 = s[end + 7:end + 11]
- if len(esc2) != 4:
- raise ValueError(errmsg(msg, s, end))
- uni2 = int(esc2, 16)
- uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
- next_end += 6
+ if sys.maxunicode > 65535 and \
+ 0xd800 <= uni <= 0xdbff and s[end:end + 2] == '\\u':
+ uni2 = _decode_uXXXX(s, end + 1)
+ if 0xdc00 <= uni2 <= 0xdfff:
+ uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
+ end += 6
char = unichr(uni)
- end = next_end
# Append the unescaped character
_append(char)
return u''.join(chunks), end
diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py
index 4fef8cb..ed80a41 100644
--- a/Lib/json/tests/test_scanstring.py
+++ b/Lib/json/tests/test_scanstring.py
@@ -5,10 +5,6 @@ from json.tests import PyTest, CTest
class TestScanstring(object):
def test_scanstring(self):
scanstring = self.json.decoder.scanstring
- self.assertEqual(
- scanstring('"z\\ud834\\udd20x"', 1, None, True),
- (u'z\U0001d120x', 16))
-
if sys.maxunicode == 65535:
self.assertEqual(
scanstring(u'"z\U0001d120x"', 1, None, True),
@@ -94,6 +90,58 @@ class TestScanstring(object):
scanstring('["Bad value", truth]', 2, None, True),
(u'Bad value', 12))

+ def test_surrogates(self):
+ scanstring = self.json.decoder.scanstring
+ def assertScan(given, expect):
+ self.assertEqual(scanstring(given, 1, None, True),
+ (expect, len(given)))
+ if not isinstance(given, unicode):
+ given = unicode(given)
+ self.assertEqual(scanstring(given, 1, None, True),
+ (expect, len(given)))
+
+ surrogates = unichr(0xd834) + unichr(0xdd20)
+ assertScan('"z\\ud834\\u0079x"', u'z\ud834yx')
+ assertScan('"z\\ud834\\udd20x"', u'z\U0001d120x')
+ assertScan('"z\\ud834\\ud834\\udd20x"', u'z\ud834\U0001d120x')
+ assertScan('"z\\ud834x"', u'z\ud834x')
+ assertScan(u'"z\\ud834\udd20x12345"', u'z%sx12345' % surrogates)
+ assertScan('"z\\udd20x"', u'z\udd20x')
+ assertScan(u'"z\ud834\udd20x"', u'z\ud834\udd20x')
+ assertScan(u'"z\ud834\\udd20x"', u'z%sx' % surrogates)
+ assertScan(u'"z\ud834x"', u'z\ud834x')
+
+ def test_bad_escapes(self):
+ scanstring = self.json.decoder.scanstring
+ bad_escapes = [
+ '"\\"',
+ '"\\x"',
+ '"\\u"',
+ '"\\u0"',
+ '"\\u01"',
+ '"\\u012"',
+ '"\\uz012"',
+ '"\\u0z12"',
+ '"\\u01z2"',
+ '"\\u012z"',
+ '"\\u0x12"',
+ '"\\u0X12"',
+ '"\\ud834\\"',
+ '"\\ud834\\u"',
+ '"\\ud834\\ud"',
+ '"\\ud834\\udd"',
+ '"\\ud834\\udd2"',
+ '"\\ud834\\uzdd2"',
+ '"\\ud834\\udzd2"',
+ '"\\ud834\\uddz2"',
+ '"\\ud834\\udd2z"',
+ '"\\ud834\\u0x20"',
+ '"\\ud834\\u0X20"',
+ ]
+ for s in bad_escapes:
+ with self.assertRaises(ValueError):
+ scanstring(s, 1, None, True)
+
def test_issue3623(self):
self.assertRaises(ValueError, self.json.decoder.scanstring, b"xxx", 1,
"xxx")
diff --git a/Modules/_json.c b/Modules/_json.c
index 7c925fd..56d9ee4 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -524,16 +524,10 @@ scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_s
}
#ifdef Py_UNICODE_WIDE
/* Surrogate pair */
- if ((c & 0xfc00) == 0xd800) {
+ if ((c & 0xfc00) == 0xd800 && end + 6 < len &&
+ buf[next++] == '\\' &&
+ buf[next++] == 'u') {
Py_UNICODE c2 = 0;
- if (end + 6 >= len) {
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);
- goto bail;
- }
- if (buf[next++] != '\\' || buf[next++] != 'u') {
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);
- goto bail;
- }
end += 6;
/* Decode 4 hex digits */
for (; next < end; next++) {
@@ -554,15 +548,10 @@ scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_s
goto bail;
}
}
- if ((c2 & 0xfc00) != 0xdc00) {
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);
- goto bail;
- }
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));
- }
- else if ((c & 0xfc00) == 0xdc00) {
- raise_errmsg("Unpaired low surrogate", pystr, end - 5);
- goto bail;
+ if ((c2 & 0xfc00) == 0xdc00)
+ c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));
+ else
+ end -= 6;
}
#endif
}
@@ -703,16 +692,9 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
}
#ifdef Py_UNICODE_WIDE
/* Surrogate pair */
- if ((c & 0xfc00) == 0xd800) {
+ if ((c & 0xfc00) == 0xd800 && end + 6 < len &&
+ buf[next++] == '\\' && buf[next++] == 'u') {
Py_UNICODE c2 = 0;
- if (end + 6 >= len) {
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);
- goto bail;
- }
- if (buf[next++] != '\\' || buf[next++] != 'u') {
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);
- goto bail;
- }
end += 6;
/* Decode 4 hex digits */
for (; next < end; next++) {
@@ -733,15 +715,10 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
goto bail;
}
}
- if ((c2 & 0xfc00) != 0xdc00) {
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);
- goto bail;
- }
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));
- }
- else if ((c & 0xfc00) == 0xdc00) {
- raise_errmsg("Unpaired low surrogate", pystr, end - 5);
- goto bail;
+ if ((c2 & 0xfc00) == 0xdc00)
+ c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));
+ else
+ end -= 6;
}
#endif
}
--
2.5.5

101
SOURCES/00236-use-Py_ssize_t-for-file-offset-and-length-computations-in-iteration.patch

@ -0,0 +1,101 @@
From 6bebd55022c82829c0b15d24d2ca99edd22562df Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Wed, 4 May 2016 10:39:40 +0200
Subject: [PATCH] use Py_ssize_t for file offset and length computations in
iteration

---
Lib/test/test_file2k.py | 16 +++++++++++++++-
Objects/fileobject.c | 15 +++++++--------
2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py
index 5a3c354..8f94cee 100644
--- a/Lib/test/test_file2k.py
+++ b/Lib/test/test_file2k.py
@@ -14,7 +14,7 @@ except ImportError:
threading = None

from test import test_support
-from test.test_support import TESTFN, run_unittest
+from test.test_support import TESTFN, run_unittest, requires
from UserList import UserList

class AutoFileTests(unittest.TestCase):
@@ -416,6 +416,20 @@ class OtherFileTests(unittest.TestCase):
finally:
os.unlink(TESTFN)

+ @test_support.precisionbigmemtest(2**31, 2.5, dry_run=False)
+ def test_very_long_line(self, size):
+ # Issue #22526
+ requires('largefile')
+ with open(TESTFN, "wb") as fp:
+ fp.seek(size - 1)
+ fp.write("\0")
+ with open(TESTFN, "rb") as fp:
+ for l in fp:
+ pass
+ self.assertEqual(len(l), size)
+ self.assertEqual(l.count("\0"), size)
+ l = None
+
class FileSubclassTests(unittest.TestCase):

def testExit(self):
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 76cdf74..fabe207 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -2230,7 +2230,7 @@ drop_readahead(PyFileObject *f)
(unless at EOF) and no more than bufsize. Returns negative value on
error, will set MemoryError if bufsize bytes cannot be allocated. */
static int
-readahead(PyFileObject *f, int bufsize)
+readahead(PyFileObject *f, Py_ssize_t bufsize)
{
Py_ssize_t chunksize;

@@ -2268,7 +2268,7 @@ readahead(PyFileObject *f, int bufsize)
logarithmic buffer growth to about 50 even when reading a 1gb line. */

static PyStringObject *
-readahead_get_line_skip(PyFileObject *f, int skip, int bufsize)
+readahead_get_line_skip(PyFileObject *f, Py_ssize_t skip, Py_ssize_t bufsize)
{
PyStringObject* s;
char *bufptr;
@@ -2288,10 +2288,10 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize)
bufptr++; /* Count the '\n' */
len = bufptr - f->f_bufptr;
s = (PyStringObject *)
- PyString_FromStringAndSize(NULL, skip+len);
+ PyString_FromStringAndSize(NULL, skip + len);
if (s == NULL)
return NULL;
- memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len);
+ memcpy(PyString_AS_STRING(s) + skip, f->f_bufptr, len);
f->f_bufptr = bufptr;
if (bufptr == f->f_bufend)
drop_readahead(f);
@@ -2299,14 +2299,13 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize)
bufptr = f->f_bufptr;
buf = f->f_buf;
f->f_buf = NULL; /* Force new readahead buffer */
- assert(skip+len < INT_MAX);
- s = readahead_get_line_skip(
- f, (int)(skip+len), bufsize + (bufsize>>2) );
+ assert(len <= PY_SSIZE_T_MAX - skip);
+ s = readahead_get_line_skip(f, skip + len, bufsize + (bufsize>>2));
if (s == NULL) {
PyMem_Free(buf);
return NULL;
}
- memcpy(PyString_AS_STRING(s)+skip, bufptr, len);
+ memcpy(PyString_AS_STRING(s) + skip, bufptr, len);
PyMem_Free(buf);
}
return s;
--
2.5.5

34
SOURCES/00237-CVE-2016-0772-smtplib.patch

@ -0,0 +1,34 @@
From 5b67aca6fb4246e84981d6361ba218bd52e73ac2 Mon Sep 17 00:00:00 2001
From: Tomas Orsava <torsava@redhat.com>
Date: Tue, 21 Jun 2016 15:52:03 +0200
Subject: [PATCH] Raise an error when STARTTLS fails

CVE-2016-0772 python: smtplib StartTLS stripping attack
rhbz#1303647: https://bugzilla.redhat.com/show_bug.cgi?id=1303647

Based on an upstream change by Benjamin Peterson <benjamin@python.org>
- in changeset 101886:b3ce713fb9be 2.7
- https://hg.python.org/cpython/rev/b3ce713fb9be
---
Lib/smtplib.py | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/Lib/smtplib.py b/Lib/smtplib.py
index dc16ef6..8bc806b 100755
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -655,6 +655,11 @@ class SMTP:
self.ehlo_resp = None
self.esmtp_features = {}
self.does_esmtp = 0
+ else:
+ # RFC 3207:
+ # 501 Syntax error (no parameters allowed)
+ # 454 TLS not available due to temporary reason
+ raise SMTPResponseException(resp, reply)
return (resp, reply)
def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
--
2.5.5

158
SOURCES/00238-CVE-2016-5699-httplib.patch

@ -0,0 +1,158 @@
From e91c46c7a1a904eba04e29cdf896c99cb546d989 Mon Sep 17 00:00:00 2001
From: Tomas Orsava <torsava@redhat.com>
Date: Wed, 22 Jun 2016 17:06:01 +0200
Subject: [PATCH] Disabled HTTP header injections in httplib

CVE-2016-5699 python: http protocol steam injection attack
rhbz#1303699 : https://bugzilla.redhat.com/show_bug.cgi?id=1303699

Based on an upstream change by Demian Brecht and Serhiy Storchaka
- in changeset 94951:1c45047c5102 2.7
- https://hg.python.org/cpython/rev/1c45047c5102
---
Lib/httplib.py | 40 +++++++++++++++++++++++++++++++++-
Lib/test/test_httplib.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/Lib/httplib.py b/Lib/httplib.py
index 8e02ac3..592ee57 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -68,6 +68,7 @@ Req-sent-unread-response _CS_REQ_SENT <response_class>
from array import array
import os
+import re
import socket
from sys import py3kwarning
from urlparse import urlsplit
@@ -218,6 +219,34 @@ _MAXLINE = 65536
# maximum amount of headers accepted
_MAXHEADERS = 100
+# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
+#
+# VCHAR = %x21-7E
+# obs-text = %x80-FF
+# header-field = field-name ":" OWS field-value OWS
+# field-name = token
+# field-value = *( field-content / obs-fold )
+# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+# field-vchar = VCHAR / obs-text
+#
+# obs-fold = CRLF 1*( SP / HTAB )
+# ; obsolete line folding
+# ; see Section 3.2.4
+
+# token = 1*tchar
+#
+# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
+# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
+# / DIGIT / ALPHA
+# ; any VCHAR, except delimiters
+#
+# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1
+
+# the patterns for both name and value are more leniant than RFC
+# definitions to allow for backwards compatibility
+_is_legal_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match
+_is_illegal_header_value = re.compile(r'\n(?![ \t])|\r(?![ \t\n])').search
+
class HTTPMessage(mimetools.Message):
@@ -956,7 +985,16 @@ class HTTPConnection:
if self.__state != _CS_REQ_STARTED:
raise CannotSendHeader()
- hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values]))
+ header = '%s' % header
+ if not _is_legal_header_name(header):
+ raise ValueError('Invalid header name %r' % (header,))
+
+ values = [str(v) for v in values]
+ for one_value in values:
+ if _is_illegal_header_value(one_value):
+ raise ValueError('Invalid header value %r' % (one_value,))
+
+ hdr = '%s: %s' % (header, '\r\n\t'.join(values))
self._output(hdr)
def endheaders(self, message_body=None):
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index c29aceb..29af589 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -133,6 +133,33 @@ class HeaderTests(TestCase):
conn.putheader('Content-length',42)
self.assertTrue('Content-length: 42' in conn._buffer)
+ conn.putheader('Foo', ' bar ')
+ self.assertIn(b'Foo: bar ', conn._buffer)
+ conn.putheader('Bar', '\tbaz\t')
+ self.assertIn(b'Bar: \tbaz\t', conn._buffer)
+ conn.putheader('Authorization', 'Bearer mytoken')
+ self.assertIn(b'Authorization: Bearer mytoken', conn._buffer)
+ conn.putheader('IterHeader', 'IterA', 'IterB')
+ self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer)
+ conn.putheader('LatinHeader', b'\xFF')
+ self.assertIn(b'LatinHeader: \xFF', conn._buffer)
+ conn.putheader('Utf8Header', b'\xc3\x80')
+ self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer)
+ conn.putheader('C1-Control', b'next\x85line')
+ self.assertIn(b'C1-Control: next\x85line', conn._buffer)
+ conn.putheader('Embedded-Fold-Space', 'is\r\n allowed')
+ self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer)
+ conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed')
+ self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer)
+ conn.putheader('Key Space', 'value')
+ self.assertIn(b'Key Space: value', conn._buffer)
+ conn.putheader('KeySpace ', 'value')
+ self.assertIn(b'KeySpace : value', conn._buffer)
+ conn.putheader(b'Nonbreak\xa0Space', 'value')
+ self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer)
+ conn.putheader(b'\xa0NonbreakSpace', 'value')
+ self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer)
+
def test_ipv6host_header(self):
# Default host header on IPv6 transaction should wrapped by [] if
# its actual IPv6 address
@@ -152,6 +179,35 @@ class HeaderTests(TestCase):
conn.request('GET', '/foo')
self.assertTrue(sock.data.startswith(expected))
+ def test_invalid_headers(self):
+ conn = httplib.HTTPConnection('example.com')
+ conn.sock = FakeSocket('')
+ conn.putrequest('GET', '/')
+
+ # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no
+ # longer allowed in header names
+ cases = (
+ (b'Invalid\r\nName', b'ValidValue'),
+ (b'Invalid\rName', b'ValidValue'),
+ (b'Invalid\nName', b'ValidValue'),
+ (b'\r\nInvalidName', b'ValidValue'),
+ (b'\rInvalidName', b'ValidValue'),
+ (b'\nInvalidName', b'ValidValue'),
+ (b' InvalidName', b'ValidValue'),
+ (b'\tInvalidName', b'ValidValue'),
+ (b'Invalid:Name', b'ValidValue'),
+ (b':InvalidName', b'ValidValue'),
+ (b'ValidName', b'Invalid\r\nValue'),
+ (b'ValidName', b'Invalid\rValue'),
+ (b'ValidName', b'Invalid\nValue'),
+ (b'ValidName', b'InvalidValue\r\n'),
+ (b'ValidName', b'InvalidValue\r'),
+ (b'ValidName', b'InvalidValue\n'),
+ )
+ for name, value in cases:
+ with self.assertRaisesRegexp(ValueError, 'Invalid header'):
+ conn.putheader(name, value)
+
class BasicTest(TestCase):
def test_status_lines(self):
--
2.9.0

66
SOURCES/00240-increase-smtplib-tests-timeouts.patch

@ -0,0 +1,66 @@
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py
index 14d0060d8ec..1bb66901880 100644
--- a/Lib/test/test_smtplib.py
+++ b/Lib/test/test_smtplib.py
@@ -179,31 +179,31 @@ def tearDown(self):
def testBasic(self):
# connect
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
smtp.quit()
def testNOOP(self):
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
expected = (250, 'Ok')
self.assertEqual(smtp.noop(), expected)
smtp.quit()
def testRSET(self):
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
expected = (250, 'Ok')
self.assertEqual(smtp.rset(), expected)
smtp.quit()
def testNotImplemented(self):
# EHLO isn't implemented in DebuggingServer
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
expected = (502, 'Error: command "EHLO" not implemented')
self.assertEqual(smtp.ehlo(), expected)
smtp.quit()
def testVRFY(self):
# VRFY isn't implemented in DebuggingServer
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
expected = (502, 'Error: command "VRFY" not implemented')
self.assertEqual(smtp.vrfy('nobody@nowhere.com'), expected)
self.assertEqual(smtp.verify('nobody@nowhere.com'), expected)
@@ -212,21 +212,21 @@ def testVRFY(self):
def testSecondHELO(self):
# check that a second HELO returns a message that it's a duplicate
# (this behavior is specific to smtpd.SMTPChannel)
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
smtp.helo()
expected = (503, 'Duplicate HELO/EHLO')
self.assertEqual(smtp.helo(), expected)
smtp.quit()
def testHELP(self):
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
self.assertEqual(smtp.help(), 'Error: command "HELP" not implemented')
smtp.quit()
def testSend(self):
# connect and send mail
m = 'A test message'
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
smtp.sendmail('John', 'Sally', m)
# XXX(nnorwitz): this test is flaky and dies with a bad file descriptor
# in asyncore. This sleep might help, but should really be fixed

39
SOURCES/00241-CVE-2016-5636-buffer-overflow-in-zipimport-module-fix.patch

@ -0,0 +1,39 @@
From 0f12cb75c708978f9201c1dd3464d2a8572b4544 Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Fri, 8 Jul 2016 20:24:10 +0200
Subject: [PATCH] CVE-2016-5636 fix

---
Modules/zipimport.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 7240cb4..2e6a61f 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -861,6 +861,10 @@ get_data(char *archive, PyObject *toc_entry)
&date, &crc)) {
return NULL;
}
+ if (data_size < 0) {
+ PyErr_Format(ZipImportError, "negative data size");
+ return NULL;
+ }
fp = fopen(archive, "rb");
if (!fp) {
@@ -895,6 +899,11 @@ get_data(char *archive, PyObject *toc_entry)
PyMarshal_ReadShortFromFile(fp); /* local header size */
file_offset += l; /* Start of file data */
+ if (data_size > LONG_MAX - 1) {
+ fclose(fp);
+ PyErr_NoMemory();
+ return NULL;
+ }
raw_data = PyString_FromStringAndSize((char *)NULL, compress == 0 ?
data_size : data_size + 1);
if (raw_data == NULL) {
--
2.7.4

121
SOURCES/00242-CVE-2016-1000110-httpoxy.patch

@ -0,0 +1,121 @@
From 3a184cc875709d4324d234a4b939d614a2c9bb0f Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Mon, 1 Aug 2016 11:20:11 +0200
Subject: [PATCH] =?UTF-8?q?Fix=20for=20CVE-2016-1000110=20http://bugs.pyth?=
=?UTF-8?q?on.org/issue27568=20Based=20on=20the=20patch=20by=20R=C3=A9mi?=
=?UTF-8?q?=20Rampin?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
Doc/howto/urllib2.rst | 5 +++++
Doc/library/urllib.rst | 10 ++++++++++
Doc/library/urllib2.rst | 4 ++++
Lib/test/test_urllib.py | 12 ++++++++++++
Lib/urllib.py | 9 +++++++++
5 files changed, 40 insertions(+)

diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst
index f84bf08..6542846 100644
--- a/Doc/howto/urllib2.rst
+++ b/Doc/howto/urllib2.rst
@@ -523,6 +523,11 @@ setting up a `Basic Authentication`_ handler : ::
through a proxy. However, this can be enabled by extending urllib2 as
shown in the recipe [#]_.
+.. note::
+
+ ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; see
+ the documentation on :func:`~urllib.getproxies`.
+
Sockets and Layers
==================
diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst
index c7d200d..3b9876e 100644
--- a/Doc/library/urllib.rst
+++ b/Doc/library/urllib.rst
@@ -280,6 +280,16 @@ Utility functions
find it, looks for proxy information from Mac OSX System Configuration for
Mac OS X and Windows Systems Registry for Windows.
+ .. note::
+
+ If the environment variable ``REQUEST_METHOD`` is set, which usually
+ indicates your script is running in a CGI environment, the environment
+ variable ``HTTP_PROXY`` (uppercase ``_PROXY``) will be ignored. This is
+ because that variable can be injected by a client using the "Proxy:"
+ HTTP header. If you need to use an HTTP proxy in a CGI environment,
+ either use ``ProxyHandler`` explicitly, or make sure the variable name
+ is in lowercase (or at least the ``_proxy`` suffix).
+
.. note::
urllib also exposes certain utility functions like splittype, splithost and
others parsing url into various components. But it is recommended to use
diff --git a/Doc/library/urllib2.rst b/Doc/library/urllib2.rst
index 24deeb4..46fce59 100644
--- a/Doc/library/urllib2.rst
+++ b/Doc/library/urllib2.rst
@@ -224,6 +224,10 @@ The following classes are provided:
To disable autodetected proxy pass an empty dictionary.
+ .. note::
+
+ ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set;
+ see the documentation on :func:`~urllib.getproxies`.
.. class:: HTTPPasswordMgr()
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py
index 3a273f8..3845012 100644
--- a/Lib/test/test_urllib.py
+++ b/Lib/test/test_urllib.py
@@ -161,6 +161,18 @@ class ProxyTests(unittest.TestCase):
self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com')
self.assertTrue(urllib.proxy_bypass_environment('anotherdomain.com'))
+ def test_proxy_cgi_ignore(self):
+ try:
+ self.env.set('HTTP_PROXY', 'http://somewhere:3128')
+ proxies = urllib.getproxies_environment()
+ self.assertEqual('http://somewhere:3128', proxies['http'])
+ self.env.set('REQUEST_METHOD', 'GET')
+ proxies = urllib.getproxies_environment()
+ self.assertNotIn('http', proxies)
+ finally:
+ self.env.unset('REQUEST_METHOD')
+ self.env.unset('HTTP_PROXY')
+
class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin):
"""Test urlopen() opening a fake http connection."""
diff --git a/Lib/urllib.py b/Lib/urllib.py
index f9655f9..9b31df1 100644
--- a/Lib/urllib.py
+++ b/Lib/urllib.py
@@ -1361,11 +1361,20 @@ def getproxies_environment():
[Fancy]URLopener constructor.
"""
+ # Get all variables
proxies = {}
for name, value in os.environ.items():
name = name.lower()
if value and name[-6:] == '_proxy':
proxies[name[:-6]] = value
+
+ # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY
+ # (non-all-lowercase) as it may be set from the web server by a "Proxy:"
+ # header from the client
+ # If "proxy" is lowercase, it will still be used thanks to the next block
+ if 'REQUEST_METHOD' in os.environ:
+ proxies.pop('http', None)
+
return proxies
def proxy_bypass_environment(host):
--
2.7.4

235
SOURCES/00255-Fix-ssl-module-parsing-of-GEN_RID-subject-alternative-name-fields-in-X.509-certs.patch

@ -0,0 +1,235 @@

# HG changeset patch
# User Christian Heimes <christian@python.org>
# Date 1473197135 -7200
# Node ID 74805fd9e7343649372d0b9c76b4490b2975a674
# Parent 6f4f19217d9be12be7a9c86cf1e118b140564b4f
Issue #27691: Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs.

diff --git a/Lib/test/allsans.pem b/Lib/test/allsans.pem
new file mode 100644
--- /dev/null
+++ b/Lib/test/allsans.pem
@@ -0,0 +1,37 @@
+-----BEGIN PRIVATE KEY-----
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE
+6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG
+Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm
+DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu
+A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az
+61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk
+elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb
+tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G
+kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l
+xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J
+b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/
+EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa
+czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2
+/CyWR2P3yLtOmA==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1
+MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO
+Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0
+aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO
+ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA
+pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw
+ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp
+ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC
+AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu
+b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw
+IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly
+bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA
+AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT
+VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG
+iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f
+3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ==
+-----END CERTIFICATE-----
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py
--- a/Lib/test/make_ssl_certs.py
+++ b/Lib/test/make_ssl_certs.py
@@ -20,7 +20,28 @@ req_template = """
CN = {hostname}
[req_x509_extensions]
- subjectAltName = DNS:{hostname}
+ subjectAltName = @san
+
+ [san]
+ DNS.1 = {hostname}
+ {extra_san}
+
+ [dir_sect]
+ C = XY
+ L = Castle Anthrax
+ O = Python Software Foundation
+ CN = dirname example
+
+ [princ_name]
+ realm = EXP:0, GeneralString:KERBEROS.REALM
+ principal_name = EXP:1, SEQUENCE:principal_seq
+
+ [principal_seq]
+ name_type = EXP:0, INTEGER:1
+ name_string = EXP:1, SEQUENCE:principals
+
+ [principals]
+ princ1 = GeneralString:username
[ ca ]
default_ca = CA_default
@@ -67,7 +88,7 @@ req_template = """
here = os.path.abspath(os.path.dirname(__file__))
-def make_cert_key(hostname, sign=False):
+def make_cert_key(hostname, sign=False, extra_san=''):
print("creating cert for " + hostname)
tempnames = []
for i in range(3):
@@ -75,8 +96,9 @@ def make_cert_key(hostname, sign=False):
tempnames.append(f.name)
req_file, cert_file, key_file = tempnames
try:
+ req = req_template.format(hostname=hostname, extra_san=extra_san)
with open(req_file, 'w') as f:
- f.write(req_template.format(hostname=hostname))
+ f.write(req)
args = ['req', '-new', '-days', '3650', '-nodes',
'-newkey', 'rsa:1024', '-keyout', key_file,
'-config', req_file]
@@ -120,7 +142,7 @@ def make_ca():
f.write('unique_subject = no')
with tempfile.NamedTemporaryFile("w") as t:
- t.write(req_template.format(hostname='our-ca-server'))
+ t.write(req_template.format(hostname='our-ca-server', extra_san=''))
t.flush()
with tempfile.NamedTemporaryFile() as f:
args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes',
@@ -171,6 +193,25 @@ if __name__ == '__main__':
f.write(key)
f.write(cert)
+ extra_san = [
+ 'otherName.1 = 1.2.3.4;UTF8:some other identifier',
+ 'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name',
+ 'email.1 = user@example.org',
+ 'DNS.2 = www.example.org',
+ # GEN_X400
+ 'dirName.1 = dir_sect',
+ # GEN_EDIPARTY
+ 'URI.1 = https://www.python.org/',
+ 'IP.1 = 127.0.0.1',
+ 'IP.2 = ::1',
+ 'RID.1 = 1.2.3.4.5',
+ ]
+
+ cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san))
+ with open('allsans.pem', 'w') as f:
+ f.write(key)
+ f.write(cert)
+
unmake_ca()
print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber")
check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout'])
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index fa59641..9d5816b 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -57,6 +57,8 @@ CRLFILE = data_file("revocation.crl")
SIGNED_CERTFILE = data_file("keycert3.pem")
SIGNED_CERTFILE2 = data_file("keycert4.pem")
SIGNING_CA = data_file("pycacert.pem")
+# cert with all kinds of subject alt names
+ALLSANFILE = data_file("allsans.pem")
SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem")
@@ -236,6 +238,28 @@ class BasicSocketTests(unittest.TestCase):
('IP Address', '2001:DB8:0:0:0:0:0:1\n'))
)
+ def test_parse_all_sans(self):
+ p = ssl._ssl._test_decode_cert(ALLSANFILE)
+ self.assertEqual(p['subjectAltName'],
+ (
+ ('DNS', 'allsans'),
+ ('othername', '<unsupported>'),
+ ('othername', '<unsupported>'),
+ ('email', 'user@example.org'),
+ ('DNS', 'www.example.org'),
+ ('DirName',
+ ((('countryName', 'XY'),),
+ (('localityName', 'Castle Anthrax'),),
+ (('organizationName', 'Python Software Foundation'),),
+ (('commonName', 'dirname example'),))),
+ ('URI', 'https://www.python.org/'),
+ ('IP Address', '127.0.0.1'),
+ ('IP Address', '0:0:0:0:0:0:0:1\n'),
+ ('Registered ID', '1.2.3.4.5')
+ )
+ )
+
+
def test_DER_to_PEM(self):
with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
pem = f.read()
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -953,6 +953,35 @@ static PyObject *
PyTuple_SET_ITEM(t, 1, v);
break;
+ case GEN_RID:
+ t = PyTuple_New(2);
+ if (t == NULL)
+ goto fail;
+
+ v = PyUnicode_FromString("Registered ID");
+ if (v == NULL) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(t, 0, v);
+
+ len = i2t_ASN1_OBJECT(buf, sizeof(buf)-1, name->d.rid);
+ if (len < 0) {
+ Py_DECREF(t);
+ _setSSLError(NULL, 0, __FILE__, __LINE__);
+ goto fail;
+ } else if (len >= (int)sizeof(buf)) {
+ v = PyUnicode_FromString("<INVALID>");
+ } else {
+ v = PyUnicode_FromStringAndSize(buf, len);
+ }
+ if (v == NULL) {
+ Py_DECREF(t);
+ goto fail;
+ }
+ PyTuple_SET_ITEM(t, 1, v);
+ break;
+
default:
/* for everything else, we use the OpenSSL print form */
switch (gntype) {
@@ -978,8 +1007,12 @@ static PyObject *
goto fail;
}
vptr = strchr(buf, ':');
- if (vptr == NULL)
+ if (vptr == NULL) {
+ PyErr_Format(PyExc_ValueError,
+ "Invalid value %.200s",
+ buf);
goto fail;
+ }
t = PyTuple_New(2);
if (t == NULL)
goto fail;

20
SOURCES/00257-threading-wait-clamp-remaining-time.patch

@ -0,0 +1,20 @@
diff --git a/Lib/threading.py b/Lib/threading.py
index e4c7f35..91b3849 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -351,13 +351,14 @@ class _Condition(_Verbose):
gotit = waiter.acquire(0)
if gotit:
break
- remaining = endtime - _time()
+ remaining = min(endtime - _time(), timeout)
if remaining <= 0:
break
if balancing:
delay = min(delay * 2, remaining, 0.05)
else:
delay = remaining
+ endtime = _time() + remaining
_sleep(delay)
if not gotit:
if __debug__:

14
SOURCES/00263-fix-ssl-reference-leaks.patch

@ -0,0 +1,14 @@
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index a3ea254..d0a3830 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2564,7 +2564,9 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
}
SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata);
+ Py_XDECREF(keyfile_bytes);
PyMem_Free(pw_info.password);
+ PyMem_Free(certfile_bytes);
Py_RETURN_NONE;
error:

114
SOURCES/00265-protect-key-list-during-fork.patch

@ -0,0 +1,114 @@
diff --git a/Include/pythread.h b/Include/pythread.h
index dfd6157..f3e6259 100644
--- a/Include/pythread.h
+++ b/Include/pythread.h
@@ -30,6 +30,8 @@ PyAPI_FUNC(void) PyThread_delete_key(int);
PyAPI_FUNC(int) PyThread_set_key_value(int, void *);
PyAPI_FUNC(void *) PyThread_get_key_value(int);
PyAPI_FUNC(void) PyThread_delete_key_value(int key);
+PyAPI_FUNC(int) _PyThread_AcquireKeyLock(void);
+PyAPI_FUNC(void) _PyThread_ReleaseKeyLock(void);
/* Cleanup after a fork */
PyAPI_FUNC(void) PyThread_ReInitTLS(void);
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 022d7aa..8f6cbb2 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -65,6 +65,10 @@ corresponding Unix manual entries for more information on calls.");
#include "osdefs.h"
#endif

+#ifdef WITH_THREAD
+#include "pythread.h"
+#endif
+
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
@@ -3796,7 +3800,18 @@ posix_fork1(PyObject *self, PyObject *noargs)
pid_t pid;
int result = 0;
_PyImport_AcquireLock();
+#ifdef WITH_THREAD
+ if (_PyThread_AcquireKeyLock() == 0) {
+ _PyImport_ReleaseLock();
+ PyErr_SetString(PyExc_RuntimeError,
+ "could not acquire thread key lock");
+ return NULL;
+ }
+#endif
pid = fork1();
+#ifdef WITH_THREAD
+ _PyThread_ReleaseKeyLock();
+#endif
if (pid == 0) {
/* child: this clobbers and resets the import lock. */
PyOS_AfterFork();
@@ -3829,7 +3844,18 @@ posix_fork(PyObject *self, PyObject *noargs)
pid_t pid;
int result = 0;
_PyImport_AcquireLock();
+#ifdef WITH_THREAD
+ if (_PyThread_AcquireKeyLock() == 0) {
+ _PyImport_ReleaseLock();
+ PyErr_SetString(PyExc_RuntimeError,
+ "could not acquire thread key lock");
+ return NULL;
+ }
+#endif
pid = fork();
+#ifdef WITH_THREAD
+ _PyThread_ReleaseKeyLock();
+#endif
if (pid == 0) {
/* child: this clobbers and resets the import lock. */
PyOS_AfterFork();
@@ -3955,7 +3981,18 @@ posix_forkpty(PyObject *self, PyObject *noargs)
pid_t pid;
_PyImport_AcquireLock();
+#ifdef WITH_THREAD
+ if (_PyThread_AcquireKeyLock() == 0) {
+ _PyImport_ReleaseLock();
+ PyErr_SetString(PyExc_RuntimeError,
+ "could not acquire thread key lock");
+ return NULL;
+ }
+#endif
pid = forkpty(&master_fd, NULL, NULL, NULL);
+#ifdef WITH_THREAD
+ _PyThread_ReleaseKeyLock();
+#endif
if (pid == 0) {
/* child: this clobbers and resets the import lock. */
PyOS_AfterFork();
diff --git a/Python/thread.c b/Python/thread.c
index dd333e8..957739e 100644
--- a/Python/thread.c
+++ b/Python/thread.c
@@ -387,6 +387,24 @@ PyThread_delete_key_value(int key)
PyThread_release_lock(keymutex);
}
+int
+_PyThread_AcquireKeyLock(void)
+{
+ if (keymutex == NULL) {
+ keymutex = PyThread_allocate_lock();
+ }
+ if (keymutex == NULL) {
+ return 0;
+ }
+ return PyThread_acquire_lock(keymutex, 1);
+}
+
+void
+_PyThread_ReleaseKeyLock(void)
+{
+ PyThread_release_lock(keymutex);
+}
+
/* Forget everything not associated with the current thread id.
* This function is called from PyOS_AfterFork(). It is necessary
* because other thread ids which were in use at the time of the fork

376
SOURCES/00266-fix-shutil.make_archive-ignoring-empty-dirs.patch

@ -0,0 +1,376 @@
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 420802f..d0ff2ef 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -446,17 +446,24 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
zip_filename, base_dir)
if not dry_run:
- zip = zipfile.ZipFile(zip_filename, "w",
- compression=zipfile.ZIP_DEFLATED)
-
- for dirpath, dirnames, filenames in os.walk(base_dir):
- for name in filenames:
- path = os.path.normpath(os.path.join(dirpath, name))
- if os.path.isfile(path):
- zip.write(path, path)
+ with zipfile.ZipFile(zip_filename, "w",
+ compression=zipfile.ZIP_DEFLATED) as zf:
+ path = os.path.normpath(base_dir)
+ zf.write(path, path)
+ if logger is not None:
+ logger.info("adding '%s'", path)
+ for dirpath, dirnames, filenames in os.walk(base_dir):
+ for name in sorted(dirnames):
+ path = os.path.normpath(os.path.join(dirpath, name))
+ zf.write(path, path)
if logger is not None:
logger.info("adding '%s'", path)
- zip.close()
+ for name in filenames:
+ path = os.path.normpath(os.path.join(dirpath, name))
+ if os.path.isfile(path):
+ zf.write(path, path)
+ if logger is not None:
+ logger.info("adding '%s'", path)
return zip_filename
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 9bdb724..9238489 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -10,13 +10,13 @@ import os.path
import errno
from os.path import splitdrive
from distutils.spawn import find_executable, spawn
-from shutil import (_make_tarball, _make_zipfile, make_archive,
+from shutil import (make_archive,
register_archive_format, unregister_archive_format,
get_archive_formats)
import tarfile
import warnings
-from test import test_support
+from test import test_support as support
from test.test_support import TESTFN, check_warnings, captured_stdout
TESTFN2 = TESTFN + "2"
@@ -372,139 +372,135 @@ class TestShutil(unittest.TestCase):
@unittest.skipUnless(zlib, "requires zlib")
def test_make_tarball(self):
# creating something to tar
- tmpdir = self.mkdtemp()
- self.write_file([tmpdir, 'file1'], 'xxx')
- self.write_file([tmpdir, 'file2'], 'xxx')
- os.mkdir(os.path.join(tmpdir, 'sub'))
- self.write_file([tmpdir, 'sub', 'file3'], 'xxx')
+ root_dir, base_dir = self._create_files('')
tmpdir2 = self.mkdtemp()
# force shutil to create the directory
os.rmdir(tmpdir2)
- unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
+ unittest.skipUnless(splitdrive(root_dir)[0] == splitdrive(tmpdir2)[0],
"source and target should be on same drive")
base_name = os.path.join(tmpdir2, 'archive')
# working with relative paths to avoid tar warnings
- old_dir = os.getcwd()
- os.chdir(tmpdir)
- try:
- _make_tarball(splitdrive(base_name)[1], '.')
- finally:
- os.chdir(old_dir)
+ make_archive(splitdrive(base_name)[1], 'gztar', root_dir, '.')
# check if the compressed tarball was created
tarball = base_name + '.tar.gz'
- self.assertTrue(os.path.exists(tarball))
+ self.assertTrue(os.path.isfile(tarball))
+ self.assertTrue(tarfile.is_tarfile(tarball))
+ with tarfile.open(tarball, 'r:gz') as tf:
+ self.assertEqual(sorted(tf.getnames()),
+ ['.', './file1', './file2',
+ './sub', './sub/file3', './sub2'])
# trying an uncompressed one
base_name = os.path.join(tmpdir2, 'archive')
- old_dir = os.getcwd()
- os.chdir(tmpdir)
- try:
- _make_tarball(splitdrive(base_name)[1], '.', compress=None)
- finally:
- os.chdir(old_dir)
+ make_archive(splitdrive(base_name)[1], 'tar', root_dir, '.')
tarball = base_name + '.tar'
- self.assertTrue(os.path.exists(tarball))
+ self.assertTrue(os.path.isfile(tarball))
+ self.assertTrue(tarfile.is_tarfile(tarball))
+ with tarfile.open(tarball, 'r') as tf:
+ self.assertEqual(sorted(tf.getnames()),
+ ['.', './file1', './file2',
+ './sub', './sub/file3', './sub2'])
def _tarinfo(self, path):
- tar = tarfile.open(path)
- try:
+ with tarfile.open(path) as tar:
names = tar.getnames()
names.sort()
return tuple(names)
- finally:
- tar.close()
- def _create_files(self):
+ def _create_files(self, base_dir='dist'):
# creating something to tar
- tmpdir = self.mkdtemp()
- dist = os.path.join(tmpdir, 'dist')
- os.mkdir(dist)
- self.write_file([dist, 'file1'], 'xxx')
- self.write_file([dist, 'file2'], 'xxx')
+ root_dir = self.mkdtemp()
+ dist = os.path.join(root_dir, base_dir)
+ if not os.path.isdir(dist):
+ os.makedirs(dist)
+ self.write_file((dist, 'file1'), 'xxx')
+ self.write_file((dist, 'file2'), 'xxx')
os.mkdir(os.path.join(dist, 'sub'))
- self.write_file([dist, 'sub', 'file3'], 'xxx')
+ self.write_file((dist, 'sub', 'file3'), 'xxx')
os.mkdir(os.path.join(dist, 'sub2'))
- tmpdir2 = self.mkdtemp()
- base_name = os.path.join(tmpdir2, 'archive')
- return tmpdir, tmpdir2, base_name
+ if base_dir:
+ self.write_file((root_dir, 'outer'), 'xxx')
+ return root_dir, base_dir
@unittest.skipUnless(zlib, "Requires zlib")
- @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
+ @unittest.skipUnless(find_executable('tar'),
'Need the tar command to run')
def test_tarfile_vs_tar(self):
- tmpdir, tmpdir2, base_name = self._create_files()
- old_dir = os.getcwd()
- os.chdir(tmpdir)
- try:
- _make_tarball(base_name, 'dist')
- finally:
- os.chdir(old_dir)
+ root_dir, base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ make_archive(base_name, 'gztar', root_dir, base_dir)
# check if the compressed tarball was created
tarball = base_name + '.tar.gz'
- self.assertTrue(os.path.exists(tarball))
+ self.assertTrue(os.path.isfile(tarball))
# now create another tarball using `tar`
- tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
- tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
- gzip_cmd = ['gzip', '-f9', 'archive2.tar']
- old_dir = os.getcwd()
- os.chdir(tmpdir)
- try:
- with captured_stdout() as s:
- spawn(tar_cmd)
- spawn(gzip_cmd)
- finally:
- os.chdir(old_dir)
+ tarball2 = os.path.join(root_dir, 'archive2.tar')
+ tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
+ with support.change_cwd(root_dir), captured_stdout():
+ spawn(tar_cmd)
- self.assertTrue(os.path.exists(tarball2))
+ self.assertTrue(os.path.isfile(tarball2))
# let's compare both tarballs
self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
# trying an uncompressed one
- base_name = os.path.join(tmpdir2, 'archive')
- old_dir = os.getcwd()
- os.chdir(tmpdir)
- try:
- _make_tarball(base_name, 'dist', compress=None)
- finally:
- os.chdir(old_dir)
+ make_archive(base_name, 'tar', root_dir, base_dir)
tarball = base_name + '.tar'
- self.assertTrue(os.path.exists(tarball))
+ self.assertTrue(os.path.isfile(tarball))
# now for a dry_run
- base_name = os.path.join(tmpdir2, 'archive')
- old_dir = os.getcwd()
- os.chdir(tmpdir)
- try:
- _make_tarball(base_name, 'dist', compress=None, dry_run=True)
- finally:
- os.chdir(old_dir)
+ make_archive(base_name, 'tar', root_dir, base_dir, dry_run=True)
tarball = base_name + '.tar'
- self.assertTrue(os.path.exists(tarball))
+ self.assertTrue(os.path.isfile(tarball))
@unittest.skipUnless(zlib, "Requires zlib")
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
def test_make_zipfile(self):
- # creating something to tar
- tmpdir = self.mkdtemp()
- self.write_file([tmpdir, 'file1'], 'xxx')
- self.write_file([tmpdir, 'file2'], 'xxx')
+ # creating something to zip
+ root_dir, base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
- tmpdir2 = self.mkdtemp()
- # force shutil to create the directory
- os.rmdir(tmpdir2)
- base_name = os.path.join(tmpdir2, 'archive')
- _make_zipfile(base_name, tmpdir)
+ res = make_archive(base_name, 'zip', root_dir, base_dir)
- # check if the compressed tarball was created
- tarball = base_name + '.zip'
- self.assertTrue(os.path.exists(tarball))
+ self.assertEqual(res, base_name + '.zip')
+ self.assertTrue(os.path.isfile(res))
+ self.assertTrue(zipfile.is_zipfile(res))
+ with zipfile.ZipFile(res) as zf:
+ self.assertEqual(sorted(zf.namelist()),
+ ['dist/', 'dist/file1', 'dist/file2',
+ 'dist/sub/', 'dist/sub/file3', 'dist/sub2/'])
+ @unittest.skipUnless(zlib, "Requires zlib")
+ @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
+ @unittest.skipUnless(find_executable('zip'),
+ 'Need the zip command to run')
+ def test_zipfile_vs_zip(self):
+ root_dir, base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
+ archive = make_archive(base_name, 'zip', root_dir, base_dir)
+
+ # check if ZIP file was created
+ self.assertEqual(archive, base_name + '.zip')
+ self.assertTrue(os.path.isfile(archive))
+
+ # now create another ZIP file using `zip`
+ archive2 = os.path.join(root_dir, 'archive2.zip')
+ zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
+ with support.change_cwd(root_dir):
+ spawn(zip_cmd)
+
+ self.assertTrue(os.path.isfile(archive2))
+ # let's compare both ZIP files
+ with zipfile.ZipFile(archive) as zf:
+ names = zf.namelist()
+ with zipfile.ZipFile(archive2) as zf:
+ names2 = zf.namelist()
+ self.assertEqual(sorted(names), sorted(names2))
def test_make_archive(self):
tmpdir = self.mkdtemp()
@@ -521,39 +517,36 @@ class TestShutil(unittest.TestCase):
else:
group = owner = 'root'
- base_dir, root_dir, base_name = self._create_files()
- base_name = os.path.join(self.mkdtemp() , 'archive')
+ root_dir, base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
group=group)
- self.assertTrue(os.path.exists(res))
+ self.assertTrue(os.path.isfile(res))
res = make_archive(base_name, 'zip', root_dir, base_dir)
- self.assertTrue(os.path.exists(res))
+ self.assertTrue(os.path.isfile(res))
res = make_archive(base_name, 'tar', root_dir, base_dir,
owner=owner, group=group)
- self.assertTrue(os.path.exists(res))
+ self.assertTrue(os.path.isfile(res))
res = make_archive(base_name, 'tar', root_dir, base_dir,
owner='kjhkjhkjg', group='oihohoh')
- self.assertTrue(os.path.exists(res))
+ self.assertTrue(os.path.isfile(res))
@unittest.skipUnless(zlib, "Requires zlib")
@unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
def test_tarfile_root_owner(self):
- tmpdir, tmpdir2, base_name = self._create_files()
- old_dir = os.getcwd()
- os.chdir(tmpdir)
+ root_dir, base_dir = self._create_files()
+ base_name = os.path.join(self.mkdtemp(), 'archive')
group = grp.getgrgid(0)[0]
owner = pwd.getpwuid(0)[0]
- try:
- archive_name = _make_tarball(base_name, 'dist', compress=None,
- owner=owner, group=group)
- finally:
- os.chdir(old_dir)
+ with support.change_cwd(root_dir):
+ archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
+ owner=owner, group=group)
# check if the compressed tarball was created
- self.assertTrue(os.path.exists(archive_name))
+ self.assertTrue(os.path.isfile(archive_name))
# now checks the rights
archive = tarfile.open(archive_name)
@@ -859,7 +852,7 @@ class TestCopyFile(unittest.TestCase):
def test_main():
- test_support.run_unittest(TestShutil, TestMove, TestCopyFile)
+ support.run_unittest(TestShutil, TestMove, TestCopyFile)
if __name__ == '__main__':
test_main()
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 42c1b4d..98a9275 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -491,6 +491,33 @@ TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid())
SAVEDCWD = os.getcwd()
@contextlib.contextmanager
+def change_cwd(path, quiet=False):
+ """Return a context manager that changes the current working directory.
+
+ Arguments:
+
+ path: the directory to use as the temporary current working directory.
+
+ quiet: if False (the default), the context manager raises an exception
+ on error. Otherwise, it issues only a warning and keeps the current
+ working directory the same.
+
+ """
+ saved_dir = os.getcwd()
+ try:
+ os.chdir(path)
+ except OSError:
+ if not quiet:
+ raise
+ warnings.warn('tests may fail, unable to change CWD to: ' + path,
+ RuntimeWarning, stacklevel=3)
+ try:
+ yield os.getcwd()
+ finally:
+ os.chdir(saved_dir)
+
+
+@contextlib.contextmanager
def temp_cwd(name='tempcwd', quiet=False):
"""
Context manager that creates a temporary directory and set it as CWD.

20
SOURCES/00268-set-stream-name-to-None.patch

@ -0,0 +1,20 @@

# HG changeset patch
# User Vinay Sajip <vinay_sajip@yahoo.co.uk>
# Date 1402737594 -3600
# Node ID bb8b0c7fefd0c5ed99b3f336178a4f9554a1d0ef
# Parent 31adcc4c43916f7448c9dd8048ad5be7e5bb6456
Issue #21742: Set stream to None after closing.

diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -423,6 +423,7 @@ class WatchedFileHandler(logging.FileHan
# we have an open file handle, clean it up
self.stream.flush()
self.stream.close()
+ self.stream = None # See Issue #21742: _open () might fail.
# open a new file handle and get new stat info from that fd
self.stream = self._open()
self._statstream()

22
SOURCES/00275-fix-fnctl-with-integer-on-big-endian.patch

@ -0,0 +1,22 @@
diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c
index 997867a..2bd2f55 100644
--- a/Modules/fcntlmodule.c
+++ b/Modules/fcntlmodule.c
@@ -34,7 +34,7 @@ fcntl_fcntl(PyObject *self, PyObject *args)
{
int fd;
int code;
- long arg;
+ int arg;
int ret;
char *str;
Py_ssize_t len;
@@ -61,7 +61,7 @@ fcntl_fcntl(PyObject *self, PyObject *args)
PyErr_Clear();
arg = 0;
if (!PyArg_ParseTuple(args,
- "O&i|l;fcntl requires a file or file descriptor,"
+ "O&i|I;fcntl requires a file or file descriptor,"
" an integer and optionally a third integer or a string",
conv_descriptor, &fd, &code, &arg)) {
return NULL;

22
SOURCES/00276-increase-imaplib-MAXLINE.patch

@ -0,0 +1,22 @@
diff --git a/Lib/imaplib.py b/Lib/imaplib.py
index 4586fb3..d8243e5 100644
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -37,11 +37,12 @@ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first
# Maximal line length when calling readline(). This is to prevent
# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1)
-# don't specify a line length. RFC 2683 however suggests limiting client
-# command lines to 1000 octets and server command lines to 8000 octets.
-# We have selected 10000 for some extra margin and since that is supposedly
-# also what UW and Panda IMAP does.
-_MAXLINE = 10000
+# don't specify a line length. RFC 2683 suggests limiting client
+# command lines to 1000 octets and that servers should be prepared
+# to accept command lines up to 8000 octets, so we used to use 10K here.
+# In the modern world (eg: gmail) the response to, for example, a
+# search command can be quite large, so we now use 1M.
+_MAXLINE = 1000000
# Commands

91
SOURCES/00281-add-context-parameter-to-xmlrpclib.ServerProxy.patch

@ -0,0 +1,91 @@

# HG changeset patch
# User Benjamin Peterson <benjamin@python.org>
# Date 1417319735 18000
# Node ID 62bd574e95d5ec4b37ca8f72ae6523ea7d6c11cd
# Parent 1ac5aec658f6972c3372f139ce69ee6799dc0b2e
add context parameter to xmlrpclib.ServerProxy (#22960)

Patch from Alex Gaynor.

diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst
--- a/Doc/library/xmlrpclib.rst
+++ b/Doc/library/xmlrpclib.rst
@@ -39,7 +39,7 @@ between conformable Python objects and X
For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate
and hostname checks by default
-.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]])
+.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime[, context]]]]]])
A :class:`ServerProxy` instance is an object that manages communication with a
remote XML-RPC server. The required first argument is a URI (Uniform Resource
@@ -57,11 +57,13 @@ between conformable Python objects and X
:class:`datetime.datetime` objects may be passed to calls.
Both the HTTP and HTTPS transports support the URL syntax extension for HTTP
- Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass``
+ Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass``
portion will be base64-encoded as an HTTP 'Authorization' header, and sent to
the remote server as part of the connection process when invoking an XML-RPC
method. You only need to use this if the remote server requires a Basic
- Authentication user and password.
+ Authentication user and password. If an HTTPS url is provided, *context* may
+ be :class:`ssl.SSLContext` and configures the SSL settings of the underlying
+ HTTPS connection.
The returned instance is a proxy object with methods that can be used to invoke
corresponding RPC calls on the remote server. If the remote server supports the
@@ -131,6 +133,9 @@ between conformable Python objects and X
*__dict__* attribute and don't have a base class that is marshalled in a
special way.
+ .. versionchanged:: 2.7.9
+ Added the *context* argument.
+
.. seealso::
diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py
--- a/Lib/xmlrpclib.py
+++ b/Lib/xmlrpclib.py
@@ -1478,6 +1478,10 @@ class Transport:
class SafeTransport(Transport):
"""Handles an HTTPS transaction to an XML-RPC server."""
+ def __init__(self, use_datetime=0, context=None):
+ Transport.__init__(self, use_datetime=use_datetime)
+ self.context = context
+
# FIXME: mostly untested
def make_connection(self, host):
@@ -1493,7 +1497,7 @@ class SafeTransport(Transport):
)
else:
chost, self._extra_headers, x509 = self.get_host_info(host)
- self._connection = host, HTTPS(chost, None, **(x509 or {}))
+ self._connection = host, HTTPS(chost, None, context=self.context, **(x509 or {}))
return self._connection[1]
##
@@ -1536,7 +1540,7 @@ class ServerProxy:
"""
def __init__(self, uri, transport=None, encoding=None, verbose=0,
- allow_none=0, use_datetime=0):
+ allow_none=0, use_datetime=0, context=None):
# establish a "logical" server connection
if isinstance(uri, unicode):
@@ -1553,7 +1557,7 @@ class ServerProxy:
if transport is None:
if type == "https":
- transport = SafeTransport(use_datetime=use_datetime)
+ transport = SafeTransport(use_datetime=use_datetime, context=context)
else:
transport = Transport(use_datetime=use_datetime)
self.__transport = transport

157
SOURCES/00282-obmalloc-mmap-threshold.patch

@ -0,0 +1,157 @@
Make it more likely for the system allocator to release free()d memory arenas on glibc-based systems.
Patch by Charles-François Natali.
https://bugs.python.org/issue20494

diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -2,6 +2,13 @@
#ifdef WITH_PYMALLOC
+#ifdef HAVE_MMAP
+ #include <sys/mman.h>
+ #ifdef MAP_ANONYMOUS
+ #define ARENAS_USE_MMAP
+ #endif
+#endif
+
#ifdef WITH_VALGRIND
#include <valgrind/valgrind.h>
@@ -75,7 +82,8 @@ static int running_on_valgrind = -1;
* Allocation strategy abstract:
*
* For small requests, the allocator sub-allocates <Big> blocks of memory.
- * Requests greater than 256 bytes are routed to the system's allocator.
+ * Requests greater than SMALL_REQUEST_THRESHOLD bytes are routed to the
+ * system's allocator.
*
* Small requests are grouped in size classes spaced 8 bytes apart, due
* to the required valid alignment of the returned address. Requests of
@@ -107,10 +115,11 @@ static int running_on_valgrind = -1;
* 57-64 64 7
* 65-72 72 8
* ... ... ...
- * 241-248 248 30
- * 249-256 256 31
+ * 497-504 504 62
+ * 505-512 512 63
*
- * 0, 257 and up: routed to the underlying allocator.
+ * 0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying
+ * allocator.
*/
/*==========================================================================*/
@@ -143,10 +152,13 @@ static int running_on_valgrind = -1;
* 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 256
* 2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT
*
+ * Note: a size threshold of 512 guarantees that newly created dictionaries
+ * will be allocated from preallocated memory pools on 64-bit.
+ *
* Although not required, for better performance and space efficiency,
* it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2.
*/
-#define SMALL_REQUEST_THRESHOLD 256
+#define SMALL_REQUEST_THRESHOLD 512
#define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT)
/*
@@ -174,15 +186,15 @@ static int running_on_valgrind = -1;
/*
* The allocator sub-allocates <Big> blocks of memory (called arenas) aligned
* on a page boundary. This is a reserved virtual address space for the
- * current process (obtained through a malloc call). In no way this means
- * that the memory arenas will be used entirely. A malloc(<Big>) is usually
- * an address range reservation for <Big> bytes, unless all pages within this
- * space are referenced subsequently. So malloc'ing big blocks and not using
- * them does not mean "wasting memory". It's an addressable range wastage...
+ * current process (obtained through a malloc()/mmap() call). In no way this
+ * means that the memory arenas will be used entirely. A malloc(<Big>) is
+ * usually an address range reservation for <Big> bytes, unless all pages within
+ * this space are referenced subsequently. So malloc'ing big blocks and not
+ * using them does not mean "wasting memory". It's an addressable range
+ * wastage...
*
- * Therefore, allocating arenas with malloc is not optimal, because there is
- * some address space wastage, but this is the most portable way to request
- * memory from the system across various platforms.
+ * Arenas are allocated with mmap() on systems supporting anonymous memory
+ * mappings to reduce heap fragmentation.
*/
#define ARENA_SIZE (256 << 10) /* 256KB */
@@ -440,6 +452,9 @@ static poolp usedpools[2 * ((NB_SMALL_SI
, PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55)
#if NB_SMALL_SIZE_CLASSES > 56
, PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63)
+#if NB_SMALL_SIZE_CLASSES > 64
+#error "NB_SMALL_SIZE_CLASSES should be less than 64"
+#endif /* NB_SMALL_SIZE_CLASSES > 64 */
#endif /* NB_SMALL_SIZE_CLASSES > 56 */
#endif /* NB_SMALL_SIZE_CLASSES > 48 */
#endif /* NB_SMALL_SIZE_CLASSES > 40 */
@@ -577,7 +592,12 @@ new_arena(void)
arenaobj = unused_arena_objects;
unused_arena_objects = arenaobj->nextarena;
assert(arenaobj->address == 0);
+#ifdef ARENAS_USE_MMAP
+ arenaobj->address = (uptr)mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+#else
arenaobj->address = (uptr)malloc(ARENA_SIZE);
+#endif
if (arenaobj->address == 0) {
/* The allocation failed: return NULL after putting the
* arenaobj back.
@@ -1054,7 +1074,11 @@ PyObject_Free(void *p)
unused_arena_objects = ao;
/* Free the entire arena. */
+#ifdef ARENAS_USE_MMAP
+ munmap((void *)ao->address, ARENA_SIZE);
+#else
free((void *)ao->address);
+#endif
ao->address = 0; /* mark unassociated */
--narenas_currently_allocated;
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -10164,7 +10164,7 @@ for ac_func in alarm setitimer getitimer
clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
- initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \
+ initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime mmap \
mremap nice pathconf pause plock poll pthread_init \
putenv readlink realpath \
select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -2905,7 +2905,7 @@ AC_CHECK_FUNCS(alarm setitimer getitimer
clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \
- initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \
+ initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime mmap \
mremap nice pathconf pause plock poll pthread_init \
putenv readlink realpath \
select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \
diff --git a/pyconfig.h.in b/pyconfig.h.in
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -475,6 +475,9 @@
/* Define to 1 if you have the `mktime' function. */
#undef HAVE_MKTIME
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
/* Define to 1 if you have the `mremap' function. */
#undef HAVE_MREMAP

59
SOURCES/00285-fix-non-deterministic-read-in-test_pty.patch

@ -0,0 +1,59 @@
diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py
index bec38c45456..f623aa09620 100644
--- a/Lib/test/test_pty.py
+++ b/Lib/test/test_pty.py
@@ -11,6 +11,7 @@
import select
import signal
import socket
+import io # readline
import unittest
TEST_STRING_1 = "I wish to buy a fish license.\n"
@@ -24,6 +25,16 @@ def debug(msg):
pass
+# Note that os.read() is nondeterministic so we need to be very careful
+# to make the test suite deterministic. A normal call to os.read() may
+# give us less than expected.
+#
+# Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get
+# back 'foo\r\n' at the other end. The behavior depends on the termios
+# setting. The newline translation may be OS-specific. To make the
+# test suite deterministic and OS-independent, the functions _readline
+# and normalize_output can be used.
+
def normalize_output(data):
# Some operating systems do conversions on newline. We could possibly
# fix that by doing the appropriate termios.tcsetattr()s. I couldn't
@@ -45,6 +56,12 @@ def normalize_output(data):
return data
+def _readline(fd):
+ """Read one line. May block forever if no newline is read."""
+ reader = io.FileIO(fd, mode='rb', closefd=False)
+ return reader.readline()
+
+
# Marginal testing of pty suite. Cannot do extensive 'do or fail' testing
# because pty code is not too portable.
@@ -97,14 +114,14 @@ def test_basic(self):
debug("Writing to slave_fd")
os.write(slave_fd, TEST_STRING_1)
- s1 = os.read(master_fd, 1024)
+ s1 = _readline(master_fd)
self.assertEqual('I wish to buy a fish license.\n',
normalize_output(s1))
debug("Writing chunked output")
os.write(slave_fd, TEST_STRING_2[:5])
os.write(slave_fd, TEST_STRING_2[5:])
- s2 = os.read(master_fd, 1024)
+ s2 = _readline(master_fd)
self.assertEqual('For my pet fish, Eric.\n', normalize_output(s2))
os.close(slave_fd)

135
SOURCES/00287-fix-thread-hanging-on-inaccessible-nfs-server.patch

@ -0,0 +1,135 @@
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 4a71a57ec0d..2b40ada195a 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -146,9 +146,15 @@ dircheck(fileio* self, PyObject *nameobj)
{
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
struct stat buf;
+ int res;
if (self->fd < 0)
return 0;
- if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(self->fd, &buf);
+ Py_END_ALLOW_THREADS
+
+ if (res == 0 && S_ISDIR(buf.st_mode)) {
errno = EISDIR;
PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
return -1;
@@ -162,17 +168,34 @@ check_fd(int fd)
{
#if defined(HAVE_FSTAT)
struct stat buf;
- if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
- PyObject *exc;
- char *msg = strerror(EBADF);
- exc = PyObject_CallFunction(PyExc_OSError, "(is)",
- EBADF, msg);
- PyErr_SetObject(PyExc_OSError, exc);
- Py_XDECREF(exc);
- return -1;
+ int res;
+ PyObject *exc;
+ char *msg;
+
+ if (!_PyVerify_fd(fd)) {
+ goto badfd;
}
-#endif
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(fd, &buf);
+ Py_END_ALLOW_THREADS
+
+ if (res < 0 && errno == EBADF) {
+ goto badfd;
+ }
+
return 0;
+
+badfd:
+ msg = strerror(EBADF);
+ exc = PyObject_CallFunction(PyExc_OSError, "(is)",
+ EBADF, msg);
+ PyErr_SetObject(PyExc_OSError, exc);
+ Py_XDECREF(exc);
+ return -1;
+#else
+ return 0;
+#endif
}
@@ -519,9 +542,19 @@ new_buffersize(fileio *self, size_t currentsize)
#ifdef HAVE_FSTAT
off_t pos, end;
struct stat st;
- if (fstat(self->fd, &st) == 0) {
+ int res;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(self->fd, &st);
+ Py_END_ALLOW_THREADS
+
+ if (res == 0) {
end = st.st_size;
+
+ Py_BEGIN_ALLOW_THREADS
pos = lseek(self->fd, 0L, SEEK_CUR);
+ Py_END_ALLOW_THREADS
+
/* Files claiming a size smaller than SMALLCHUNK may
actually be streaming pseudo-files. In this case, we
apply the more aggressive algorithm below.
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 2f63c374d1e..8d1c5812f0d 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -121,10 +121,15 @@ dircheck(PyFileObject* f)
{
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
struct stat buf;
+ int res;
if (f->f_fp == NULL)
return f;
- if (fstat(fileno(f->f_fp), &buf) == 0 &&
- S_ISDIR(buf.st_mode)) {
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(fileno(f->f_fp), &buf);
+ Py_END_ALLOW_THREADS
+
+ if (res == 0 && S_ISDIR(buf.st_mode)) {
char *msg = strerror(EISDIR);
PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)",
EISDIR, msg, f->f_name);
@@ -1010,7 +1015,13 @@ new_buffersize(PyFileObject *f, size_t currentsize)
#ifdef HAVE_FSTAT
off_t pos, end;
struct stat st;
- if (fstat(fileno(f->f_fp), &st) == 0) {
+ int res;
+
+ Py_BEGIN_ALLOW_THREADS
+ res = fstat(fileno(f->f_fp), &st);
+ Py_END_ALLOW_THREADS
+
+ if (res == 0) {
end = st.st_size;
/* The following is not a bug: we really need to call lseek()
*and* ftell(). The reason is that some stdio libraries
@@ -1021,7 +1032,11 @@ new_buffersize(PyFileObject *f, size_t currentsize)
works. We can't use the lseek() value either, because we
need to take the amount of buffered data into account.
(Yet another reason why stdio stinks. :-) */
+
+ Py_BEGIN_ALLOW_THREADS
pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR);
+ Py_END_ALLOW_THREADS
+
if (pos >= 0) {
pos = ftell(f->f_fp);
}

250
SOURCES/00295-fix-https-behind-proxy.patch

@ -0,0 +1,250 @@
diff --git a/Lib/httplib.py b/Lib/httplib.py
index 592ee57..b69145b 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -735,25 +735,40 @@ class HTTPConnection:
self._tunnel_host = None
self._tunnel_port = None
self._tunnel_headers = {}
-
- self._set_hostport(host, port)
if strict is not None:
self.strict = strict
+ (self.host, self.port) = self._get_hostport(host, port)
+
+ # This is stored as an instance variable to allow unittests
+ # to replace with a suitable mock
+ self._create_connection = socket.create_connection
+
def set_tunnel(self, host, port=None, headers=None):
- """ Sets up the host and the port for the HTTP CONNECT Tunnelling.
+ """ Set up host and port for HTTP CONNECT tunnelling.
+
+ In a connection that uses HTTP Connect tunneling, the host passed to the
+ constructor is used as proxy server that relays all communication to the
+ endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT
+ request to the proxy server when the connection is established.
+
+ This method must be called before the HTTP connection has been
+ established.
The headers argument should be a mapping of extra HTTP headers
to send with the CONNECT request.
"""
- self._tunnel_host = host
- self._tunnel_port = port
+ # Verify if this is required.
+ if self.sock:
+ raise RuntimeError("Can't setup tunnel for established connection.")
+
+ self._tunnel_host, self._tunnel_port = self._get_hostport(host, port)
if headers:
self._tunnel_headers = headers
else:
self._tunnel_headers.clear()
- def _set_hostport(self, host, port):
+ def _get_hostport(self, host, port):
if port is None:
i = host.rfind(':')
j = host.rfind(']') # ipv6 addresses have [...]
@@ -770,15 +785,14 @@ class HTTPConnection:
port = self.default_port
if host and host[0] == '[' and host[-1] == ']':
host = host[1:-1]
- self.host = host
- self.port = port
+ return (host, port)
def set_debuglevel(self, level):
self.debuglevel = level
def _tunnel(self):
- self._set_hostport(self._tunnel_host, self._tunnel_port)
- self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self.host, self.port))
+ self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self._tunnel_host,
+ self._tunnel_port))
for header, value in self._tunnel_headers.iteritems():
self.send("%s: %s\r\n" % (header, value))
self.send("\r\n")
@@ -803,8 +817,8 @@ class HTTPConnection:
def connect(self):
"""Connect to the host and port specified in __init__."""
- self.sock = socket.create_connection((self.host,self.port),
- self.timeout, self.source_address)
+ self.sock = self._create_connection((self.host,self.port),
+ self.timeout, self.source_address)
if self._tunnel_host:
self._tunnel()
@@ -942,17 +956,24 @@ class HTTPConnection:
netloc_enc = netloc.encode("idna")
self.putheader('Host', netloc_enc)
else:
+ if self._tunnel_host:
+ host = self._tunnel_host
+ port = self._tunnel_port
+ else:
+ host = self.host
+ port = self.port
+
try:
- host_enc = self.host.encode("ascii")
+ host_enc = host.encode("ascii")
except UnicodeEncodeError:
- host_enc = self.host.encode("idna")
+ host_enc = host.encode("idna")
# Wrap the IPv6 Host Header with [] (RFC 2732)
if host_enc.find(':') >= 0:
host_enc = "[" + host_enc + "]"
- if self.port == self.default_port:
+ if port == self.default_port:
self.putheader('Host', host_enc)
else:
- self.putheader('Host', "%s:%s" % (host_enc, self.port))
+ self.putheader('Host', "%s:%s" % (host_enc, port))
# note: we are assuming that clients will not attempt to set these
# headers since *this* library must deal with the
@@ -1141,7 +1162,7 @@ class HTTP:
"Accept arguments to set the host/port, since the superclass doesn't."
if host is not None:
- self._conn._set_hostport(host, port)
+ (self._conn.host, self._conn.port) = self._conn._get_hostport(host, port)
self._conn.connect()
def getfile(self):
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 29af589..9db30cc 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -21,10 +21,12 @@ CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotn
HOST = test_support.HOST
class FakeSocket:
- def __init__(self, text, fileclass=StringIO.StringIO):
+ def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None):
self.text = text
self.fileclass = fileclass
self.data = ''
+ self.host = host
+ self.port = port
def sendall(self, data):
self.data += ''.join(data)
@@ -34,6 +36,9 @@ class FakeSocket:
raise httplib.UnimplementedFileMode()
return self.fileclass(self.text)
+ def close(self):
+ pass
+
class EPipeSocket(FakeSocket):
def __init__(self, text, pipe_trigger):
@@ -487,7 +492,11 @@ class OfflineTest(TestCase):
self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found")
-class SourceAddressTest(TestCase):
+class TestServerMixin:
+ """A limited socket server mixin.
+
+ This is used by test cases for testing http connection end points.
+ """
def setUp(self):
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.port = test_support.bind_port(self.serv)
@@ -502,6 +511,7 @@ class SourceAddressTest(TestCase):
self.serv.close()
self.serv = None
+class SourceAddressTest(TestServerMixin, TestCase):
def testHTTPConnectionSourceAddress(self):
self.conn = httplib.HTTPConnection(HOST, self.port,
source_address=('', self.source_port))
@@ -518,6 +528,24 @@ class SourceAddressTest(TestCase):
# for an ssl_wrapped connect() to actually return from.
+class HTTPTest(TestServerMixin, TestCase):
+ def testHTTPConnection(self):
+ self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None)
+ self.conn.connect()
+ self.assertEqual(self.conn._conn.host, HOST)
+ self.assertEqual(self.conn._conn.port, self.port)
+
+ def testHTTPWithConnectHostPort(self):
+ testhost = 'unreachable.test.domain'
+ testport = '80'
+ self.conn = httplib.HTTP(host=testhost, port=testport)
+ self.conn.connect(host=HOST, port=self.port)
+ self.assertNotEqual(self.conn._conn.host, testhost)
+ self.assertNotEqual(self.conn._conn.port, testport)
+ self.assertEqual(self.conn._conn.host, HOST)
+ self.assertEqual(self.conn._conn.port, self.port)
+
+
class TimeoutTest(TestCase):
PORT = None
@@ -716,13 +744,54 @@ class HTTPSTest(TestCase):
c = httplib.HTTPSConnection(hp, context=context)
self.assertEqual(h, c.host)
self.assertEqual(p, c.port)
-
+
+class TunnelTests(TestCase):
+ def test_connect(self):
+ response_text = (
+ 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT
+ 'HTTP/1.1 200 OK\r\n' # Reply to HEAD
+ 'Content-Length: 42\r\n\r\n'
+ )
+
+ def create_connection(address, timeout=None, source_address=None):
+ return FakeSocket(response_text, host=address[0], port=address[1])
+
+ conn = httplib.HTTPConnection('proxy.com')
+ conn._create_connection = create_connection
+
+ # Once connected, we should not be able to tunnel anymore
+ conn.connect()
+ self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com')
+
+ # But if close the connection, we are good.
+ conn.close()
+ conn.set_tunnel('destination.com')
+ conn.request('HEAD', '/', '')
+
+ self.assertEqual(conn.sock.host, 'proxy.com')
+ self.assertEqual(conn.sock.port, 80)
+ self.assertIn('CONNECT destination.com', conn.sock.data)
+ # issue22095
+ self.assertNotIn('Host: destination.com:None', conn.sock.data)
+ # issue22095
+
+ self.assertNotIn('Host: proxy.com', conn.sock.data)
+
+ conn.close()
+
+ conn.request('PUT', '/', '')
+ self.assertEqual(conn.sock.host, 'proxy.com')
+ self.assertEqual(conn.sock.port, 80)
+ self.assertTrue('CONNECT destination.com' in conn.sock.data)
+ self.assertTrue('Host: destination.com' in conn.sock.data)
+
@test_support.reap_threads
def test_main(verbose=None):
test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest,
- HTTPSTest, SourceAddressTest)
+ HTTPTest, HTTPSTest, SourceAddressTest,
+ TunnelTests)
if __name__ == '__main__':
test_main()

26
SOURCES/00296-Readd-the-private-_set_hostport-api-to-httplib.patch

@ -0,0 +1,26 @@
From 8a91bb4ea0a7f50d024fe55014c2e86e36e67751 Mon Sep 17 00:00:00 2001
From: Tomas Orsava <torsava@redhat.com>
Date: Mon, 19 Feb 2018 14:42:13 +0100
Subject: [PATCH] Readd the private `_set_hostport` api to httplib

---
Lib/httplib.py | 3 +++
1 file changed, 3 insertions(+)

diff --git a/Lib/httplib.py b/Lib/httplib.py
index b69145b..da2f346 100644
--- a/Lib/httplib.py
+++ b/Lib/httplib.py
@@ -787,6 +787,9 @@ class HTTPConnection:
host = host[1:-1]
return (host, port)
+ def _set_hostport(self, host, port):
+ (self.host, self.port) = self._get_hostport(host, port)
+
def set_debuglevel(self, level):
self.debuglevel = level
--
2.13.6

60
SOURCES/00298-do-not-send-IP-in-SNI-TLS-extension.patch

@ -0,0 +1,60 @@
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index d0a3830..51b192c 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -50,6 +50,11 @@
#include <sys/poll.h>
#endif
+#ifndef MS_WINDOWS
+/* inet_pton */
+#include <arpa/inet.h>
+#endif
+
/* Include OpenSSL header files */
#include "openssl/rsa.h"
#include "openssl/crypto.h"
@@ -493,8 +498,41 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
SSL_set_mode(self->ssl, mode);
#if HAVE_SNI
- if (server_hostname != NULL)
- SSL_set_tlsext_host_name(self->ssl, server_hostname);
+ if (server_hostname != NULL) {
+/* Don't send SNI for IP addresses. We cannot simply use inet_aton() and
+ * inet_pton() here. inet_aton() may be linked weakly and inet_pton() isn't
+ * available on all platforms. Use OpenSSL's IP address parser. It's
+ * available since 1.0.2 and LibreSSL since at least 2.3.0. */
+ int send_sni = 1;
+#if OPENSSL_VERSION_NUMBER >= 0x10200000L
+ ASN1_OCTET_STRING *ip = a2i_IPADDRESS(server_hostname);
+ if (ip == NULL) {
+ send_sni = 1;
+ ERR_clear_error();
+ } else {
+ send_sni = 0;
+ ASN1_OCTET_STRING_free(ip);
+ }
+#elif defined(HAVE_INET_PTON)
+#ifdef ENABLE_IPV6
+ char packed[Py_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))];
+#else
+ char packed[sizeof(struct in_addr)];
+#endif /* ENABLE_IPV6 */
+ if (inet_pton(AF_INET, server_hostname, packed)) {
+ send_sni = 0;
+#ifdef ENABLE_IPV6
+ } else if(inet_pton(AF_INET6, server_hostname, packed)) {
+ send_sni = 0;
+#endif /* ENABLE_IPV6 */
+ } else {
+ send_sni = 1;
+ }
+#endif /* HAVE_INET_PTON */
+ if (send_sni) {
+ SSL_set_tlsext_host_name(self->ssl, server_hostname);
+ }
+ }
#endif
/* If the socket is in non-blocking mode or timeout mode, set the BIO

24
SOURCES/00299-fix-ssl-module-pymax.patch

@ -0,0 +1,24 @@
From 439956a149f8a3eb44646498c63b2ef3337d5f3d Mon Sep 17 00:00:00 2001
From: Christian Heimes <christian@python.org>
Date: Sun, 25 Feb 2018 13:08:05 +0100
Subject: [PATCH] Fix ssl module, Python 2.7 doesn't have Py_MAX (#5878)

Signed-off-by: Christian Heimes <christian@python.org>
---
Modules/_ssl.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index af66a581e15a..f9ed94dee1e1 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -610,7 +610,8 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
}
#elif defined(HAVE_INET_PTON)
#ifdef ENABLE_IPV6
- char packed[Py_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))];
+ #define PySSL_MAX(x, y) (((x) > (y)) ? (x) : (y))
+ char packed[PySSL_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))];
#else
char packed[sizeof(struct in_addr)];
#endif /* ENABLE_IPV6 */

86
SOURCES/00303-CVE-2018-1060-1.patch

@ -0,0 +1,86 @@
diff --git a/Lib/difflib.py b/Lib/difflib.py
index 1c6fbdbedcb7..788a92df3f89 100644
--- a/Lib/difflib.py
+++ b/Lib/difflib.py
@@ -1103,7 +1103,7 @@ def _qformat(self, aline, bline, atags, btags):
import re
-def IS_LINE_JUNK(line, pat=re.compile(r"\s*#?\s*$").match):
+def IS_LINE_JUNK(line, pat=re.compile(r"\s*(?:#\s*)?$").match):
r"""
Return 1 for ignorable line: iff `line` is blank or contains a single '#'.
diff --git a/Lib/poplib.py b/Lib/poplib.py
index b91e5f72d2ca..a238510b38fc 100644
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -274,7 +274,7 @@ def rpop(self, user):
return self._shortcmd('RPOP %s' % user)
- timestamp = re.compile(r'\+OK.*(<[^>]+>)')
+ timestamp = re.compile(br'\+OK.[^<]*(<.*>)')
def apop(self, user, secret):
"""Authorisation
diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py
index 35f2c36ca70a..d8277b79b880 100644
--- a/Lib/test/test_difflib.py
+++ b/Lib/test/test_difflib.py
@@ -269,13 +269,33 @@ def test_range_format_context(self):
self.assertEqual(fmt(3,6), '4,6')
self.assertEqual(fmt(0,0), '0')
+class TestJunkAPIs(unittest.TestCase):
+ def test_is_line_junk_true(self):
+ for line in ['#', ' ', ' #', '# ', ' # ', '']:
+ self.assertTrue(difflib.IS_LINE_JUNK(line), repr(line))
+
+ def test_is_line_junk_false(self):
+ for line in ['##', ' ##', '## ', 'abc ', 'abc #', 'Mr. Moose is up!']:
+ self.assertFalse(difflib.IS_LINE_JUNK(line), repr(line))
+
+ def test_is_line_junk_REDOS(self):
+ evil_input = ('\t' * 1000000) + '##'
+ self.assertFalse(difflib.IS_LINE_JUNK(evil_input))
+
+ def test_is_character_junk_true(self):
+ for char in [' ', '\t']:
+ self.assertTrue(difflib.IS_CHARACTER_JUNK(char), repr(char))
+
+ def test_is_character_junk_false(self):
+ for char in ['a', '#', '\n', '\f', '\r', '\v']:
+ self.assertFalse(difflib.IS_CHARACTER_JUNK(char), repr(char))
def test_main():
difflib.HtmlDiff._default_prefix = 0
Doctests = doctest.DocTestSuite(difflib)
run_unittest(
TestWithAscii, TestAutojunk, TestSFpatches, TestSFbugs,
- TestOutputFormat, Doctests)
+ TestOutputFormat, TestJunkAPIs)
if __name__ == '__main__':
test_main()
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
index 23d688724b95..d2143759ba66 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -211,6 +211,16 @@ def test_noop(self):
def test_rpop(self):
self.assertOK(self.client.rpop('foo'))
+ def test_apop_REDOS(self):
+ # Replace welcome with very long evil welcome.
+ # NB The upper bound on welcome length is currently 2048.
+ # At this length, evil input makes each apop call take
+ # on the order of milliseconds instead of microseconds.
+ evil_welcome = b'+OK' + (b'<' * 1000000)
+ with test_support.swap_attr(self.client, 'welcome', evil_welcome):
+ # The evil welcome is invalid, so apop should throw.
+ self.assertRaises(poplib.error_proto, self.client.apop, 'a', 'kb')
+
def test_top(self):
expected = ('+OK 116 bytes',
['From: postmaster@python.org', 'Content-Type: text/plain',

53
SOURCES/00305-CVE-2016-2183.patch

@ -0,0 +1,53 @@
diff --git a/Lib/ssl.py b/Lib/ssl.py
index 038daa4..5311321 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -143,38 +143,36 @@ if _ssl.HAS_TLS_UNIQUE:
else:
CHANNEL_BINDING_TYPES = []
+
# Disable weak or insecure ciphers by default
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
# Enable a better set of ciphers by default
# This list has been explicitly chosen to:
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
# * Prefer ECDHE over DHE for better performance
-# * Prefer any AES-GCM over any AES-CBC for better performance and security
+# * Prefer AEAD over CBC for better performance and security
# * Then Use HIGH cipher suites as a fallback
-# * Then Use 3DES as fallback which is secure but slow
# * Finally use RC4 as a fallback which is problematic but needed for
# compatibility some times.
-# * Disable NULL authentication, NULL encryption, and MD5 MACs for security
-# reasons
+# * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs
+# for security reasons
_DEFAULT_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
- 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'
- 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'
+ 'DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:ECDH+RC4:DH+RC4:RSA+RC4:!aNULL:!eNULL:'
+ '!MD5:!3DES'
)
# Restricted and more secure ciphers for the server side
# This list has been explicitly chosen to:
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
# * Prefer ECDHE over DHE for better performance
-# * Prefer any AES-GCM over any AES-CBC for better performance and security
+# * Prefer AEAD over CBC for better performance and security
# * Then Use HIGH cipher suites as a fallback
-# * Then Use 3DES as fallback which is secure but slow
-# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for
-# security reasons
+# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and
+# 3DES for security reasons
_RESTRICTED_SERVER_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
- 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
- '!eNULL:!MD5:!DSS:!RC4'
+ 'DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES'
)

44
SOURCES/00306-fix-oserror-17-upon-semaphores-creation.patch

@ -0,0 +1,44 @@

# HG changeset patch
# User Charles-François Natali <cf.natali@gmail.com>
# Date 1455316761 0
# Node ID d3662c088db8fb2c89f754031f18b1543419fed9
# Parent 5715a6d9ff12053e81f7ad75268ac059b079b351
Issue #24303: Fix random EEXIST upon multiprocessing semaphores creation with
Linux PID namespaces enabled.

diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c
--- a/Modules/_multiprocessing/semaphore.c
+++ b/Modules/_multiprocessing/semaphore.c
@@ -429,7 +429,7 @@ semlock_new(PyTypeObject *type, PyObject
int kind, maxvalue, value;
PyObject *result;
static char *kwlist[] = {"kind", "value", "maxvalue", NULL};
- static int counter = 0;
+ int try = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist,
&kind, &value, &maxvalue))
@@ -440,10 +440,18 @@ semlock_new(PyTypeObject *type, PyObject
return NULL;
}
- PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++);
+ /* Create a semaphore with a unique name. The bytes returned by
+ * _PyOS_URandom() are treated as unsigned long to ensure that the filename
+ * is valid (no special characters). */
+ do {
+ unsigned long suffix;
+ _PyOS_URandom((char *)&suffix, sizeof(suffix));
+ PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%lu", (long)getpid(),
+ suffix);
+ SEM_CLEAR_ERROR();
+ handle = SEM_CREATE(buffer, value, maxvalue);
+ } while ((handle == SEM_FAILED) && (errno == EEXIST) && (++try < 100));
- SEM_CLEAR_ERROR();
- handle = SEM_CREATE(buffer, value, maxvalue);
/* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */
if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
goto failure;

216
SOURCES/05000-autotool-intermediates.patch

@ -0,0 +1,216 @@
diff -up ./configure.autotool-intermediates ./configure
--- ./configure.autotool-intermediates 2013-04-09 11:24:01.024185796 +0200
+++ ./configure 2013-04-09 11:24:01.780183954 +0200
@@ -639,6 +639,8 @@ TRUE
MACHDEP_OBJS
DYNLOADFILE
DLINCLDIR
+DTRACEHDRS
+DTRACEOBJS
THREADOBJ
LDLAST
USE_THREAD_MODULE
@@ -659,6 +661,8 @@ OTHER_LIBTOOL_OPT
UNIVERSAL_ARCH_FLAGS
BASECFLAGS
OPT
+DEBUG_SUFFIX
+DEBUG_EXT
LN
MKDIR_P
INSTALL_DATA
@@ -795,8 +799,11 @@ with_pth
enable_ipv6
with_doc_strings
with_tsc
+with_count_allocs
+with_call_profile
with_pymalloc
with_valgrind
+with_dtrace
with_wctype_functions
with_fpectl
with_libm
@@ -1472,8 +1479,11 @@ Optional Packages:
--with-pth use GNU pth threading libraries
--with(out)-doc-strings disable/enable documentation strings
--with(out)-tsc enable/disable timestamp counter profile
+ --with(out)count-allocs enable/disable per-type instance accounting
+ --with(out)-call-profile enable/disable statistics on function call invocation
--with(out)-pymalloc disable/enable specialized mallocs
--with-valgrind Enable Valgrind support
+ --with(out)-dtrace disable/enable dtrace support
--with-wctype-functions use wctype.h functions
--with-fpectl enable SIGFPE catching
--with-libm=STRING math library
@@ -5171,7 +5181,7 @@ esac
$as_echo_n "checking LIBRARY... " >&6; }
if test -z "$LIBRARY"
then
- LIBRARY='libpython$(VERSION).a'
+ LIBRARY='libpython$(VERSION)$(DEBUG_EXT).a'
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBRARY" >&5
$as_echo "$LIBRARY" >&6; }
@@ -5343,8 +5353,8 @@ $as_echo "#define Py_ENABLE_SHARED 1" >>
INSTSONAME="$LDLIBRARY".$SOVERSION
;;
Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*)
- LDLIBRARY='libpython$(VERSION).so'
- BLDLIBRARY='-L. -lpython$(VERSION)'
+ LDLIBRARY='libpython$(VERSION)$(DEBUG_EXT).so'
+ BLDLIBRARY='-L. -lpython$(VERSION)$(DEBUG_EXT)'
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH}
case $ac_sys_system in
FreeBSD*)
@@ -5367,7 +5377,7 @@ $as_echo "#define Py_ENABLE_SHARED 1" >>
;;
OSF*)
LDLIBRARY='libpython$(VERSION).so'
- BLDLIBRARY='-rpath $(LIBDIR) -L. -lpython$(VERSION)'
+ BLDLIBRARY='-L. -lpython$(VERSION)'
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH}
;;
atheos*)
@@ -5894,6 +5904,14 @@ $as_echo "no" >&6; }
fi
+if test "$Py_DEBUG" = 'true'
+then
+ DEBUG_EXT=_d
+ DEBUG_SUFFIX=-debug
+fi
+
+
+
# XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be
# merged with this chunk of code?
@@ -9958,6 +9976,50 @@ $as_echo "no" >&6; }
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-count-allocs" >&5
+$as_echo_n "checking for --with-count-allocs... " >&6; }
+
+# Check whether --with-count-allocs was given.
+if test "${with_count_allocs+set}" = set; then :
+ withval=$with_count_allocs;
+if test "$withval" != no
+then
+
+$as_echo "#define COUNT_ALLOCS 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-call-profile" >&5
+$as_echo_n "checking for --with-call-profile... " >&6; }
+
+# Check whether --with-call-profile was given.
+if test "${with_call_profile+set}" = set; then :
+ withval=$with_call_profile;
+if test "$withval" != no
+then
+
+$as_echo "#define CALL_PROFILE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
# Check for Python-specific malloc support
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pymalloc" >&5
$as_echo_n "checking for --with-pymalloc... " >&6; }
@@ -10007,6 +10069,46 @@ fi
fi
+# Check for dtrace support
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dtrace" >&5
+$as_echo_n "checking for --with-dtrace... " >&6; }
+
+# Check whether --with-dtrace was given.
+if test "${with_dtrace+set}" = set; then :
+ withval=$with_dtrace;
+fi
+
+
+if test ! -z "$with_dtrace"
+then
+ if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null
+ then
+
+$as_echo "#define WITH_DTRACE 1" >>confdefs.h
+
+ with_dtrace="Sun"
+ DTRACEOBJS="Python/dtrace.o"
+ DTRADEHDRS=""
+ elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d
+ then
+
+$as_echo "#define WITH_DTRACE 1" >>confdefs.h
+
+ with_dtrace="Apple"
+ DTRACEOBJS=""
+ DTRADEHDRS="pydtrace.h"
+ else
+ with_dtrace="no"
+ fi
+else
+ with_dtrace="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5
+$as_echo "$with_dtrace" >&6; }
+
+
+
# Check for --with-wctype-functions
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-wctype-functions" >&5
$as_echo_n "checking for --with-wctype-functions... " >&6; }
diff -up ./pyconfig.h.in.autotool-intermediates ./pyconfig.h.in
--- ./pyconfig.h.in.autotool-intermediates 2013-04-09 11:24:01.020185806 +0200
+++ ./pyconfig.h.in 2013-04-09 11:24:02.088183204 +0200
@@ -18,6 +18,12 @@
/* Define this if you have BeOS threads. */
#undef BEOS_THREADS
+/* Define to keep records on function call invocation */
+#undef CALL_PROFILE
+
+/* Define to keep records of the number of instances of each type */
+#undef COUNT_ALLOCS
+
/* Define if you have the Mach cthreads package */
#undef C_THREADS
@@ -1119,12 +1125,6 @@
/* Define to profile with the Pentium timestamp counter */
#undef WITH_TSC
-/* Define to keep records of the number of instances of each type */
-#undef COUNT_ALLOCS
-
-/* Define to keep records on function call invocation */
-#undef CALL_PROFILE
-
/* Define if you want pymalloc to be disabled when running under valgrind */
#undef WITH_VALGRIND

8
SOURCES/cert-verification.cfg

@ -0,0 +1,8 @@
# Possible values are:
# 'enable' to ensure HTTPS certificate verification is enabled by default
# 'disable' to ensure HTTPS certificate verification is disabled by default
# 'platform_default' to delegate the decision to the redistributor providing this particular Python version

# For more info refer to https://www.python.org/dev/peps/pep-0493/
[https]
verify=platform_default

73
SOURCES/macros.python

@ -0,0 +1,73 @@
%py_setup setup.py
%py_shbang_opts -s

# Use the slashes after expand so that the command starts on the same line as
# the macro
%py_build() %{expand:\\\
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py_shbang_opts}" %{?*}
sleep 1
}

%py_build_egg() %{expand:\\\
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
sleep 1
}

%py_build_wheel() %{expand:\\\
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
sleep 1
}

%py_install() %{expand:\\\
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
}

%py_install_egg() %{expand:\\\
mkdir -p %{buildroot}%{python_sitelib}
easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python_version}.egg %{?*}
}

%py_install_wheel() %{expand:\\\
pip install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps
}

%python_provide() %{lua:
function string.starts(String,Start)
return string.sub(String,1,string.len(Start))==Start
end
package = rpm.expand("%{?1}")
vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}")
if (string.starts(package, "python2-")) then
if (rpm.expand("%{?buildarch}") ~= "noarch") then
str = "Provides: python-" .. string.sub(package,9,string.len(package)) .. "%{?_isa} = " .. vr
print(rpm.expand(str))
end
print("\\nProvides: python-")
print(string.sub(package,9,string.len(package)))
print(" = ")
print(vr)
--Obsoleting the previous default python package
print("\\nObsoletes: python-")
print(string.sub(package,9,string.len(package)))
print(" < ")
print(vr)
elseif (string.starts(package, "python" .. rpm.expand("%{python3_pkgversion}") .. "-")) then
--No unversioned provides as python3 is not default
elseif (rpm.expand("%{?python3_other_pkgversion}") ~= "" and string.starts(package, "python" .. rpm.expand("%{python3_other_pkgversion}") .. "-")) then
--No unversioned provides as python3_other is not default
elseif (string.starts(package, "pypy-")) then
--No unversioned provides as pypy is not default
elseif (string.starts(package, "pypy3-")) then
--No unversioned provides as pypy is not default
elseif (string.starts(package, "python-")) then
--Providing the current default python
print("Provides: python2-")
print(string.sub(package,8,string.len(package)))
print(" = ")
print(vr)
else
print("%python_provide: ERROR: ")
print(package)
print(" not recognized.")
end
}

37
SOURCES/macros.python2

@ -0,0 +1,37 @@
%__python2 /usr/bin/python2
%python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
%python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")
%python2_version %(%{__python2} -c "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))")
%python2_version_nodots %(%{__python2} -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))")

%py2_shbang_opts -s

# Use the slashes after expand so that the command starts on the same line as
# the macro
%py2_build() %{expand:\\\
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py2_shbang_opts}" %{?*}
sleep 1
}

%py2_build_egg() %{expand:\\\
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} bdist_egg %{?*}
sleep 1
}

%py2_build_wheel() %{expand:\\\
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} bdist_wheel %{?*}
sleep 1
}

%py2_install() %{expand:\\\
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*}
}

%py2_install_egg() %{expand:\\\
mkdir -p %{buildroot}%{python2_sitelib}
easy_install-%{python2_version} -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python2_version}.egg %{?*}
}

%py2_install_wheel() %{expand:\\\
pip%{python2_version} install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps
}

2
SOURCES/pynche

@ -0,0 +1,2 @@
#!/bin/bash
exec `python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific = True))"`/pynche/pynche

11
SOURCES/python-2.5-cflags.patch

@ -0,0 +1,11 @@
--- Python-2.5c1/Makefile.pre.in.cflags 2006-08-18 11:05:40.000000000 -0400
+++ Python-2.5c1/Makefile.pre.in 2006-08-18 11:09:26.000000000 -0400
@@ -334,7 +334,7 @@
# Build the interpreter
$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY)
- $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) -o $@ \
+ $(LINKCC) $(CFLAGS) $(LDFLAGS) $(LINKFORSHARED) -o $@ \
Modules/python.o \
$(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST)

12
SOURCES/python-2.5.1-plural-fix.patch

@ -0,0 +1,12 @@
diff -up Python-2.5.1/Lib/gettext.py.plural Python-2.5.1/Lib/gettext.py
--- Python-2.5.1/Lib/gettext.py.plural 2007-09-10 11:38:57.000000000 -0400
+++ Python-2.5.1/Lib/gettext.py 2007-09-10 11:39:00.000000000 -0400
@@ -299,6 +299,8 @@ class GNUTranslations(NullTranslations):
item = item.strip()
if not item:
continue
+ if item.startswith("#"):
+ continue
if ':' in item:
k, v = item.split(':', 1)
k = k.strip().lower()

24
SOURCES/python-2.5.1-sqlite-encoding.patch

@ -0,0 +1,24 @@
diff -up Python-2.5.1/Lib/sqlite3/dbapi2.py.encoding Python-2.5.1/Lib/sqlite3/dbapi2.py
--- Python-2.5.1/Lib/sqlite3/dbapi2.py.encoding 2007-09-14 10:41:50.000000000 -0400
+++ Python-2.5.1/Lib/sqlite3/dbapi2.py 2007-09-14 10:42:00.000000000 -0400
@@ -1,7 +1,6 @@
-# -*- coding: iso-8859-1 -*-
# pysqlite2/dbapi2.py: the DB-API 2.0 interface
#
-# Copyright (C) 2004-2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2005 Gerhard Haering <gh@ghaering.de>
#
# This file is part of pysqlite.
#
diff -up Python-2.5.1/Lib/sqlite3/__init__.py.encoding Python-2.5.1/Lib/sqlite3/__init__.py
--- Python-2.5.1/Lib/sqlite3/__init__.py.encoding 2007-09-14 10:41:47.000000000 -0400
+++ Python-2.5.1/Lib/sqlite3/__init__.py 2007-09-14 10:42:06.000000000 -0400
@@ -1,7 +1,6 @@
-#-*- coding: ISO-8859-1 -*-
# pysqlite2/__init__.py: the pysqlite2 package.
#
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2005 Gerhard Haering <gh@ghaering.de>
#
# This file is part of pysqlite.
#

12
SOURCES/python-2.6-rpath.patch

@ -0,0 +1,12 @@
diff -up Python-2.6/configure.ac.rpath Python-2.6/configure.ac
--- Python-2.6/configure.ac.rpath 2008-11-24 02:51:06.000000000 -0500
+++ Python-2.6/configure.ac 2008-11-24 02:51:21.000000000 -0500
@@ -729,7 +729,7 @@ if test $enable_shared = "yes"; then
;;
OSF*)
LDLIBRARY='libpython$(VERSION).so'
- BLDLIBRARY='-rpath $(LIBDIR) -L. -lpython$(VERSION)'
+ BLDLIBRARY='-L. -lpython$(VERSION)'
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH}
;;
atheos*)

20
SOURCES/python-2.6.4-distutils-rpath.patch

@ -0,0 +1,20 @@
diff -up Python-2.6.4/Lib/distutils/unixccompiler.py.distutils-rpath Python-2.6.4/Lib/distutils/unixccompiler.py
--- Python-2.6.4/Lib/distutils/unixccompiler.py.distutils-rpath 2009-09-09 04:34:06.000000000 -0400
+++ Python-2.6.4/Lib/distutils/unixccompiler.py 2010-03-15 21:33:25.000000000 -0400
@@ -142,6 +142,16 @@ class UnixCCompiler(CCompiler):
if sys.platform == "cygwin":
exe_extension = ".exe"
+ def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs):
+ """Remove standard library path from rpath"""
+ libraries, library_dirs, runtime_library_dirs = \
+ CCompiler._fix_lib_args(self, libraries, library_dirs,
+ runtime_library_dirs)
+ libdir = sysconfig.get_config_var('LIBDIR')
+ if runtime_library_dirs and (libdir in runtime_library_dirs):
+ runtime_library_dirs.remove(libdir)
+ return libraries, library_dirs, runtime_library_dirs
+
def preprocess(self, source,
output_file=None, macros=None, include_dirs=None,
extra_preargs=None, extra_postargs=None):

44
SOURCES/python-2.7-lib64-sysconfig.patch

@ -0,0 +1,44 @@
diff -up Python-2.7/Lib/sysconfig.py.lib64-sysconfig Python-2.7/Lib/sysconfig.py
--- Python-2.7/Lib/sysconfig.py.lib64-sysconfig 2010-07-08 14:18:41.386898476 -0400
+++ Python-2.7/Lib/sysconfig.py 2010-07-08 14:22:02.837896461 -0400
@@ -7,20 +7,20 @@ from os.path import pardir, realpath
_INSTALL_SCHEMES = {
'posix_prefix': {
- 'stdlib': '{base}/lib/python{py_version_short}',
- 'platstdlib': '{platbase}/lib/python{py_version_short}',
+ 'stdlib': '{base}/lib64/python{py_version_short}',
+ 'platstdlib': '{platbase}/lib64/python{py_version_short}',
'purelib': '{base}/lib/python{py_version_short}/site-packages',
- 'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
+ 'platlib': '{platbase}/lib64/python{py_version_short}/site-packages',
'include': '{base}/include/python{py_version_short}',
'platinclude': '{platbase}/include/python{py_version_short}',
'scripts': '{base}/bin',
'data': '{base}',
},
'posix_home': {
- 'stdlib': '{base}/lib/python',
- 'platstdlib': '{base}/lib/python',
+ 'stdlib': '{base}/lib64/python',
+ 'platstdlib': '{base}/lib64/python',
'purelib': '{base}/lib/python',
- 'platlib': '{base}/lib/python',
+ 'platlib': '{base}/lib64/python',
'include': '{base}/include/python',
'platinclude': '{base}/include/python',
'scripts': '{base}/bin',
@@ -65,10 +65,10 @@ _INSTALL_SCHEMES = {
'data' : '{userbase}',
},
'posix_user': {
- 'stdlib': '{userbase}/lib/python{py_version_short}',
- 'platstdlib': '{userbase}/lib/python{py_version_short}',
+ 'stdlib': '{userbase}/lib64/python{py_version_short}',
+ 'platstdlib': '{userbase}/lib64/python{py_version_short}',
'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
- 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
+ 'platlib': '{userbase}/lib64/python{py_version_short}/site-packages',
'include': '{userbase}/include/python{py_version_short}',
'scripts': '{userbase}/bin',
'data' : '{userbase}',

283
SOURCES/python-2.7.1-config.patch

@ -0,0 +1,283 @@
--- Python-2.7.4/Modules/Setup.dist.rhconfig 2013-04-06 16:02:34.000000000 +0200
+++ Python-2.7.4/Modules/Setup.dist 2013-04-08 10:05:16.369985654 +0200
@@ -153,7 +153,7 @@ GLHACK=-Dclear=__GLclear
# modules are to be built as shared libraries (see above for more
# detail; also note that *static* reverses this effect):
-#*shared*
+*shared*
# GNU readline. Unlike previous Python incarnations, GNU readline is
# now incorporated in an optional module, configured in the Setup file
@@ -163,77 +163,77 @@ GLHACK=-Dclear=__GLclear
# it, depending on your system -- see the GNU readline instructions.
# It's okay for this to be a shared library, too.
-#readline readline.c -lreadline -ltermcap
+readline readline.c -lreadline -ltermcap
# Modules that should always be present (non UNIX dependent):
-#array arraymodule.c # array objects
-#cmath cmathmodule.c _math.c # -lm # complex math library functions
-#math mathmodule.c _math.c # -lm # math library functions, e.g. sin()
-#_struct _struct.c # binary structure packing/unpacking
-#time timemodule.c # -lm # time operations and variables
-#operator operator.c # operator.add() and similar goodies
-#_testcapi _testcapimodule.c # Python C API test module
-#_random _randommodule.c # Random number generator
-#_collections _collectionsmodule.c # Container types
+array arraymodule.c # array objects
+cmath cmathmodule.c _math.c # -lm # complex math library functions
+math mathmodule.c _math.c # -lm # math library functions, e.g. sin()
+_struct _struct.c # binary structure packing/unpacking
+time timemodule.c # -lm # time operations and variables
+operator operator.c # operator.add() and similar goodies
+_testcapi _testcapimodule.c # Python C API test module
+_random _randommodule.c # Random number generator
+_collections _collectionsmodule.c # Container types
#_heapq _heapqmodule.c # Heapq type
-#itertools itertoolsmodule.c # Functions creating iterators for efficient looping
-#strop stropmodule.c # String manipulations
-#_functools _functoolsmodule.c # Tools for working with functions and callable objects
+itertools itertoolsmodule.c # Functions creating iterators for efficient looping
+strop stropmodule.c # String manipulations
+_functools _functoolsmodule.c # Tools for working with functions and callable objects
#_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator
#_pickle _pickle.c # pickle accelerator
#datetime datetimemodule.c # date/time type
-#_bisect _bisectmodule.c # Bisection algorithms
+_bisect _bisectmodule.c # Bisection algorithms
-#unicodedata unicodedata.c # static Unicode character database
+unicodedata unicodedata.c # static Unicode character database
# access to ISO C locale support
-#_locale _localemodule.c # -lintl
+_locale _localemodule.c # -lintl
# Standard I/O baseline
#_io -I$(srcdir)/Modules/_io _io/bufferedio.c _io/bytesio.c _io/fileio.c _io/iobase.c _io/_iomodule.c _io/stringio.c _io/textio.c
# Modules with some UNIX dependencies -- on by default:
# (If you have a really backward UNIX, select and socket may not be
# supported...)
-#fcntl fcntlmodule.c # fcntl(2) and ioctl(2)
-#spwd spwdmodule.c # spwd(3)
-#grp grpmodule.c # grp(3)
-#select selectmodule.c # select(2); not on ancient System V
+fcntl fcntlmodule.c # fcntl(2) and ioctl(2)
+spwd spwdmodule.c # spwd(3)
+grp grpmodule.c # grp(3)
+select selectmodule.c # select(2); not on ancient System V
# Memory-mapped files (also works on Win32).
-#mmap mmapmodule.c
+mmap mmapmodule.c
# CSV file helper
-#_csv _csv.c
+_csv _csv.c
# Socket module helper for socket(2)
-#_socket socketmodule.c timemodule.c
+_socket socketmodule.c timemodule.c
# Socket module helper for SSL support; you must comment out the other
# socket line above, and possibly edit the SSL variable:
#SSL=/usr/local/ssl
-#_ssl _ssl.c \
-# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
-# -L$(SSL)/lib -lssl -lcrypto
+_ssl _ssl.c \
+ -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
+ -L$(SSL)/lib -lssl -lcrypto
# The crypt module is now disabled by default because it breaks builds
# on many systems (where -lcrypt is needed), e.g. Linux (I believe).
#
# First, look at Setup.config; configure may have set this for you.
-#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems
+crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems
# Some more UNIX dependent modules -- off by default, since these
# are not supported by all UNIX systems:
-#nis nismodule.c -lnsl # Sun yellow pages -- not everywhere
-#termios termios.c # Steen Lumholt's termios module
-#resource resource.c # Jeremy Hylton's rlimit interface
+nis nismodule.c -lnsl # Sun yellow pages -- not everywhere
+termios termios.c # Steen Lumholt's termios module
+resource resource.c # Jeremy Hylton's rlimit interface
# Multimedia modules -- off by default.
@@ -238,8 +238,8 @@ GLHACK=-Dclear=__GLclear
# #993173 says audioop works on 64-bit platforms, though.
# These represent audio samples or images as strings:
-#audioop audioop.c # Operations on audio samples
-#imageop imageop.c # Operations on images
+audioop audioop.c # Operations on audio samples
+imageop imageop.c # Operations on images
# Note that the _md5 and _sha modules are normally only built if the
@@ -249,14 +249,14 @@ GLHACK=-Dclear=__GLclear
# Message-Digest Algorithm, described in RFC 1321. The necessary files
# md5.c and md5.h are included here.
-#_md5 md5module.c md5.c
+_md5 md5module.c md5.c
# The _sha module implements the SHA checksum algorithms.
# (NIST's Secure Hash Algorithms.)
-#_sha shamodule.c
-#_sha256 sha256module.c
-#_sha512 sha512module.c
+_sha shamodule.c
+_sha256 sha256module.c
+_sha512 sha512module.c
# SGI IRIX specific modules -- off by default.
@@ -303,12 +303,12 @@ GLHACK=-Dclear=__GLclear
# A Linux specific module -- off by default; this may also work on
# some *BSDs.
-#linuxaudiodev linuxaudiodev.c
+linuxaudiodev linuxaudiodev.c
# George Neville-Neil's timing module:
-#timing timingmodule.c
+timing timingmodule.c
# The _tkinter module.
@@ -323,7 +323,7 @@ GLHACK=-Dclear=__GLclear
# every system.
# *** Always uncomment this (leave the leading underscore in!):
-# _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \
+_tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \
# *** Uncomment and edit to reflect where your Tcl/Tk libraries are:
# -L/usr/local/lib \
# *** Uncomment and edit to reflect where your Tcl/Tk headers are:
@@ -333,7 +333,7 @@ GLHACK=-Dclear=__GLclear
# *** Or uncomment this for Solaris:
# -I/usr/openwin/include \
# *** Uncomment and edit for Tix extension only:
-# -DWITH_TIX -ltix8.1.8.2 \
+ -DWITH_TIX -ltix \
# *** Uncomment and edit for BLT extension only:
# -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \
# *** Uncomment and edit for PIL (TkImaging) extension only:
@@ -342,7 +342,7 @@ GLHACK=-Dclear=__GLclear
# *** Uncomment and edit for TOGL extension only:
# -DWITH_TOGL togl.c \
# *** Uncomment and edit to reflect your Tcl/Tk versions:
-# -ltk8.2 -ltcl8.2 \
+ -ltk -ltcl \
# *** Uncomment and edit to reflect where your X11 libraries are:
# -L/usr/X11R6/lib \
# *** Or uncomment this for Solaris:
@@ -352,7 +352,7 @@ GLHACK=-Dclear=__GLclear
# *** Uncomment for AIX:
# -lld \
# *** Always uncomment this; X11 libraries to link with:
-# -lX11
+ -lX11
# Lance Ellinghaus's syslog module
#syslog syslogmodule.c # syslog daemon interface
@@ -374,7 +374,7 @@ GLHACK=-Dclear=__GLclear
# it is a highly experimental and dangerous device for calling
# *arbitrary* C functions in *arbitrary* shared libraries:
-#dl dlmodule.c
+dl dlmodule.c
# Modules that provide persistent dictionary-like semantics. You will
@@ -397,7 +397,7 @@ GLHACK=-Dclear=__GLclear
#
# First, look at Setup.config; configure may have set this for you.
-#gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm
+gdbm gdbmmodule.c -lgdbm
# Sleepycat Berkeley DB interface.
@@ -412,11 +412,9 @@ GLHACK=-Dclear=__GLclear
#
# Edit the variables DB and DBLIBVERto point to the db top directory
# and the subdirectory of PORT where you built it.
-#DB=/usr/local/BerkeleyDB.4.0
-#DBLIBVER=4.0
-#DBINC=$(DB)/include
-#DBLIB=$(DB)/lib
-#_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER)
+DBINC=/usr/include/libdb
+DBLIB=/usr/lib
+_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb
# Historical Berkeley DB 1.85
#
@@ -431,14 +430,14 @@ GLHACK=-Dclear=__GLclear
# Helper module for various ascii-encoders
-#binascii binascii.c
+binascii binascii.c
# Fred Drake's interface to the Python parser
-#parser parsermodule.c
+parser parsermodule.c
# cStringIO and cPickle
-#cStringIO cStringIO.c
-#cPickle cPickle.c
+cStringIO cStringIO.c
+cPickle cPickle.c
# Lee Busby's SIGFPE modules.
@@ -461,7 +460,7 @@ GLHACK=-Dclear=__GLclear
# Andrew Kuchling's zlib module.
# This require zlib 1.1.3 (or later).
# See http://www.gzip.org/zlib/
-#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
+zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
# Interface to the Expat XML parser
#
@@ -480,14 +479,14 @@ GLHACK=-Dclear=__GLclear
# Hye-Shik Chang's CJKCodecs
# multibytecodec is required for all the other CJK codec modules
-#_multibytecodec cjkcodecs/multibytecodec.c
+_multibytecodec cjkcodecs/multibytecodec.c
-#_codecs_cn cjkcodecs/_codecs_cn.c
-#_codecs_hk cjkcodecs/_codecs_hk.c
-#_codecs_iso2022 cjkcodecs/_codecs_iso2022.c
-#_codecs_jp cjkcodecs/_codecs_jp.c
-#_codecs_kr cjkcodecs/_codecs_kr.c
-#_codecs_tw cjkcodecs/_codecs_tw.c
+_codecs_cn cjkcodecs/_codecs_cn.c
+_codecs_hk cjkcodecs/_codecs_hk.c
+_codecs_iso2022 cjkcodecs/_codecs_iso2022.c
+_codecs_jp cjkcodecs/_codecs_jp.c
+_codecs_kr cjkcodecs/_codecs_kr.c
+_codecs_tw cjkcodecs/_codecs_tw.c
# Example -- included for reference only:
# xx xxmodule.c

27
SOURCES/python-2.7.1-fix_test_abc_with_COUNT_ALLOCS.patch

@ -0,0 +1,27 @@
diff -up Python-2.7.1/Lib/test/test_abc.py.cache_leak Python-2.7.1/Lib/test/test_abc.py
--- Python-2.7.1/Lib/test/test_abc.py.cache_leak 2010-12-28 18:06:35.551938356 -0500
+++ Python-2.7.1/Lib/test/test_abc.py 2010-12-28 18:09:09.021059202 -0500
@@ -3,6 +3,8 @@
"""Unit tests for abc.py."""
+import sys
+
import unittest, weakref
from test import test_support
@@ -229,8 +231,12 @@ class TestABC(unittest.TestCase):
# Trigger cache.
C().f()
del C
- test_support.gc_collect()
- self.assertEqual(r(), None)
+ # This doesn't work in our debug build, presumably due to its use
+ # of COUNT_ALLOCS, which makes heap-allocated types immortal (once
+ # they've ever had an instance):
+ if not hasattr(sys, 'getcounts'):
+ test_support.gc_collect()
+ self.assertEqual(r(), None)
def test_main():
test_support.run_unittest(TestABC)

18
SOURCES/python-2.7.2-add-extension-suffix-to-python-config.patch

@ -0,0 +1,18 @@
diff -up Python-2.7.2/Misc/python-config.in.add-extension-suffix-to-python-config Python-2.7.2/Misc/python-config.in
--- Python-2.7.2/Misc/python-config.in.add-extension-suffix-to-python-config 2011-08-23 18:15:41.832497124 -0400
+++ Python-2.7.2/Misc/python-config.in 2011-08-23 18:17:25.854490011 -0400
@@ -6,7 +6,7 @@ import getopt
from distutils import sysconfig
valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags',
- 'ldflags', 'help']
+ 'ldflags', 'extension-suffix', 'help']
def exit_with_usage(code=1):
print >>sys.stderr, "Usage: %s [%s]" % (sys.argv[0],
@@ -54,3 +54,5 @@ for opt in opt_flags:
libs.extend(getvar('LINKFORSHARED').split())
print ' '.join(libs)
+ elif opt == '--extension-suffix':
+ print (sys.pydebug and "_d" or "") + sysconfig.get_config_var('SO')

292
SOURCES/python-2.7.3-debug-build.patch

@ -0,0 +1,292 @@
diff -up Python-2.7.3/configure.ac.debug-build Python-2.7.3/configure.ac
--- Python-2.7.3/configure.ac.debug-build 2012-04-18 19:46:22.066498521 -0400
+++ Python-2.7.3/configure.ac 2012-04-18 19:46:22.078498372 -0400
@@ -635,7 +635,7 @@ AC_SUBST(LIBRARY)
AC_MSG_CHECKING(LIBRARY)
if test -z "$LIBRARY"
then
- LIBRARY='libpython$(VERSION).a'
+ LIBRARY='libpython$(VERSION)$(DEBUG_EXT).a'
fi
AC_MSG_RESULT($LIBRARY)
@@ -780,8 +780,8 @@ if test $enable_shared = "yes"; then
INSTSONAME="$LDLIBRARY".$SOVERSION
;;
Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*)
- LDLIBRARY='libpython$(VERSION).so'
- BLDLIBRARY='-L. -lpython$(VERSION)'
+ LDLIBRARY='libpython$(VERSION)$(DEBUG_EXT).so'
+ BLDLIBRARY='-L. -lpython$(VERSION)$(DEBUG_EXT)'
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH}
case $ac_sys_system in
FreeBSD*)
@@ -905,6 +905,14 @@ else AC_MSG_RESULT(no); Py_DEBUG='false'
fi],
[AC_MSG_RESULT(no)])
+if test "$Py_DEBUG" = 'true'
+then
+ DEBUG_EXT=_d
+ DEBUG_SUFFIX=-debug
+fi
+AC_SUBST(DEBUG_EXT)
+AC_SUBST(DEBUG_SUFFIX)
+
# XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be
# merged with this chunk of code?
diff -up Python-2.7.3/Lib/distutils/command/build_ext.py.debug-build Python-2.7.3/Lib/distutils/command/build_ext.py
--- Python-2.7.3/Lib/distutils/command/build_ext.py.debug-build 2012-04-09 19:07:29.000000000 -0400
+++ Python-2.7.3/Lib/distutils/command/build_ext.py 2012-04-18 19:46:22.079498360 -0400
@@ -676,7 +676,10 @@ class build_ext (Command):
so_ext = get_config_var('SO')
if os.name == 'nt' and self.debug:
return os.path.join(*ext_path) + '_d' + so_ext
- return os.path.join(*ext_path) + so_ext
+
+ # Similarly, extensions in debug mode are named 'module_d.so', to
+ # avoid adding the _d to the SO config variable:
+ return os.path.join(*ext_path) + (sys.pydebug and "_d" or "") + so_ext
def get_export_symbols (self, ext):
"""Return the list of symbols that a shared extension has to
@@ -761,6 +764,8 @@ class build_ext (Command):
template = "python%d.%d"
pythonlib = (template %
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
+ if sys.pydebug:
+ pythonlib += '_d'
return ext.libraries + [pythonlib]
else:
return ext.libraries
diff -up Python-2.7.3/Lib/distutils/sysconfig.py.debug-build Python-2.7.3/Lib/distutils/sysconfig.py
--- Python-2.7.3/Lib/distutils/sysconfig.py.debug-build 2012-04-18 19:46:21.988499499 -0400
+++ Python-2.7.3/Lib/distutils/sysconfig.py 2012-04-18 19:46:22.080498348 -0400
@@ -85,7 +85,8 @@ def get_python_inc(plat_specific=0, pref
# Include is located in the srcdir
inc_dir = os.path.join(srcdir, "Include")
return inc_dir
- return os.path.join(prefix, "include", "python" + get_python_version())
+ return os.path.join(prefix, "include",
+ "python" + get_python_version() + (sys.pydebug and '-debug' or ''))
elif os.name == "nt":
return os.path.join(prefix, "include")
elif os.name == "os2":
@@ -250,7 +251,7 @@ def get_makefile_filename():
if python_build:
return os.path.join(project_base, "Makefile")
lib_dir = get_python_lib(plat_specific=1, standard_lib=1)
- return os.path.join(lib_dir, "config", "Makefile")
+ return os.path.join(lib_dir, "config" + (sys.pydebug and "-debug" or ""), "Makefile")
def parse_config_h(fp, g=None):
diff -up Python-2.7.3/Lib/distutils/tests/test_install.py.debug-build Python-2.7.3/Lib/distutils/tests/test_install.py
--- Python-2.7.3/Lib/distutils/tests/test_install.py.debug-build 2012-04-18 19:46:21.997499385 -0400
+++ Python-2.7.3/Lib/distutils/tests/test_install.py 2012-04-18 19:46:22.080498348 -0400
@@ -20,8 +20,9 @@ from distutils.tests import support
def _make_ext_name(modname):
- if os.name == 'nt' and sys.executable.endswith('_d.exe'):
+ if sys.pydebug:
modname += '_d'
+
return modname + sysconfig.get_config_var('SO')
diff -up Python-2.7.3/Makefile.pre.in.debug-build Python-2.7.3/Makefile.pre.in
--- Python-2.7.3/Makefile.pre.in.debug-build 2012-04-18 19:46:22.073498437 -0400
+++ Python-2.7.3/Makefile.pre.in 2012-04-18 19:48:46.336694896 -0400
@@ -102,8 +102,8 @@ SCRIPTDIR= $(prefix)/lib64
# Detailed destination directories
BINLIBDEST= $(LIBDIR)/python$(VERSION)
LIBDEST= $(SCRIPTDIR)/python$(VERSION)
-INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)
-CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION)
+INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)$(DEBUG_SUFFIX)
+CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION)$(DEBUG_SUFFIX)
LIBP= $(LIBDIR)/python$(VERSION)
# Symbols used for using shared libraries
@@ -117,6 +117,12 @@ DESTSHARED= $(BINLIBDEST)/lib-dynload
EXE= @EXEEXT@
BUILDEXE= @BUILDEXEEXT@
+# DEBUG_EXT is used by ELF files (names and SONAMEs); it will be "_d" for a debug build
+# DEBUG_SUFFIX is used by filesystem paths; it will be "-debug" for a debug build
+# Both will be empty in an optimized build
+DEBUG_EXT= @DEBUG_EXT@
+DEBUG_SUFFIX= @DEBUG_SUFFIX@
+
# Short name and location for Mac OS X Python framework
UNIVERSALSDK=@UNIVERSALSDK@
PYTHONFRAMEWORK= @PYTHONFRAMEWORK@
@@ -180,8 +186,8 @@ LIBOBJDIR= Python/
LIBOBJS= @LIBOBJS@
UNICODE_OBJS= @UNICODE_OBJS@
-PYTHON= python$(EXE)
-BUILDPYTHON= python$(BUILDEXE)
+PYTHON= python$(DEBUG_SUFFIX)$(EXE)
+BUILDPYTHON= python$(DEBUG_SUFFIX)$(BUILDEXE)
PYTHON_FOR_BUILD=@PYTHON_FOR_BUILD@
_PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@
@@ -413,7 +419,7 @@ sharedmods: $(BUILDPYTHON)
$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
-libpython$(VERSION).so: $(LIBRARY_OBJS)
+libpython$(VERSION)$(DEBUG_EXT).so: $(LIBRARY_OBJS)
if test $(INSTSONAME) != $(LDLIBRARY); then \
$(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
$(LN) -f $(INSTSONAME) $@; \
@@ -796,18 +802,18 @@ bininstall: altbininstall
then rm -f $(DESTDIR)$(BINDIR)/$(PYTHON); \
else true; \
fi
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(EXE) $(PYTHON))
- -rm -f $(DESTDIR)$(BINDIR)/python2$(EXE)
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(EXE) python2$(EXE))
- -rm -f $(DESTDIR)$(BINDIR)/python2-config
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)-config python2-config)
- -rm -f $(DESTDIR)$(BINDIR)/python-config
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python2-config python-config)
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(DEBUG_SUFFIX)$(EXE) $(PYTHON))
+ -rm -f $(DESTDIR)$(BINDIR)/python2$(DEBUG_SUFFIX)$(EXE)
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(DEBUG_SUFFIX)$(EXE) python2$(DEBUG_SUFFIX)$(EXE))
+ -rm -f $(DESTDIR)$(BINDIR)/python2$(DEBUG_SUFFIX)-config
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(DEBUG_SUFFIX)-config python2$(DEBUG_SUFFIX)-config)
+ -rm -f $(DESTDIR)$(BINDIR)/python$(DEBUG_SUFFIX)-config
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(DEBUG_SUFFIX)-config python$(DEBUG_SUFFIX)-config)
-test -d $(DESTDIR)$(LIBPC) || $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(LIBPC)
- -rm -f $(DESTDIR)$(LIBPC)/python2.pc
- (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION).pc python2.pc)
- -rm -f $(DESTDIR)$(LIBPC)/python.pc
- (cd $(DESTDIR)$(LIBPC); $(LN) -s python2.pc python.pc)
+ -rm -f $(DESTDIR)$(LIBPC)/python2$(DEBUG_SUFFIX).pc
+ (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION)$(DEBUG_SUFFIX).pc python2$(DEBUG_SUFFIX).pc)
+ -rm -f $(DESTDIR)$(LIBPC)/python$(DEBUG_SUFFIX).pc
+ (cd $(DESTDIR)$(LIBPC); $(LN) -s python2$(DEBUG_SUFFIX).pc python$(DEBUG_SUFFIX).pc)
# Install the interpreter with $(VERSION) affixed
# This goes into $(exec_prefix)
@@ -820,7 +826,7 @@ altbininstall: $(BUILDPYTHON)
else true; \
fi; \
done
- $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(EXE)
+ $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)$(EXE)
if test -f $(LDLIBRARY); then \
if test -n "$(DLLLIBRARY)" ; then \
$(INSTALL_SHARED) $(DLLLIBRARY) $(DESTDIR)$(BINDIR); \
@@ -970,10 +976,11 @@ $(srcdir)/Lib/$(PLATDIR):
fi; \
cd $(srcdir)/Lib/$(PLATDIR); $(RUNSHARED) ./regen
-python-config: $(srcdir)/Misc/python-config.in
+python$(DEBUG_SUFFIX)-config: $(srcdir)/Misc/python-config.in
# Substitution happens here, as the completely-expanded BINDIR
# is not available in configure
- sed -e "s,@EXENAME@,$(BINDIR)/python$(VERSION)$(EXE)," < $(srcdir)/Misc/python-config.in >python-config
+ sed -e "s,@EXENAME@,$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)$(EXE)," < $(srcdir)/Misc/python-config.in >python$(DEBUG_SUFFIX)-config
+
# Install the include files
INCLDIRSTOMAKE=$(INCLUDEDIR) $(CONFINCLUDEDIR) $(INCLUDEPY) $(CONFINCLUDEPY)
@@ -994,13 +1001,13 @@ inclinstall:
$(INSTALL_DATA) pyconfig.h $(DESTDIR)$(CONFINCLUDEPY)/pyconfig.h
# Install the library and miscellaneous stuff needed for extending/embedding
-# This goes into $(exec_prefix)
-LIBPL= $(LIBP)/config
+# This goes into $(exec_prefix)$(DEBUG_SUFFIX)
+LIBPL= $(LIBP)/config$(DEBUG_SUFFIX)
# pkgconfig directory
LIBPC= $(LIBDIR)/pkgconfig
-libainstall: all python-config
+libainstall: all python$(DEBUG_SUFFIX)-config
@for i in $(LIBDIR) $(LIBP) $(LIBPL) $(LIBPC); \
do \
if test ! -d $(DESTDIR)$$i; then \
@@ -1016,11 +1023,10 @@ libainstall: all python-config
$(INSTALL_DATA) Modules/Setup $(DESTDIR)$(LIBPL)/Setup
$(INSTALL_DATA) Modules/Setup.local $(DESTDIR)$(LIBPL)/Setup.local
$(INSTALL_DATA) Modules/Setup.config $(DESTDIR)$(LIBPL)/Setup.config
- $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION).pc
+ $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION)$(DEBUG_SUFFIX).pc
$(INSTALL_SCRIPT) $(srcdir)/Modules/makesetup $(DESTDIR)$(LIBPL)/makesetup
$(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh
- $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(VERSION)-config
- rm python-config
+ $(INSTALL_SCRIPT) python$(DEBUG_SUFFIX)-config $(DESTDIR)$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)-config
@if [ -s Modules/python.exp -a \
"`echo $(MACHDEP) | sed 's/^\(...\).*/\1/'`" = "aix" ]; then \
echo; echo "Installing support files for building shared extension modules on AIX:"; \
diff -up Python-2.7.3/Misc/python-config.in.debug-build Python-2.7.3/Misc/python-config.in
--- Python-2.7.3/Misc/python-config.in.debug-build 2012-04-09 19:07:33.000000000 -0400
+++ Python-2.7.3/Misc/python-config.in 2012-04-18 19:46:22.082498324 -0400
@@ -45,7 +45,7 @@ for opt in opt_flags:
elif opt in ('--libs', '--ldflags'):
libs = getvar('LIBS').split() + getvar('SYSLIBS').split()
- libs.append('-lpython'+pyver)
+ libs.append('-lpython' + pyver + (sys.pydebug and "_d" or ""))
# add the prefix/lib/pythonX.Y/config dir, but only if there is no
# shared library in prefix/lib/.
if opt == '--ldflags':
diff -up Python-2.7.3/Modules/makesetup.debug-build Python-2.7.3/Modules/makesetup
--- Python-2.7.3/Modules/makesetup.debug-build 2012-04-09 19:07:34.000000000 -0400
+++ Python-2.7.3/Modules/makesetup 2012-04-18 19:46:22.083498312 -0400
@@ -233,7 +233,7 @@ sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' |
*$mod.o*) base=$mod;;
*) base=${mod}module;;
esac
- file="$srcdir/$base\$(SO)"
+ file="$srcdir/$base\$(DEBUG_EXT)\$(SO)"
case $doconfig in
no) SHAREDMODS="$SHAREDMODS $file";;
esac
diff -up Python-2.7.3/Python/dynload_shlib.c.debug-build Python-2.7.3/Python/dynload_shlib.c
--- Python-2.7.3/Python/dynload_shlib.c.debug-build 2012-04-09 19:07:35.000000000 -0400
+++ Python-2.7.3/Python/dynload_shlib.c 2012-04-18 19:46:22.083498312 -0400
@@ -46,11 +46,16 @@ const struct filedescr _PyImport_DynLoad
{"module.exe", "rb", C_EXTENSION},
{"MODULE.EXE", "rb", C_EXTENSION},
#else
+#ifdef Py_DEBUG
+ {"_d.so", "rb", C_EXTENSION},
+ {"module_d.so", "rb", C_EXTENSION},
+#else
{".so", "rb", C_EXTENSION},
{"module.so", "rb", C_EXTENSION},
-#endif
-#endif
-#endif
+#endif /* Py_DEBUG */
+#endif /* __VMS */
+#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */
+#endif /* __CYGWIN__ */
{0, 0}
};
diff -up Python-2.7.3/Python/sysmodule.c.debug-build Python-2.7.3/Python/sysmodule.c
--- Python-2.7.3/Python/sysmodule.c.debug-build 2012-04-09 19:07:35.000000000 -0400
+++ Python-2.7.3/Python/sysmodule.c 2012-04-18 19:46:22.083498312 -0400
@@ -1506,6 +1506,12 @@ _PySys_Init(void)
PyString_FromString("legacy"));
#endif
+#ifdef Py_DEBUG
+ PyDict_SetItemString(sysdict, "pydebug", Py_True);
+#else
+ PyDict_SetItemString(sysdict, "pydebug", Py_False);
+#endif
+
#undef SET_SYS_FROM_STRING
if (PyErr_Occurred())
return NULL;

196
SOURCES/python-2.7.3-lib64.patch

@ -0,0 +1,196 @@
diff -up Python-2.7.3/Lib/distutils/command/install.py.lib64 Python-2.7.3/Lib/distutils/command/install.py
--- Python-2.7.3/Lib/distutils/command/install.py.lib64 2012-04-09 19:07:29.000000000 -0400
+++ Python-2.7.3/Lib/distutils/command/install.py 2013-02-19 13:58:20.446015129 -0500
@@ -42,14 +42,14 @@ else:
INSTALL_SCHEMES = {
'unix_prefix': {
'purelib': '$base/lib/python$py_version_short/site-packages',
- 'platlib': '$platbase/lib/python$py_version_short/site-packages',
+ 'platlib': '$platbase/lib64/python$py_version_short/site-packages',
'headers': '$base/include/python$py_version_short/$dist_name',
'scripts': '$base/bin',
'data' : '$base',
},
'unix_home': {
'purelib': '$base/lib/python',
- 'platlib': '$base/lib/python',
+ 'platlib': '$base/lib64/python',
'headers': '$base/include/python/$dist_name',
'scripts': '$base/bin',
'data' : '$base',
diff -up Python-2.7.3/Lib/distutils/sysconfig.py.lib64 Python-2.7.3/Lib/distutils/sysconfig.py
--- Python-2.7.3/Lib/distutils/sysconfig.py.lib64 2012-04-09 19:07:29.000000000 -0400
+++ Python-2.7.3/Lib/distutils/sysconfig.py 2013-02-19 13:58:20.446015129 -0500
@@ -114,8 +114,12 @@ def get_python_lib(plat_specific=0, stan
prefix = plat_specific and EXEC_PREFIX or PREFIX
if os.name == "posix":
+ if plat_specific or standard_lib:
+ lib = "lib64"
+ else:
+ lib = "lib"
libpython = os.path.join(prefix,
- "lib", "python" + get_python_version())
+ lib, "python" + get_python_version())
if standard_lib:
return libpython
else:
diff -up Python-2.7.3/Lib/site.py.lib64 Python-2.7.3/Lib/site.py
--- Python-2.7.3/Lib/site.py.lib64 2012-04-09 19:07:31.000000000 -0400
+++ Python-2.7.3/Lib/site.py 2013-02-19 13:58:20.447015128 -0500
@@ -300,12 +300,16 @@ def getsitepackages():
if sys.platform in ('os2emx', 'riscos'):
sitepackages.append(os.path.join(prefix, "Lib", "site-packages"))
elif os.sep == '/':
+ sitepackages.append(os.path.join(prefix, "lib64",
+ "python" + sys.version[:3],
+ "site-packages"))
sitepackages.append(os.path.join(prefix, "lib",
"python" + sys.version[:3],
"site-packages"))
sitepackages.append(os.path.join(prefix, "lib", "site-python"))
else:
sitepackages.append(prefix)
+ sitepackages.append(os.path.join(prefix, "lib64", "site-packages"))
sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
if sys.platform == "darwin":
# for framework builds *only* we add the standard Apple
diff -up Python-2.7.3/Lib/test/test_site.py.lib64 Python-2.7.3/Lib/test/test_site.py
--- Python-2.7.3/Lib/test/test_site.py.lib64 2012-04-09 19:07:32.000000000 -0400
+++ Python-2.7.3/Lib/test/test_site.py 2013-02-19 13:58:20.447015128 -0500
@@ -241,17 +241,20 @@ class HelperFunctionsTests(unittest.Test
self.assertEqual(dirs[2], wanted)
elif os.sep == '/':
# OS X non-framwework builds, Linux, FreeBSD, etc
- self.assertEqual(len(dirs), 2)
- wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3],
+ self.assertEqual(len(dirs), 3)
+ wanted = os.path.join('xoxo', 'lib64', 'python' + sys.version[:3],
'site-packages')
self.assertEqual(dirs[0], wanted)
- wanted = os.path.join('xoxo', 'lib', 'site-python')
+ wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3],
+ 'site-packages')
self.assertEqual(dirs[1], wanted)
+ wanted = os.path.join('xoxo', 'lib', 'site-python')
+ self.assertEqual(dirs[2], wanted)
else:
# other platforms
self.assertEqual(len(dirs), 2)
self.assertEqual(dirs[0], 'xoxo')
- wanted = os.path.join('xoxo', 'lib', 'site-packages')
+ wanted = os.path.join('xoxo', 'lib64', 'site-packages')
self.assertEqual(dirs[1], wanted)
class PthFile(object):
diff -up Python-2.7.3/Makefile.pre.in.lib64 Python-2.7.3/Makefile.pre.in
--- Python-2.7.3/Makefile.pre.in.lib64 2013-02-19 13:58:20.435015131 -0500
+++ Python-2.7.3/Makefile.pre.in 2013-02-19 13:58:20.447015128 -0500
@@ -97,7 +97,7 @@ LIBDIR= @libdir@
MANDIR= @mandir@
INCLUDEDIR= @includedir@
CONFINCLUDEDIR= $(exec_prefix)/include
-SCRIPTDIR= $(prefix)/lib
+SCRIPTDIR= $(prefix)/lib64
# Detailed destination directories
BINLIBDEST= $(LIBDIR)/python$(VERSION)
diff -up Python-2.7.3/Modules/getpath.c.lib64 Python-2.7.3/Modules/getpath.c
--- Python-2.7.3/Modules/getpath.c.lib64 2012-04-09 19:07:34.000000000 -0400
+++ Python-2.7.3/Modules/getpath.c 2013-02-19 13:58:20.448015128 -0500
@@ -117,8 +117,8 @@
#endif
#ifndef PYTHONPATH
-#define PYTHONPATH PREFIX "/lib/python" VERSION ":" \
- EXEC_PREFIX "/lib/python" VERSION "/lib-dynload"
+#define PYTHONPATH PREFIX "/lib64/python" VERSION ":" \
+ EXEC_PREFIX "/lib64/python" VERSION "/lib-dynload"
#endif
#ifndef LANDMARK
@@ -129,7 +129,7 @@ static char prefix[MAXPATHLEN+1];
static char exec_prefix[MAXPATHLEN+1];
static char progpath[MAXPATHLEN+1];
static char *module_search_path = NULL;
-static char lib_python[] = "lib/python" VERSION;
+static char lib_python[] = "lib64/python" VERSION;
static void
reduce(char *dir)
@@ -528,7 +528,7 @@ calculate_path(void)
}
else
strncpy(zip_path, PREFIX, MAXPATHLEN);
- joinpath(zip_path, "lib/python00.zip");
+ joinpath(zip_path, "lib64/python00.zip");
bufsz = strlen(zip_path); /* Replace "00" with version */
zip_path[bufsz - 6] = VERSION[0];
zip_path[bufsz - 5] = VERSION[2];
@@ -538,7 +538,7 @@ calculate_path(void)
fprintf(stderr,
"Could not find platform dependent libraries <exec_prefix>\n");
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN);
- joinpath(exec_prefix, "lib/lib-dynload");
+ joinpath(exec_prefix, "lib64/lib-dynload");
}
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */
diff -up Python-2.7.3/Modules/Setup.dist.lib64 Python-2.7.3/Modules/Setup.dist
--- Python-2.7.3/Modules/Setup.dist.lib64 2013-02-19 13:58:20.442015131 -0500
+++ Python-2.7.3/Modules/Setup.dist 2013-02-19 14:02:25.255998391 -0500
@@ -413,7 +413,7 @@ gdbm gdbmmodule.c -lgdbm
# Edit the variables DB and DBLIBVERto point to the db top directory
# and the subdirectory of PORT where you built it.
DBINC=/usr/include/libdb
-DBLIB=/usr/lib
+DBLIB=/usr/lib64
_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb
# Historical Berkeley DB 1.85
@@ -459,7 +459,7 @@ cPickle cPickle.c
# Andrew Kuchling's zlib module.
# This require zlib 1.1.3 (or later).
# See http://www.gzip.org/zlib/
-zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
+zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib64 -lz
# Interface to the Expat XML parser
#
diff -up Python-2.7.3/setup.py.lib64 Python-2.7.3/setup.py
--- Python-2.7.3/setup.py.lib64 2012-04-09 19:07:36.000000000 -0400
+++ Python-2.7.3/setup.py 2013-02-19 13:58:20.449015129 -0500
@@ -369,7 +369,7 @@ class PyBuildExt(build_ext):
def detect_modules(self):
# Ensure that /usr/local is always used
- add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
+ add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib64')
add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
self.add_gcc_paths()
self.add_multiarch_paths()
@@ -677,11 +677,11 @@ class PyBuildExt(build_ext):
elif curses_library:
readline_libs.append(curses_library)
elif self.compiler.find_library_file(lib_dirs +
- ['/usr/lib/termcap'],
+ ['/usr/lib64/termcap'],
'termcap'):
readline_libs.append('termcap')
exts.append( Extension('readline', ['readline.c'],
- library_dirs=['/usr/lib/termcap'],
+ library_dirs=['/usr/lib64/termcap'],
extra_link_args=readline_extra_link_args,
libraries=readline_libs) )
else:
@@ -715,8 +715,8 @@ class PyBuildExt(build_ext):
if krb5_h:
ssl_incs += krb5_h
ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs,
- ['/usr/local/ssl/lib',
- '/usr/contrib/ssl/lib/'
+ ['/usr/local/ssl/lib64',
+ '/usr/contrib/ssl/lib64/'
] )
if (ssl_incs is not None and

14
SOURCES/python-2.7rc1-binutils-no-dep.patch

@ -0,0 +1,14 @@
diff -up Python-2.7rc1/Lib/ctypes/util.py.binutils-no-dep Python-2.7rc1/Lib/ctypes/util.py
--- Python-2.7rc1/Lib/ctypes/util.py.binutils-no-dep 2010-03-15 09:42:23.000000000 -0400
+++ Python-2.7rc1/Lib/ctypes/util.py 2010-06-06 05:03:02.155975210 -0400
@@ -140,7 +140,9 @@ elif os.name == "posix":
dump = f.read()
rv = f.close()
if rv == 10:
- raise OSError, 'objdump command not found'
+ return os.path.basename(f) # This is good for GLibc, I think,
+ # and a dep on binutils is big (for
+ # live CDs).
f = os.popen(cmd)
try:
data = f.read()

64
SOURCES/python-2.7rc1-socketmodule-constants.patch

@ -0,0 +1,64 @@
--- Python-2.7rc1/Modules/socketmodule.c.socketmodule 2010-05-09 10:46:46.000000000 -0400
+++ Python-2.7rc1/Modules/socketmodule.c 2010-06-07 23:04:19.374234780 -0400
@@ -4783,6 +4783,61 @@ init_socket(void)
PyModule_AddIntConstant(m, "SO_SETFIB", SO_SETFIB);
#endif
+#ifdef SO_SNDBUFFORCE
+ PyModule_AddIntConstant(m, "SO_SNDBUFFORCE", SO_SNDBUFFORCE);
+#endif
+#ifdef SO_RCVBUFFORCE
+ PyModule_AddIntConstant(m, "SO_RCVBUFFORCE", SO_RCVBUFFORCE);
+#endif
+#ifdef SO_NO_CHECK
+ PyModule_AddIntConstant(m, "SO_NO_CHECK", SO_NO_CHECK);
+#endif
+#ifdef SO_PRIORITY
+ PyModule_AddIntConstant(m, "SO_PRIORITY", SO_PRIORITY);
+#endif
+#ifdef SO_BSDCOMPAT
+ PyModule_AddIntConstant(m, "SO_BSDCOMPAT", SO_BSDCOMPAT);
+#endif
+#ifdef SO_PASSCRED
+ PyModule_AddIntConstant(m, "SO_PASSCRED", SO_PASSCRED);
+#endif
+#ifdef SO_PEERCRED
+ PyModule_AddIntConstant(m, "SO_PEERCRED", SO_PEERCRED);
+#endif
+#ifdef SO_SECURITY_AUTHENTICATION
+ PyModule_AddIntConstant(m, "SO_SECURITY_AUTHENTICATION", SO_SECURITY_AUTHENTICATION);
+#endif
+#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
+ PyModule_AddIntConstant(m, "SO_SECURITY_ENCRYPTION_TRANSPORT", SO_SECURITY_ENCRYPTION_TRANSPORT);
+#endif
+#ifdef SO_SECURITY_ENCRYPTION_NETWORK
+ PyModule_AddIntConstant(m, "SO_SECURITY_ENCRYPTION_NETWORK", SO_SECURITY_ENCRYPTION_NETWORK);
+#endif
+#ifdef SO_BINDTODEVICE
+ PyModule_AddIntConstant(m, "SO_BINDTODEVICE", SO_BINDTODEVICE);
+#endif
+#ifdef SO_ATTACH_FILTER
+ PyModule_AddIntConstant(m, "SO_ATTACH_FILTER", SO_ATTACH_FILTER);
+#endif
+#ifdef SO_DETACH_FILTER
+ PyModule_AddIntConstant(m, "SO_DETACH_FILTER", SO_DETACH_FILTER);
+#endif
+#ifdef SO_PEERNAME
+ PyModule_AddIntConstant(m, "SO_PEERNAME", SO_PEERNAME);
+#endif
+#ifdef SO_TIMESTAMP
+ PyModule_AddIntConstant(m, "SO_TIMESTAMP", SO_TIMESTAMP);
+#endif
+#ifdef SO_PEERSEC
+ PyModule_AddIntConstant(m, "SO_PEERSEC", SO_PEERSEC);
+#endif
+#ifdef SO_PASSSEC
+ PyModule_AddIntConstant(m, "SO_PASSSEC", SO_PASSSEC);
+#endif
+#ifdef SO_TIMESTAMPNS
+ PyModule_AddIntConstant(m, "SO_TIMESTAMPNS", SO_TIMESTAMPNS);
+#endif
+
/* Maximum number of connections for "listen" */
#ifdef SOMAXCONN
PyModule_AddIntConstant(m, "SOMAXCONN", SOMAXCONN);

19
SOURCES/python-2.7rc1-socketmodule-constants2.patch

@ -0,0 +1,19 @@
diff -up Python-2.7rc1/Modules/socketmodule.c.socketmodule2 Python-2.7rc1/Modules/socketmodule.c
--- Python-2.7rc1/Modules/socketmodule.c.socketmodule2 2010-06-07 23:06:59.133498087 -0400
+++ Python-2.7rc1/Modules/socketmodule.c 2010-06-07 23:11:51.249520087 -0400
@@ -5253,6 +5253,15 @@ init_socket(void)
#ifdef TCP_QUICKACK
PyModule_AddIntConstant(m, "TCP_QUICKACK", TCP_QUICKACK);
#endif
+#ifdef TCP_CONGESTION
+ PyModule_AddIntConstant(m, "TCP_CONGESTION", TCP_CONGESTION);
+#endif
+#ifdef TCP_MD5SIG
+ PyModule_AddIntConstant(m, "TCP_MD5SIG", TCP_MD5SIG);
+#endif
+#ifdef TCP_MD5SIG_MAXKEYLEN
+ PyModule_AddIntConstant(m, "TCP_MD5SIG_MAXKEYLEN", TCP_MD5SIG_MAXKEYLEN);
+#endif
/* IPX options */

1
SOURCES/python.conf

@ -0,0 +1 @@
x /tmp/pymp-*

32
SOURCES/pythondeps.sh

@ -0,0 +1,32 @@
#!/bin/bash

[ $# -ge 1 ] || {
cat > /dev/null
exit 0
}

case $1 in
-P|--provides)
shift
# Match buildroot/payload paths of the form
# /PATH/OF/BUILDROOT/usr/bin/pythonMAJOR.MINOR
# generating a line of the form
# python(abi) = MAJOR.MINOR
# (Don't match against -config tools e.g. /usr/bin/python2.6-config)
grep "/usr/bin/python.\..$" \
| sed -e "s|.*/usr/bin/python\(.\..\)|python(abi) = \1|"
;;
-R|--requires)
shift
# Match buildroot paths of the form
# /PATH/OF/BUILDROOT/usr/lib/pythonMAJOR.MINOR/ and
# /PATH/OF/BUILDROOT/usr/lib64/pythonMAJOR.MINOR/
# generating (uniqely) lines of the form:
# python(abi) = MAJOR.MINOR
grep "/usr/lib[^/]*/python.\../.*" \
| sed -e "s|.*/usr/lib[^/]*/python\(.\..\)/.*|python(abi) = \1|g" \
| sort | uniq
;;
esac

exit 0

4233
SPECS/python.spec

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save