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 @@ @@ -1,822 +1,198 @@
diff -up Python-3.3.0rc2/configure.ac.systemtap Python-3.3.0rc2/configure.ac
--- Python-3.3.0rc2/configure.ac.systemtap 2012-09-09 05:11:14.000000000 -0400
+++ Python-3.3.0rc2/configure.ac 2012-09-10 09:17:21.114511781 -0400
@@ -2678,6 +2678,23 @@ if test "$with_valgrind" != no; then
OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT"
diff -up Python-2.7rc1/configure.ac.systemtap Python-2.7rc1/configure.ac
--- Python-2.7rc1/configure.ac.systemtap 2010-06-06 10:53:15.514975012 -0400
+++ Python-2.7rc1/configure.ac 2010-06-06 10:53:15.520974361 -0400
@@ -2616,6 +2616,38 @@ if test "$with_valgrind" != no; then
)
fi
+# Check for systemtap support
+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap
+AC_MSG_CHECKING([for --with-systemtap])
+AC_ARG_WITH([systemtap],
+ AC_HELP_STRING([--with(out)-systemtap], [disable/enable SystemTap support]),,
+ with_systemtap=no)
+AC_MSG_RESULT([$with_systemtap])
+if test "$with_systemtap" != no; then
+ AC_DEFINE(WITH_SYSTEMTAP, 1,
+ [Define if you want to compile in SystemTap support])
+ SYSTEMTAPOBJS="Python/pysystemtap.o"
+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h"
+fi
+
+AC_SUBST(SYSTEMTAPOBJS)
+AC_SUBST(SYSTEMTAPDEPS)
+
# -I${DLINCLDIR} is added to the compile rule for importdl.o
AC_SUBST(DLINCLDIR)
DLINCLDIR=.
diff -up Python-3.3.0rc2/configure.systemtap Python-3.3.0rc2/configure
--- Python-3.3.0rc2/configure.systemtap 2012-09-09 05:11:14.000000000 -0400
+++ Python-3.3.0rc2/configure 2012-09-10 09:17:21.116511780 -0400
@@ -618,6 +618,8 @@ TRUE
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;
+# Check for dtrace support
+AC_MSG_CHECKING(for --with-dtrace)
+AC_ARG_WITH(dtrace,
+ AC_HELP_STRING(--with(out)-dtrace, disable/enable dtrace support))
+
+if test ! -z "$with_dtrace"
+then
+ if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null
+ then
+ AC_DEFINE(WITH_DTRACE, 1,
+ [Define if you want to compile in Dtrace support])
+ with_dtrace="Sun"
+ DTRACEOBJS="Python/dtrace.o"
+ DTRADEHDRS=""
+ elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d
+ then
+ AC_DEFINE(WITH_DTRACE, 1,
+ [Define if you want to compile in Dtrace support])
+ with_dtrace="Apple"
+ DTRACEOBJS=""
+ DTRADEHDRS="pydtrace.h"
+ else
+ with_dtrace="no"
+ fi
+else
+ with_systemtap=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"
+ with_dtrace="no"
+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);
+};
+
+
+
# -I${DLINCLDIR} is added to the compile rule for importdl.o
DLINCLDIR=.
diff -up Python-3.3.0rc2/Doc/howto/index.rst.systemtap Python-3.3.0rc2/Doc/howto/index.rst
--- Python-3.3.0rc2/Doc/howto/index.rst.systemtap 2012-09-09 05:10:51.000000000 -0400
+++ Python-3.3.0rc2/Doc/howto/index.rst 2012-09-10 09:17:21.117511779 -0400
@@ -29,4 +29,5 @@ Currently, the HOWTOs are:
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= \
+#pragma D attributes Evolving/Evolving/Common provider python provider
+#pragma D attributes Private/Private/Common provider python module
+#pragma D attributes Private/Private/Common provider python function
+#pragma D attributes Evolving/Evolving/Common provider python name
+#pragma D attributes Evolving/Evolving/Common provider python args
diff -up Python-2.7rc1/Makefile.pre.in.systemtap Python-2.7rc1/Makefile.pre.in
--- Python-2.7rc1/Makefile.pre.in.systemtap 2010-06-06 10:53:15.488978775 -0400
+++ Python-2.7rc1/Makefile.pre.in 2010-06-06 11:05:30.411100568 -0400
@@ -298,6 +298,7 @@ PYTHON_OBJS= \
Python/formatter_unicode.o \
Python/fileutils.o \
Python/formatter_string.o \
Python/$(DYNLOADFILE) \
+ @SYSTEMTAPOBJS@ \
+ @DTRACEOBJS@ \
$(LIBOBJS) \
$(MACHDEP_OBJS) \
$(THREADOBJ)
@@ -713,7 +714,8 @@ Objects/setobject.o: $(srcdir)/Objects/s
$(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES)
$(OPCODETARGETGEN) $(OPCODETARGETS_H)
-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@
@@ -599,6 +600,18 @@ Python/formatter_unicode.o: $(srcdir)/Py
Python/formatter_string.o: $(srcdir)/Python/formatter_string.c \
$(STRINGLIB_HEADERS)
Python/frozen.o: Python/importlib.h Python/importlib_external.h
@@ -724,6 +726,13 @@ Objects/typeobject.o: $(srcdir)/Objects/
Objects/typeslots.inc: $(srcdir)/Include/typeslots.h $(srcdir)/Objects/typeslots.py
$(PYTHON) $(srcdir)/Objects/typeslots.py < $(srcdir)/Include/typeslots.h > Objects/typeslots.inc
+# Only needed with --with-systemtap; not a public header:
+$(srcdir)/Python/pysystemtap.h: $(srcdir)/Python/pysystemtap.d
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Python/pysystemtap.d
+# Only needed with --with-dtrace
+buildinclude:
+ mkdir -p Include
+
+Include/pydtrace.h: buildinclude $(srcdir)/Include/pydtrace.d
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Include/pydtrace.d
+
+Python/ceval.o: Include/pydtrace.h
+
+Python/pysystemtap.o: $(srcdir)/Python/pysystemtap.d Python/ceval.o
+ dtrace -o $@ $(DFLAGS) -C -G -s $(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)/Include/pydtrace.d Python/ceval.o
+
############################################################################
# Header files
@@ -1345,6 +1354,7 @@ clean: pycremoval
-rm -f Lib/lib2to3/*Grammar*.pickle
-rm -f Programs/_testembed Programs/_freeze_importlib
-rm -rf build
+ -rm -f $(srcdir)/Python/pysystemtap.h
profile-removal:
find . -name '*.gc??' -exec rm -f {} ';'
diff -up Python-3.3.0rc2/pyconfig.h.in.systemtap Python-3.3.0rc2/pyconfig.h.in
--- Python-3.3.0rc2/pyconfig.h.in.systemtap 2012-09-09 05:11:14.000000000 -0400
+++ Python-3.3.0rc2/pyconfig.h.in 2012-09-10 09:17:21.120511781 -0400
@@ -1306,6 +1306,9 @@
/* Define if you want to compile in Python-specific mallocs */
#undef WITH_PYMALLOC
+/* Define if you want to compile in SystemTap support */
+#undef WITH_SYSTEMTAP
+
/* Define if you want to compile in rudimentary thread support */
#undef WITH_THREAD
diff -up Python-3.3.0rc2/Python/ceval.c.systemtap Python-3.3.0rc2/Python/ceval.c
--- Python-3.3.0rc2/Python/ceval.c.systemtap 2012-09-09 05:11:12.000000000 -0400
+++ Python-3.3.0rc2/Python/ceval.c 2012-09-10 09:17:21.122511781 -0400
@@ -18,6 +18,8 @@
@@ -1251,7 +1264,7 @@ Python/thread.o: @THREADHEADERS@
.PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure
.PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools
.PHONY: frameworkaltinstallunixtools recheck autoconf clean clobber distclean
-.PHONY: smelly funny patchcheck touch altmaninstall
+.PHONY: smelly funny patchcheck touch altmaninstall buildinclude
.PHONY: gdbhooks
# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff -up Python-2.7rc1/pyconfig.h.in.systemtap Python-2.7rc1/pyconfig.h.in
--- Python-2.7rc1/pyconfig.h.in.systemtap 2010-05-08 07:04:18.000000000 -0400
+++ Python-2.7rc1/pyconfig.h.in 2010-06-06 10:53:15.521974070 -0400
@@ -1074,6 +1074,9 @@
/* Define if you want documentation strings in extension modules */
#undef WITH_DOC_STRINGS
+/* Define if you want to compile in Dtrace support */
+#undef WITH_DTRACE
+
/* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic
linker (dyld) instead of the old-style (NextStep) dynamic linker (rld).
Dyld is necessary to support frameworks. */
diff -up Python-2.7rc1/Python/ceval.c.systemtap Python-2.7rc1/Python/ceval.c
--- Python-2.7rc1/Python/ceval.c.systemtap 2010-05-09 10:46:46.000000000 -0400
+++ Python-2.7rc1/Python/ceval.c 2010-06-06 11:08:40.683100500 -0400
@@ -19,6 +19,10 @@
#include <ctype.h>
+#include "ceval_systemtap.h"
+#ifdef WITH_DTRACE
+#include "pydtrace.h"
+#endif
+
#ifndef WITH_TSC
#define READ_TIMESTAMP(var)
@@ -1160,6 +1162,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int
}
}
+ 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:
@@ -671,6 +675,55 @@ PyEval_EvalCode(PyCodeObject *co, PyObje
NULL);
}
/* pop frame */
exit_eval_frame:
+
+ 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
+#ifdef WITH_DTRACE
+static void
+dtrace_entry(PyFrameObject *f)
+{
+ PyObject *filename_obj;
+ PyObject *funcname_obj;
+ const char *filename;
+ const char *funcname;
+ const char *fname;
+ int lineno;
+};
+
+static void
+get_frame_marker_info(PyFrameObject *f, struct frame_marker_info *fmi)
+{
+ 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;
+ }
+ filename = PyString_AsString(f->f_code->co_filename);
+ fname = PyString_AsString(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+ fmi->funcname_obj = PyUnicode_AsUTF8String(f->f_code->co_name);
+ 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);
+ PYTHON_FUNCTION_ENTRY((char *)filename, (char *)fname, lineno);
+
+ /*
+ * Currently a USDT tail-call will not receive the correct arguments.
+ * Disable the tail call here.
+ */
+#if defined(__sparc)
+ asm("nop");
+#endif
+}
+
+static void
+release_frame_marker_info(struct frame_marker_info *fmi)
+dtrace_return(PyFrameObject *f)
+{
+ Py_XDECREF(fmi->filename_obj);
+ Py_XDECREF(fmi->funcname_obj);
+}
+ const char *filename;
+ const char *fname;
+ int lineno;
+
+static void
+systemtap_function_entry(PyFrameObject *f)
+{
+ struct frame_marker_info fmi;
+ get_frame_marker_info(f, &fmi);
+ PYTHON_FUNCTION_ENTRY(fmi.filename, fmi.funcname, fmi.lineno, f);
+ release_frame_marker_info(&fmi);
+}
+ filename = PyString_AsString(f->f_code->co_filename);
+ fname = PyString_AsString(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+ PYTHON_FUNCTION_RETURN((char *)filename, (char *)fname, lineno);
+
+static void
+systemtap_function_return(PyFrameObject *f)
+{
+ struct frame_marker_info fmi;
+ get_frame_marker_info(f, &fmi);
+ PYTHON_FUNCTION_RETURN(fmi.filename, fmi.funcname, fmi.lineno, f);
+ release_frame_marker_info(&fmi);
+ /*
+ * Currently a USDT tail-call will not receive the correct arguments.
+ * Disable the tail call here.
+ */
+#if defined(__sparc)
+ asm("nop");
+#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 */
+
+/*
+ When configured --without-systemtap, everything compiles away to nothing:
+*/
+#define PYTHON_FUNCTION_ENTRY_ENABLED() 0
+#define PYTHON_FUNCTION_RETURN_ENABLED() 0
+#define systemtap_function_entry(f)
+#define systemtap_function_return(f)
co = f->f_code;
names = co->co_names;
consts = co->co_consts;
@@ -3000,6 +3056,9 @@ fast_yield:
/* pop frame */
exit_eval_frame:
+ if (PYTHON_FUNCTION_RETURN_ENABLED())
+ dtrace_return(f);
+
+#endif
diff -up Python-3.3.0rc2/Python/pysystemtap.d.systemtap Python-3.3.0rc2/Python/pysystemtap.d
--- 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 *);
+};
Py_LeaveRecursiveCall();
tstate->frame = f->f_back;

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

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

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

@ -1,16 +1,17 @@ @@ -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
--- Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest 2011-09-03 12:16:44.000000000 -0400
+++ Python-3.2.2/Lib/unittest/case.py 2011-09-09 06:35:16.365568382 -0400
@@ -3,6 +3,7 @@
diff -up Python-2.7.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python-2.7.2/Lib/unittest/case.py
--- Python-2.7.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest 2011-09-08 14:45:47.677169191 -0400
+++ Python-2.7.2/Lib/unittest/case.py 2011-09-08 16:01:36.287858159 -0400
@@ -1,6 +1,7 @@
"""Test case implementation"""
import collections
+import os
import sys
import functools
import difflib
+import os
import logging
import pprint
import re
@@ -101,5 +102,21 @@ def expectedFailure(func):
raise self.test_case.failureException(msg)
@@ -94,6 +95,43 @@ def expectedFailure(func):
return wrapper
+# Non-standard/downstream-only hooks for handling issues with specific test
+# cases:
@ -28,19 +29,40 @@ diff -up Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python @@ -28,19 +29,40 @@ diff -up Python-3.2.2/Lib/unittest/case.py.add-rpmbuild-hooks-to-unittest Python
+ else:
+ 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-3.2.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest Python-3.2.2/Lib/unittest/__init__.py
--- Python-3.2.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest 2011-09-03 12:16:44.000000000 -0400
+++ Python-3.2.2/Lib/unittest/__init__.py 2011-09-09 06:35:16.366568382 -0400
diff -up Python-2.7.2/Lib/unittest/__init__.py.add-rpmbuild-hooks-to-unittest Python-2.7.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-2.7.2/Lib/unittest/__init__.py 2011-09-08 15:07:09.191081562 -0400
@@ -57,7 +57,8 @@ __unittest = True
from .result import TestResult
from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
- skipUnless, expectedFailure)
+ skipUnless, expectedFailure,
+ _skipInRpmBuild)
+ _skipInRpmBuild, _expectedFailureInRpmBuild)
from .suite import BaseTestSuite, TestSuite
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
findTestCases)

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

@ -1,12 +1,12 @@ @@ -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
--- 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-3.2.2/Lib/distutils/tests/test_bdist_rpm.py 2011-09-10 05:04:56.328852558 -0400
@@ -23,6 +23,7 @@ setup(name='foo', version='0.1', py_modu
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-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-2.7.3/Lib/distutils/tests/test_bdist_rpm.py 2012-04-13 00:20:08.223819263 -0400
@@ -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")
class BuildRpmTestCase(support.TempdirManager,
support.EnvironGuard,
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 @@ @@ -1,48 +1,82 @@
diff --git a/Lib/hashlib.py b/Lib/hashlib.py
index 316cece..b7ad879 100644
--- a/Lib/hashlib.py
+++ b/Lib/hashlib.py
@@ -23,6 +23,16 @@ the zlib module.
diff -up Python-2.7.2/Lib/hashlib.py.hashlib-fips Python-2.7.2/Lib/hashlib.py
--- Python-2.7.2/Lib/hashlib.py.hashlib-fips 2011-06-11 11:46:24.000000000 -0400
+++ Python-2.7.2/Lib/hashlib.py 2011-09-14 00:21:26.194252001 -0400
@@ -6,9 +6,12 @@
__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.
sha384 and sha512 will be slow on 32 bit platforms.
+If the underlying implementation supports "FIPS mode", and this is enabled, it
+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
+is not secure for uses such as authentication, system integrity checking, or
+digital signatures. If you need to use such a hash for non-security purposes
+(such as indexing into 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.
+Our implementation of hashlib uses OpenSSL.
+
+OpenSSL has a "FIPS mode", which, if enabled, 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 is not secure for uses such as
+authentication, system integrity checking, or digital signatures.
+
+If you need to use such a hash for non-security purposes (such as indexing into
+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:
- 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
@@ -62,6 +72,18 @@ algorithms_available = set(__always_supported)
__all__ = __always_supported + ('new', 'algorithms_guaranteed',
'algorithms_available', 'pbkdf2_hmac')
+import functools
+def __ignore_usedforsecurity(func):
+ """Used for sha3_* functions. Until OpenSSL implements them, we want
+ to use them from Python _sha3 module, but we want them to accept
+ usedforsecurity argument too."""
+ # TODO: remove this function when OpenSSL implements sha3
+ @functools.wraps(func)
+ def inner(*args, **kwargs):
+ if 'usedforsecurity' in kwargs:
+ kwargs.pop('usedforsecurity')
+ return func(*args, **kwargs)
+ return inner
__builtin_constructor_cache = {}
@@ -100,31 +122,39 @@ def __get_openssl_constructor(name):
@@ -63,74 +80,39 @@ algorithms = __always_supported
__all__ = __always_supported + ('new', 'algorithms')
-def __get_builtin_constructor(name):
- try:
- if name in ('SHA1', 'sha1'):
- import _sha
- return _sha.new
- elif name in ('MD5', 'md5'):
- import _md5
- return _md5.new
- elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'):
- import _sha256
- bs = name[3:]
- if bs == '256':
- return _sha256.sha256
- elif bs == '224':
- return _sha256.sha224
- 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)
# Allow the C module to raise ValueError. The function will be
# defined but the hash not actually available thanks to OpenSSL.
- f()
+ #
+ # We pass "usedforsecurity=False" to disable FIPS-based restrictions:
+ # at this stage we're merely seeing if the function is callable,
+ # rather than using it for actual work.
@ -50,76 +84,61 @@ index 316cece..b7ad879 100644 @@ -50,76 +84,61 @@ index 316cece..b7ad879 100644
# Use the C function directly (very fast)
return f
except (AttributeError, ValueError):
+ # TODO: We want to just raise here when OpenSSL implements sha3
+ # because we want to make sure that Fedora uses everything from OpenSSL
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)
- return __get_builtin_constructor(name)
+ raise
-def __hash_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 __hash_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).
+
-
-def __py_new(name, string=''):
- """new(name, string='') - Return a new hashing object using the named algorithm;
- optionally initialized with a string.
- """
- 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
+ a FIPS environment
"""
try:
- return _hashlib.new(name, data)
+ return _hashlib.new(name, data, usedforsecurity)
- return _hashlib.new(name, string)
+ return _hashlib.new(name, string, usedforsecurity)
except ValueError:
- # If the _hashlib module (OpenSSL) doesn't support the named
- # hash, try using our builtin implementations.
- # This allows for SHA224/256 and SHA384/512 support even though
- # the OpenSSL library prior to 0.9.8 doesn't provide them.
+ # TODO: We want to just raise here when OpenSSL implements sha3
+ # because we want to make sure that Fedora uses everything from OpenSSL
return __get_builtin_constructor(name)(data)
@@ -207,7 +237,10 @@ for __func_name in __always_supported:
- return __get_builtin_constructor(name)(string)
-
+ raise
try:
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
# version not supporting that algorithm.
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:
@@ -143,4 +125,4 @@ for __func_name in __always_supported:
# Cleanup locals()
del __always_supported, __func_name, __get_hash
del __py_new, __hash_new, __get_openssl_constructor
+del __ignore_usedforsecurity
\ No newline at end of file
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index c9b113e..60e2392 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -24,7 +24,22 @@ from test.support import _4G, bigmemtest, import_fresh_module
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'])
+
-del __py_new, __hash_new, __get_openssl_constructor
+del __hash_new, __get_openssl_constructor
diff -up Python-2.7.2/Lib/test/test_hashlib.py.hashlib-fips Python-2.7.2/Lib/test/test_hashlib.py
--- Python-2.7.2/Lib/test/test_hashlib.py.hashlib-fips 2011-06-11 11:46:25.000000000 -0400
+++ Python-2.7.2/Lib/test/test_hashlib.py 2011-09-14 01:08:55.525254195 -0400
@@ -32,6 +32,19 @@ def hexstr(s):
r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
return r
+def openssl_enforces_fips():
+ # Use the "openssl" command (if present) to try to determine if the local
+ # OpenSSL is configured to enforce FIPS
@ -134,80 +153,122 @@ index c9b113e..60e2392 100644 @@ -134,80 +153,122 @@ index c9b113e..60e2392 100644
+ return b'unknown cipher' in stderr
+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):
supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
@@ -63,11 +88,11 @@ class HashLibTestCase(unittest.TestCase):
# For each algorithm, test the direct constructor and the use
@@ -61,10 +74,10 @@ class HashLibTestCase(unittest.TestCase)
# of hashlib.new given the algorithm name.
for algorithm, constructors in self.constructors_to_test.items():
- constructors.add(getattr(hashlib, algorithm))
+ constructors.add(suppress_fips(getattr(hashlib, algorithm)))
def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm):
constructors.add(getattr(hashlib, 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:
- return hashlib.new(_alg)
- return hashlib.new(_alg, data)
+ return suppress_fips(hashlib.new)(_alg)
+ return suppress_fips(hashlib.new)(_alg, data)
+ return hashlib.new(_alg, usedforsecurity=usedforsecurity)
+ return hashlib.new(_alg, data, usedforsecurity=usedforsecurity)
constructors.add(_test_algorithm_via_hashlib_new)
_hashlib = self._conditional_import_module('_hashlib')
@@ -79,27 +104,12 @@ class HashLibTestCase(unittest.TestCase):
for algorithm, constructors in self.constructors_to_test.items():
constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
@@ -78,28 +91,13 @@ class HashLibTestCase(unittest.TestCase)
if 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)
constructors.add(constructor)
- _md5 = self._conditional_import_module('_md5')
- if _md5:
- add_builtin_constructor('md5')
- _sha1 = self._conditional_import_module('_sha1')
- if _sha1:
- add_builtin_constructor('sha1')
- self.constructors_to_test['md5'].add(_md5.new)
- _sha = self._conditional_import_module('_sha')
- if _sha:
- self.constructors_to_test['sha1'].add(_sha.new)
- _sha256 = self._conditional_import_module('_sha256')
- if _sha256:
- add_builtin_constructor('sha224')
- add_builtin_constructor('sha256')
- self.constructors_to_test['sha224'].add(_sha256.sha224)
- self.constructors_to_test['sha256'].add(_sha256.sha256)
- _sha512 = self._conditional_import_module('_sha512')
- if _sha512:
- add_builtin_constructor('sha384')
- add_builtin_constructor('sha512')
- self.constructors_to_test['sha384'].add(_sha512.sha384)
- self.constructors_to_test['sha512'].add(_sha512.sha512)
-
super(HashLibTestCase, self).__init__(*args, **kwargs)
@property
@@ -148,9 +158,6 @@ class HashLibTestCase(unittest.TestCase):
else:
del sys.modules['_md5']
self.assertRaises(TypeError, get_builtin_constructor, 3)
- constructor = get_builtin_constructor('md5')
- self.assertIs(constructor, _md5.md5)
- self.assertEqual(sorted(builtin_constructor_cache), ['MD5', 'md5'])
def test_hash_array(self):
a = array.array("b", range(10))
constructors = self.constructors_to_test.itervalues()
for cons in itertools.chain.from_iterable(constructors):
- c = cons(a)
+ c = cons(a, usedforsecurity=False)
c.hexdigest()
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):
for cons in self.hash_constructors:
@@ -433,6 +440,64 @@ class HashLibTestCase(unittest.TestCase):
for name in self.supported_hash_names:
- 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())
@ -227,74 +288,70 @@ index c9b113e..60e2392 100644 @@ -227,74 +288,70 @@ index c9b113e..60e2392 100644
+ m = hashlib.new('md5', b'abc\n', usedforsecurity=False)
+ 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,
+ 'FIPS enforcement required for this test.')
+ def test_hashlib_fips_mode(self):
+ # Ensure that we raise a ValueError on vanilla attempts to use MD5
+ # in hashlib in a FIPS-enforced setting:
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'):
+ m = hashlib.md5()
+
+ if not self._conditional_import_module('_md5'):
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'):
+ m = hashlib.new('md5')
+ self.assertRaisesUnknownCipher(hashlib.md5)
+ self.assertRaisesUnknownCipher(hashlib.new, 'md5')
+
+ @unittest.skipUnless(OPENSSL_ENFORCES_FIPS,
+ 'FIPS enforcement required for this test.')
+ def test_hashopenssl_fips_mode(self):
+ # Verify the _hashlib module's handling of md5:
+ _hashlib = self._conditional_import_module('_hashlib')
+ if _hashlib:
+ assert hasattr(_hashlib, 'openssl_md5')
+ import _hashlib
+
+ assert hasattr(_hashlib, 'openssl_md5')
+
+ # Ensure that _hashlib raises a ValueError on vanilla attempts to
+ # use MD5 in a FIPS-enforced setting:
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'):
+ m = _hashlib.openssl_md5()
+ with self.assertRaisesRegexp(ValueError, '.*unknown cipher'):
+ m = _hashlib.new('md5')
+ # Ensure that _hashlib raises a ValueError on vanilla attempts to
+ # use MD5 in a FIPS-enforced setting:
+ self.assertRaisesUnknownCipher(_hashlib.openssl_md5)
+ self.assertRaisesUnknownCipher(_hashlib.new, 'md5')
+
+ # Ensure that in such a setting we can whitelist a callsite with
+ # usedforsecurity=False and have it succeed:
+ m = _hashlib.openssl_md5(usedforsecurity=False)
+ m.update(b'abc\n')
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+ # Ensure that in such a setting we can whitelist a callsite with
+ # usedforsecurity=False and have it succeed:
+ m = _hashlib.openssl_md5(usedforsecurity=False)
+ m.update('abc\n')
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
+ m = _hashlib.new('md5', usedforsecurity=False)
+ m.update(b'abc\n')
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
+ m = _hashlib.openssl_md5(b'abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+ m = _hashlib.new('md5', usedforsecurity=False)
+ m.update('abc\n')
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
+ m = _hashlib.new('md5', b'abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
class KDFTests(unittest.TestCase):
@@ -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])
-
+ @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 @@
+ m = _hashlib.openssl_md5('abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
+ m = _hashlib.new('md5', 'abc\n', usedforsecurity=False)
+ self.assertEquals(m.hexdigest(), "0bee89b07a248e27c83fc3d5951213c1")
+
+
+
def test_main():
test_support.run_unittest(HashLibTestCase)
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 */
+#include <openssl/ssl.h>
+#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
/* We use the object interface to discover what hashes OpenSSL supports. */
@@ -45,11 +47,19 @@ typedef struct {
#define MUNCH_SIZE INT_MAX
@@ -65,11 +67,19 @@ typedef struct {
static PyTypeObject EVPtype;
@ -318,7 +375,7 @@ index 44765ac..b8cf490 100644 @@ -318,7 +375,7 @@ index 44765ac..b8cf490 100644
DEFINE_CONSTS_FOR_NEW(md5)
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 @@ -349,7 +406,7 @@ index 44765ac..b8cf490 100644
+ errstr = ERR_error_string(ERR_peek_last_error(), NULL);
+ ERR_clear_error();
+
+ return PyUnicode_FromString(errstr); /* Can be NULL */
+ return PyString_FromString(errstr); /* Can be NULL */
+}
+
+static void
@ -367,28 +424,27 @@ index 44765ac..b8cf490 100644 @@ -367,28 +424,27 @@ index 44765ac..b8cf490 100644
/* Internal methods for a hash object */
static void
@@ -259,15 +311,16 @@ EVP_repr(EVPobject *self)
@@ -313,14 +365,15 @@ EVP_repr(PyObject *self)
static int
EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"name", "string", NULL};
+ static char *kwlist[] = {"name", "string", "usedforsecurity", NULL};
PyObject *name_obj = NULL;
PyObject *data_obj = NULL;
+ int usedforsecurity = 1;
Py_buffer view;
Py_buffer view = { 0 };
char *nameStr;
const EVP_MD *digest;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:HASH", kwlist,
- &name_obj, &data_obj)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oi:HASH", kwlist,
+ &name_obj, &data_obj, &usedforsecurity)) {
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*:HASH", kwlist,
- &name_obj, &view)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s*i:HASH", kwlist,
+ &name_obj, &view, &usedforsecurity)) {
return -1;
}
@@ -288,7 +341,12 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
PyBuffer_Release(&view);
@@ -336,7 +389,12 @@ EVP_tp_init(EVPobject *self, PyObject *a
PyBuffer_Release(&view);
return -1;
}
- EVP_DigestInit(&self->ctx, digest);
@ -401,7 +457,7 @@ index 44765ac..b8cf490 100644 @@ -401,7 +457,7 @@ index 44765ac..b8cf490 100644
self->name = name_obj;
Py_INCREF(self->name);
@@ -372,7 +430,8 @@ static PyTypeObject EVPtype = {
@@ -420,7 +478,8 @@ static PyTypeObject EVPtype = {
static PyObject *
EVPnew(PyObject *name_obj,
const EVP_MD *digest, const EVP_MD_CTX *initial_ctx,
@ -411,7 +467,7 @@ index 44765ac..b8cf490 100644 @@ -411,7 +467,7 @@ index 44765ac..b8cf490 100644
{
EVPobject *self;
@@ -387,7 +446,12 @@ EVPnew(PyObject *name_obj,
@@ -435,7 +494,12 @@ EVPnew(PyObject *name_obj,
if (initial_ctx) {
EVP_MD_CTX_copy(&self->ctx, initial_ctx);
} else {
@ -425,7 +481,7 @@ index 44765ac..b8cf490 100644 @@ -425,7 +481,7 @@ index 44765ac..b8cf490 100644
}
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\
automatically hashed.\n\
\n\
@ -445,32 +501,29 @@ index 44765ac..b8cf490 100644 @@ -445,32 +501,29 @@ index 44765ac..b8cf490 100644
- static char *kwlist[] = {"name", "string", NULL};
+ static char *kwlist[] = {"name", "string", "usedforsecurity", NULL};
PyObject *name_obj = NULL;
PyObject *data_obj = NULL;
+ int usedforsecurity = 1;
Py_buffer view = { 0 };
PyObject *ret_obj;
char *name;
const EVP_MD *digest;
+ int usedforsecurity = 1;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|O:new", kwlist,
- &name_obj, &data_obj)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|Oi:new", kwlist,
+ &name_obj, &data_obj, &usedforsecurity)) {
- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*:new", kwlist,
- &name_obj, &view)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s*i:new", kwlist,
+ &name_obj, &view, &usedforsecurity)) {
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);
- ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, view.len);
+ ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf, view.len,
+ usedforsecurity);
if (data_obj)
PyBuffer_Release(&view);
@@ -722,57 +795,114 @@ generate_hash_name_list(void)
ret_obj = EVPnew(name_obj, digest, NULL, (unsigned char*)view.buf,
- view.len);
+ view.len, usedforsecurity);
PyBuffer_Release(&view);
return ret_obj;
}
/*
- * This macro generates constructor function definitions for specific
@ -486,32 +539,25 @@ index 44765ac..b8cf490 100644 @@ -486,32 +539,25 @@ index 44765ac..b8cf490 100644
#define GEN_CONSTRUCTOR(NAME) \
static PyObject * \
- 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 }; \
- PyObject *ret_obj; \
- \
- if (!PyArg_ParseTuple(args, "|O:" #NAME , &data_obj)) { \
- if (!PyArg_ParseTuple(args, "|s*:" #NAME , &view)) { \
- return NULL; \
- } \
- \
- if (data_obj) \
- GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view); \
- \
- ret_obj = EVPnew( \
- CONST_ ## NAME ## _name_obj, \
- NULL, \
- CONST_new_ ## NAME ## _ctx_p, \
- (unsigned char*)view.buf, \
- view.len); \
- \
- if (data_obj) \
- PyBuffer_Release(&view); \
- (unsigned char*)view.buf, view.len); \
- PyBuffer_Release(&view); \
- return ret_obj; \
+ return implement_specific_EVP_new(self, args, kwdict, \
+ "|Oi:" #NAME, \
+ &cached_info_ ## NAME ); \
+ return implement_specific_EVP_new(self, args, kwdict, \
+ "|s*i:" #NAME, \
+ &cached_info_ ## NAME ); \
}
+static PyObject *
@ -520,7 +566,6 @@ index 44765ac..b8cf490 100644 @@ -520,7 +566,6 @@ index 44765ac..b8cf490 100644
+ EVPCachedInfo *cached_info)
+{
+ static char *kwlist[] = {"string", "usedforsecurity", NULL};
+ PyObject *data_obj = NULL;
+ Py_buffer view = { 0 };
+ int usedforsecurity = 1;
+ int idx;
@ -529,13 +574,10 @@ index 44765ac..b8cf490 100644 @@ -529,13 +574,10 @@ index 44765ac..b8cf490 100644
+ assert(cached_info);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, format, kwlist,
+ &data_obj, &usedforsecurity)) {
+ &view, &usedforsecurity)) {
+ return NULL;
+ }
+
+ if (data_obj)
+ GET_BUFFER_VIEW_OR_ERROUT(data_obj, &view);
+
+ idx = usedforsecurity ? 1 : 0;
+
+ /*
@ -558,10 +600,9 @@ index 44765ac..b8cf490 100644 @@ -558,10 +600,9 @@ index 44765ac..b8cf490 100644
+ } else {
+ PyErr_SetString(PyExc_ValueError, "Error initializing hash");
+ }
+ }
+
+ if (data_obj)
+ PyBuffer_Release(&view);
+ }
+
+ PyBuffer_Release(&view);
+
+ return ret_obj;
+}
@ -570,7 +611,7 @@ index 44765ac..b8cf490 100644 @@ -570,7 +611,7 @@ index 44765ac..b8cf490 100644
#define CONSTRUCTOR_METH_DEF(NAME) \
- {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \
+ {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, \
+ METH_VARARGS|METH_KEYWORDS, \
+ METH_VARARGS |METH_KEYWORDS, \
PyDoc_STR("Returns a " #NAME \
" hash object; optionally initialized with a string") \
}
@ -579,7 +620,7 @@ index 44765ac..b8cf490 100644 @@ -579,7 +620,7 @@ index 44765ac..b8cf490 100644
- constructor constants if they haven't been initialized already. */
-#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \
- 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)) { \
- CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \
- EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \
@ -591,17 +632,18 @@ index 44765ac..b8cf490 100644 @@ -591,17 +632,18 @@ index 44765ac..b8cf490 100644
+ Try to initialize a context for each hash twice, once with
+ 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)
+*/
+#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \
+ init_constructor_constant(&cached_info_ ## NAME, #NAME); \
} while (0);
+static void
+init_constructor_constant(EVPCachedInfo *cached_info, const char *name)
+{
+ assert(cached_info);
+ cached_info->name_obj = PyUnicode_FromString(name);
+ cached_info->name_obj = PyString_FromString(name);
+ if (EVP_get_digestbyname(name)) {
+ int i;
+ for (i=0; i<2; i++) {
@ -612,29 +654,76 @@ index 44765ac..b8cf490 100644 @@ -612,29 +654,76 @@ index 44765ac..b8cf490 100644
+ cached_info->ctx_ptrs[i] = &cached_info->ctxs[i];
+ } else {
+ /* Failure: */
+ cached_info->ctx_ptrs[i] = NULL;
+ cached_info->error_msgs[i] = error_msg_for_last_error();
+ cached_info->ctx_ptrs[i] = NULL;
+ cached_info->error_msgs[i] = error_msg_for_last_error();
+ }
+ }
+ }
+}
+
GEN_CONSTRUCTOR(md5)
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_library_init();
OpenSSL_add_all_digests();
- /* TODO build EVP_functions openssl_* entries dynamically based
- * on what hashes are supported rather than listing many
- * but having some be unsupported. Only init appropriate
- * constants. */
+ OpenSSL_add_all_digests();
-
Py_TYPE(&EVPtype) = &PyType_Type;
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 @@ @@ -1,7 +1,7 @@
diff -up Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 Python-3.2.3/Lib/ctypes/__init__.py
--- Python-3.2.3/Lib/ctypes/__init__.py.rhbz814391 2012-04-20 15:12:49.017867692 -0400
+++ Python-3.2.3/Lib/ctypes/__init__.py 2012-04-20 15:15:09.501111408 -0400
@@ -275,11 +275,6 @@ def _reset_cache():
diff -up Python-2.7.3/Lib/ctypes/__init__.py.rhbz814391 Python-2.7.3/Lib/ctypes/__init__.py
--- Python-2.7.3/Lib/ctypes/__init__.py.rhbz814391 2012-04-20 14:51:19.390990244 -0400
+++ Python-2.7.3/Lib/ctypes/__init__.py 2012-04-20 14:51:45.141668316 -0400
@@ -272,11 +272,6 @@ def _reset_cache():
# _SimpleCData.c_char_p_from_param
POINTER(c_char).from_param = c_char_p.from_param
_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/ @@ -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?
- CFUNCTYPE(c_int)(lambda: None)
def create_unicode_buffer(init, size=None):
"""create_unicode_buffer(aString) -> character array
try:
from _ctypes import set_conversion_mode

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

@ -1,68 +1,49 @@ @@ -1,68 +1,49 @@
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index e9fdb07..ea60e6e 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -1723,30 +1723,36 @@ class PosixUidGidTests(unittest.TestCase):
def test_setuid(self):
if os.getuid() != 0:
self.assertRaises(OSError, os.setuid, 0)
+ self.assertRaises(TypeError, os.setuid, 'not an int')
self.assertRaises(OverflowError, os.setuid, 1<<32)
diff -up Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows Python-2.7.3/Lib/test/test_os.py
--- Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows 2012-04-09 19:07:32.000000000 -0400
+++ Python-2.7.3/Lib/test/test_os.py 2012-06-26 14:51:36.000817929 -0400
@@ -677,30 +677,36 @@ if sys.platform != 'win32':
def test_setuid(self):
if os.getuid() != 0:
self.assertRaises(os.error, os.setuid, 0)
+ self.assertRaises(TypeError, os.setuid, 'not an int')
self.assertRaises(OverflowError, os.setuid, 1<<32)
@unittest.skipUnless(hasattr(os, 'setgid'), 'test needs os.setgid()')
def test_setgid(self):
if os.getuid() != 0 and not HAVE_WHEEL_GROUP:
self.assertRaises(OSError, os.setgid, 0)
+ self.assertRaises(TypeError, os.setgid, 'not an int')
self.assertRaises(OverflowError, os.setgid, 1<<32)
if hasattr(os, 'setgid'):
def test_setgid(self):
if os.getuid() != 0:
self.assertRaises(os.error, os.setgid, 0)
+ self.assertRaises(TypeError, os.setgid, 'not an int')
self.assertRaises(OverflowError, os.setgid, 1<<32)
@unittest.skipUnless(hasattr(os, 'seteuid'), 'test needs os.seteuid()')
def test_seteuid(self):
if os.getuid() != 0:
self.assertRaises(OSError, os.seteuid, 0)
+ self.assertRaises(TypeError, os.seteuid, 'not an int')
self.assertRaises(OverflowError, os.seteuid, 1<<32)
if hasattr(os, 'seteuid'):
def test_seteuid(self):
if os.getuid() != 0:
self.assertRaises(os.error, os.seteuid, 0)
+ self.assertRaises(TypeError, os.seteuid, 'not an int')
self.assertRaises(OverflowError, os.seteuid, 1<<32)
@unittest.skipUnless(hasattr(os, 'setegid'), 'test needs os.setegid()')
def test_setegid(self):
if os.getuid() != 0 and not HAVE_WHEEL_GROUP:
self.assertRaises(OSError, os.setegid, 0)
+ self.assertRaises(TypeError, os.setegid, 'not an int')
self.assertRaises(OverflowError, os.setegid, 1<<32)
if hasattr(os, 'setegid'):
def test_setegid(self):
if os.getuid() != 0:
self.assertRaises(os.error, os.setegid, 0)
+ self.assertRaises(TypeError, os.setegid, 'not an int')
self.assertRaises(OverflowError, os.setegid, 1<<32)
@unittest.skipUnless(hasattr(os, 'setreuid'), 'test needs os.setreuid()')
def test_setreuid(self):
if os.getuid() != 0:
self.assertRaises(OSError, os.setreuid, 0, 0)
+ self.assertRaises(TypeError, os.setreuid, 'not an int', 0)
+ self.assertRaises(TypeError, os.setreuid, 0, 'not an int')
self.assertRaises(OverflowError, os.setreuid, 1<<32, 0)
self.assertRaises(OverflowError, os.setreuid, 0, 1<<32)
if hasattr(os, 'setreuid'):
def test_setreuid(self):
if os.getuid() != 0:
self.assertRaises(os.error, os.setreuid, 0, 0)
+ self.assertRaises(TypeError, os.setreuid, 'not an int', 0)
+ self.assertRaises(TypeError, os.setreuid, 0, 'not an int')
self.assertRaises(OverflowError, os.setreuid, 1<<32, 0)
self.assertRaises(OverflowError, os.setreuid, 0, 1<<32)
@@ -1762,6 +1768,8 @@ class PosixUidGidTests(unittest.TestCase):
def test_setregid(self):
if os.getuid() != 0 and not HAVE_WHEEL_GROUP:
self.assertRaises(OSError, os.setregid, 0, 0)
+ self.assertRaises(TypeError, os.setregid, 'not an int', 0)
+ self.assertRaises(TypeError, os.setregid, 0, 'not an int')
self.assertRaises(OverflowError, os.setregid, 1<<32, 0)
self.assertRaises(OverflowError, os.setregid, 0, 1<<32)
@@ -715,6 +721,8 @@ if sys.platform != 'win32':
def test_setregid(self):
if os.getuid() != 0:
self.assertRaises(os.error, os.setregid, 0, 0)
+ self.assertRaises(TypeError, os.setregid, 'not an int', 0)
+ self.assertRaises(TypeError, os.setregid, 0, 'not an int')
self.assertRaises(OverflowError, os.setregid, 1<<32, 0)
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 @@ @@ -1,92 +1,33 @@
diff --git a/Include/object.h b/Include/object.h
index 0c88603..e3413e8 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -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 @@
diff -up Python-2.7.3/Lib/test/test_gc.py.gc-assertions Python-2.7.3/Lib/test/test_gc.py
--- Python-2.7.3/Lib/test/test_gc.py.gc-assertions 2013-02-20 16:28:20.890536607 -0500
+++ Python-2.7.3/Lib/test/test_gc.py 2013-02-20 16:39:52.720489297 -0500
@@ -1,6 +1,7 @@
import unittest
from test.support import (verbose, refcount_test, run_unittest,
strip_python_stderr, cpython_only, start_threads,
- temp_dir, requires_type_collecting)
+ temp_dir, import_module, requires_type_collecting)
from test.support.script_helper import assert_python_ok, make_script
-from test.test_support import verbose, run_unittest
+from test.test_support import verbose, run_unittest, import_module
import sys
+import sysconfig
import time
import gc
import weakref
@@ -50,6 +51,8 @@ class GC_Detector(object):
# gc collects it.
@@ -32,6 +33,8 @@ class GC_Detector(object):
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
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)
### Tests
###############################################################################
@@ -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')
+ def test_refcount_errors(self):
+ self.preclean()
+ # Verify the "handling" of objects with broken refcounts
+
+ import_module("ctypes") #skip if not supported
+
+ import subprocess
@ -112,59 +53,131 @@ index e727499..6efcafb 100644 @@ -112,59 +53,131 @@ index e727499..6efcafb 100644
+ p.stdout.close()
+ p.stderr.close()
+ # Verify that stderr has a useful error message:
+ self.assertRegex(stderr,
+ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "\(\(gc\)->gc.gc_refs >> \(1\)\) != 0" failed.')
+ self.assertRegex(stderr,
+ self.assertRegexpMatches(stderr,
+ b'Modules/gcmodule.c:[0-9]+: visit_decref: Assertion "gc->gc.gc_refs != 0" failed.')
+ self.assertRegexpMatches(stderr,
+ b'refcount was too small')
+ self.assertRegex(stderr,
+ self.assertRegexpMatches(stderr,
+ b'object : \[\]')
+ self.assertRegex(stderr,
+ self.assertRegexpMatches(stderr,
+ b'type : list')
+ self.assertRegex(stderr,
+ self.assertRegexpMatches(stderr,
+ b'refcount: 1')
+ self.assertRegex(stderr,
+ self.assertRegexpMatches(stderr,
+ b'address : 0x[0-9a-f]+')
+
+
class GCTogglingTests(unittest.TestCase):
def setUp(self):
gc.enable()
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 0c6f444..87edd5a 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -341,7 +341,8 @@ update_refs(PyGC_Head *containers)
diff -up Python-2.7.3/Modules/gcmodule.c.gc-assertions Python-2.7.3/Modules/gcmodule.c
--- Python-2.7.3/Modules/gcmodule.c.gc-assertions 2012-04-09 19:07:34.000000000 -0400
+++ Python-2.7.3/Modules/gcmodule.c 2013-02-20 16:28:21.029536600 -0500
@@ -21,6 +21,73 @@
#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;
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),
+ _PyGCHead_REFS(gc) == GC_REACHABLE);
_PyGCHead_SET_REFS(gc, Py_REFCNT(FROM_GC(gc)));
+ gc->gc.gc_refs == GC_REACHABLE);
gc->gc.gc_refs = Py_REFCNT(FROM_GC(gc));
/* Python's cyclic gc should never see an incoming refcount
* 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
* check instead of an assert?
*/
- assert(_PyGCHead_REFS(gc) != 0);
- assert(gc->gc.gc_refs != 0);
+ 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
* 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),
+ _PyGCHead_REFS(gc) != 0,
+ "refcount was too small"); /* else refcount was too small */
if (_PyGCHead_REFS(gc) > 0)
_PyGCHead_DECREF(gc);
+ gc->gc.gc_refs != 0,
+ "refcount was too small");
if (gc->gc.gc_refs > 0)
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.
*/
else {
@ -178,25 +191,26 @@ index 0c6f444..87edd5a 100644 @@ -178,25 +191,26 @@ index 0c6f444..87edd5a 100644
}
}
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);
traverseproc traverse = Py_TYPE(op)->tp_traverse;
- assert(_PyGCHead_REFS(gc) > 0);
+ PyObject_ASSERT(op, _PyGCHead_REFS(gc) > 0);
_PyGCHead_SET_REFS(gc, GC_REACHABLE);
- assert(gc->gc.gc_refs > 0);
+ PyObject_ASSERT(op, gc->gc.gc_refs > 0);
gc->gc.gc_refs = GC_REACHABLE;
(void) traverse(op,
(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) {
PyObject *op = FROM_GC(gc);
- assert(IS_TENTATIVELY_UNREACHABLE(op));
+ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
+
next = gc->gc.gc_next;
if (has_legacy_finalizer(op)) {
@@ -619,7 +624,7 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
if (has_finalizer(op)) {
@@ -570,7 +643,7 @@ handle_weakrefs(PyGC_Head *unreachable,
PyWeakReference **wrlist;
op = FROM_GC(gc);
@ -205,7 +219,7 @@ index 0c6f444..87edd5a 100644 @@ -205,7 +219,7 @@ index 0c6f444..87edd5a 100644
next = gc->gc.gc_next;
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
* changes *wrlist.
*/
@ -217,7 +231,7 @@ index 0c6f444..87edd5a 100644 @@ -217,7 +231,7 @@ index 0c6f444..87edd5a 100644
if (wr->wr_callback == NULL)
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))
continue;
@ -226,7 +240,7 @@ index 0c6f444..87edd5a 100644 @@ -226,7 +240,7 @@ index 0c6f444..87edd5a 100644
/* Create a new reference so that wr can't go away
* 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. */
wrasgc = AS_GC(wr);
@ -236,7 +250,7 @@ index 0c6f444..87edd5a 100644 @@ -236,7 +250,7 @@ index 0c6f444..87edd5a 100644
next isn't, so they can't
be the same */
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;
op = FROM_GC(gc);
@ -251,60 +265,12 @@ index 0c6f444..87edd5a 100644 @@ -251,60 +265,12 @@ index 0c6f444..87edd5a 100644
/* copy-paste of weakrefobject.c's handle_callback() */
temp = PyObject_CallFunctionObjArgs(callback, wr, NULL);
@@ -822,12 +828,14 @@ check_garbage(PyGC_Head *collectable)
for (gc = collectable->gc.gc_next; gc != collectable;
gc = gc->gc.gc_next) {
_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)
}
}
@@ -759,7 +833,7 @@ delete_garbage(PyGC_Head *collectable, P
PyGC_Head *gc = collectable->gc.gc_next;
PyObject *op = FROM_GC(gc);
+PyAPI_FUNC(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();
+}
+
#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. */
- assert(IS_TENTATIVELY_UNREACHABLE(op));
+ PyObject_ASSERT(op, IS_TENTATIVELY_UNREACHABLE(op));
if (debug & DEBUG_SAVEALL) {
PyList_Append(garbage, op);
}

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

@ -1,13 +1,12 @@ @@ -1,13 +1,12 @@
diff --git a/config.sub b/config.sub
index 40ea5df..932128b 100755
--- a/config.sub
+++ b/config.sub
@@ -1045,7 +1045,7 @@ case $basic_machine in
diff -r de35eae9048a config.sub
--- a/config.sub Wed Apr 24 23:33:20 2013 +0200
+++ b/config.sub Thu Apr 25 08:51:00 2013 +0200
@@ -1008,7 +1008,7 @@
;;
ppc64) basic_machine=powerpc64-unknown
;;
- ppc64-*) 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

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

@ -0,0 +1,353 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -0,0 +1 @@
x /tmp/pymp-*

32
SOURCES/pythondeps.sh

@ -0,0 +1,32 @@ @@ -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