Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fa448f4

Browse filesBrowse files
authored
Merge branch '3.8' into backport-77e0919-3.8
2 parents 0789a5c + b4368b5 commit fa448f4
Copy full SHA for fa448f4

File tree

Expand file treeCollapse file tree

10 files changed

+412
-14
lines changed
Filter options
Expand file treeCollapse file tree

10 files changed

+412
-14
lines changed

‎.github/workflows/build.yml

Copy file name to clipboardExpand all lines: .github/workflows/build.yml
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ jobs:
158158
needs: check_source
159159
if: needs.check_source.outputs.run_tests == 'true'
160160
env:
161-
OPENSSL_VER: 1.1.1u
161+
OPENSSL_VER: 1.1.1v
162162
steps:
163163
- uses: actions/checkout@v2
164164
- name: Install Dependencies
@@ -199,7 +199,7 @@ jobs:
199199
strategy:
200200
fail-fast: false
201201
matrix:
202-
openssl_ver: [1.0.2u, 1.1.1u, 3.0.9, 3.1.1]
202+
openssl_ver: [1.0.2u, 1.1.1v, 3.0.10, 3.1.2]
203203
env:
204204
OPENSSL_VER: ${{ matrix.openssl_ver }}
205205
MULTISSL_DIR: ${{ github.workspace }}/multissl

‎Doc/library/tarfile.rst

Copy file name to clipboardExpand all lines: Doc/library/tarfile.rst
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,11 @@ A ``TarInfo`` object has the following public data attributes:
725725
Name of the target file name, which is only present in :class:`TarInfo` objects
726726
of type :const:`LNKTYPE` and :const:`SYMTYPE`.
727727

728+
For symbolic links (``SYMTYPE``), the *linkname* is relative to the directory
729+
that contains the link.
730+
For hard links (``LNKTYPE``), the *linkname* is relative to the root of
731+
the archive.
732+
728733

729734
.. attribute:: TarInfo.uid
730735
:type: int

‎Lib/ssl.py

Copy file name to clipboardExpand all lines: Lib/ssl.py
+30-1Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True,
10021002
)
10031003
self = cls.__new__(cls, **kwargs)
10041004
super(SSLSocket, self).__init__(**kwargs)
1005-
self.settimeout(sock.gettimeout())
1005+
sock_timeout = sock.gettimeout()
10061006
sock.detach()
10071007

10081008
self._context = context
@@ -1021,9 +1021,38 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True,
10211021
if e.errno != errno.ENOTCONN:
10221022
raise
10231023
connected = False
1024+
blocking = self.getblocking()
1025+
self.setblocking(False)
1026+
try:
1027+
# We are not connected so this is not supposed to block, but
1028+
# testing revealed otherwise on macOS and Windows so we do
1029+
# the non-blocking dance regardless. Our raise when any data
1030+
# is found means consuming the data is harmless.
1031+
notconn_pre_handshake_data = self.recv(1)
1032+
except OSError as e:
1033+
# EINVAL occurs for recv(1) on non-connected on unix sockets.
1034+
if e.errno not in (errno.ENOTCONN, errno.EINVAL):
1035+
raise
1036+
notconn_pre_handshake_data = b''
1037+
self.setblocking(blocking)
1038+
if notconn_pre_handshake_data:
1039+
# This prevents pending data sent to the socket before it was
1040+
# closed from escaping to the caller who could otherwise
1041+
# presume it came through a successful TLS connection.
1042+
reason = "Closed before TLS handshake with data in recv buffer."
1043+
notconn_pre_handshake_data_error = SSLError(e.errno, reason)
1044+
# Add the SSLError attributes that _ssl.c always adds.
1045+
notconn_pre_handshake_data_error.reason = reason
1046+
notconn_pre_handshake_data_error.library = None
1047+
try:
1048+
self.close()
1049+
except OSError:
1050+
pass
1051+
raise notconn_pre_handshake_data_error
10241052
else:
10251053
connected = True
10261054

1055+
self.settimeout(sock_timeout) # Must come after setblocking() calls.
10271056
self._connected = connected
10281057
if connected:
10291058
# create the SSL object

‎Lib/tarfile.py

Copy file name to clipboardExpand all lines: Lib/tarfile.py
+9-2Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ def __init__(self, tarinfo):
740740
class AbsoluteLinkError(FilterError):
741741
def __init__(self, tarinfo):
742742
self.tarinfo = tarinfo
743-
super().__init__(f'{tarinfo.name!r} is a symlink to an absolute path')
743+
super().__init__(f'{tarinfo.name!r} is a link to an absolute path')
744744

745745
class LinkOutsideDestinationError(FilterError):
746746
def __init__(self, tarinfo, path):
@@ -800,7 +800,14 @@ def _get_filtered_attrs(member, dest_path, for_data=True):
800800
if member.islnk() or member.issym():
801801
if os.path.isabs(member.linkname):
802802
raise AbsoluteLinkError(member)
803-
target_path = os.path.realpath(os.path.join(dest_path, member.linkname))
803+
if member.issym():
804+
target_path = os.path.join(dest_path,
805+
os.path.dirname(name),
806+
member.linkname)
807+
else:
808+
target_path = os.path.join(dest_path,
809+
member.linkname)
810+
target_path = os.path.realpath(target_path)
804811
if os.path.commonpath([target_path, dest_path]) != dest_path:
805812
raise LinkOutsideDestinationError(member, target_path)
806813
return new_attrs

‎Lib/test/test_ssl.py

Copy file name to clipboardExpand all lines: Lib/test/test_ssl.py
+215Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
import unittest
55
import unittest.mock
66
from test import support
7+
import re
78
import socket
89
import select
10+
import struct
911
import time
1012
import datetime
1113
import gc
14+
import http.client
1215
import os
1316
import errno
1417
import pprint
@@ -4815,6 +4818,218 @@ def sni_cb(sock, servername, ctx):
48154818
s.connect((HOST, server.port))
48164819

48174820

4821+
def set_socket_so_linger_on_with_zero_timeout(sock):
4822+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
4823+
4824+
4825+
class TestPreHandshakeClose(unittest.TestCase):
4826+
"""Verify behavior of close sockets with received data before to the handshake.
4827+
"""
4828+
4829+
class SingleConnectionTestServerThread(threading.Thread):
4830+
4831+
def __init__(self, *, name, call_after_accept):
4832+
self.call_after_accept = call_after_accept
4833+
self.received_data = b'' # set by .run()
4834+
self.wrap_error = None # set by .run()
4835+
self.listener = None # set by .start()
4836+
self.port = None # set by .start()
4837+
super().__init__(name=name)
4838+
4839+
def __enter__(self):
4840+
self.start()
4841+
return self
4842+
4843+
def __exit__(self, *args):
4844+
try:
4845+
if self.listener:
4846+
self.listener.close()
4847+
except OSError:
4848+
pass
4849+
self.join()
4850+
self.wrap_error = None # avoid dangling references
4851+
4852+
def start(self):
4853+
self.ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
4854+
self.ssl_ctx.verify_mode = ssl.CERT_REQUIRED
4855+
self.ssl_ctx.load_verify_locations(cafile=ONLYCERT)
4856+
self.ssl_ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY)
4857+
self.listener = socket.socket()
4858+
self.port = support.bind_port(self.listener)
4859+
self.listener.settimeout(2.0)
4860+
self.listener.listen(1)
4861+
super().start()
4862+
4863+
def run(self):
4864+
conn, address = self.listener.accept()
4865+
self.listener.close()
4866+
with conn:
4867+
if self.call_after_accept(conn):
4868+
return
4869+
try:
4870+
tls_socket = self.ssl_ctx.wrap_socket(conn, server_side=True)
4871+
except OSError as err: # ssl.SSLError inherits from OSError
4872+
self.wrap_error = err
4873+
else:
4874+
try:
4875+
self.received_data = tls_socket.recv(400)
4876+
except OSError:
4877+
pass # closed, protocol error, etc.
4878+
4879+
def non_linux_skip_if_other_okay_error(self, err):
4880+
if sys.platform == "linux":
4881+
return # Expect the full test setup to always work on Linux.
4882+
if (isinstance(err, ConnectionResetError) or
4883+
(isinstance(err, OSError) and err.errno == errno.EINVAL) or
4884+
re.search('wrong.version.number', getattr(err, "reason", ""), re.I)):
4885+
# On Windows the TCP RST leads to a ConnectionResetError
4886+
# (ECONNRESET) which Linux doesn't appear to surface to userspace.
4887+
# If wrap_socket() winds up on the "if connected:" path and doing
4888+
# the actual wrapping... we get an SSLError from OpenSSL. Typically
4889+
# WRONG_VERSION_NUMBER. While appropriate, neither is the scenario
4890+
# we're specifically trying to test. The way this test is written
4891+
# is known to work on Linux. We'll skip it anywhere else that it
4892+
# does not present as doing so.
4893+
self.skipTest(f"Could not recreate conditions on {sys.platform}:"
4894+
f" {err=}")
4895+
# If maintaining this conditional winds up being a problem.
4896+
# just turn this into an unconditional skip anything but Linux.
4897+
# The important thing is that our CI has the logic covered.
4898+
4899+
def test_preauth_data_to_tls_server(self):
4900+
server_accept_called = threading.Event()
4901+
ready_for_server_wrap_socket = threading.Event()
4902+
4903+
def call_after_accept(unused):
4904+
server_accept_called.set()
4905+
if not ready_for_server_wrap_socket.wait(2.0):
4906+
raise RuntimeError("wrap_socket event never set, test may fail.")
4907+
return False # Tell the server thread to continue.
4908+
4909+
server = self.SingleConnectionTestServerThread(
4910+
call_after_accept=call_after_accept,
4911+
name="preauth_data_to_tls_server")
4912+
server.__enter__() # starts it
4913+
self.addCleanup(server.__exit__) # ... & unittest.TestCase stops it.
4914+
4915+
with socket.socket() as client:
4916+
client.connect(server.listener.getsockname())
4917+
# This forces an immediate connection close via RST on .close().
4918+
set_socket_so_linger_on_with_zero_timeout(client)
4919+
client.setblocking(False)
4920+
4921+
server_accept_called.wait()
4922+
client.send(b"DELETE /data HTTP/1.0\r\n\r\n")
4923+
client.close() # RST
4924+
4925+
ready_for_server_wrap_socket.set()
4926+
server.join()
4927+
wrap_error = server.wrap_error
4928+
self.assertEqual(b"", server.received_data)
4929+
self.assertIsInstance(wrap_error, OSError) # All platforms.
4930+
self.non_linux_skip_if_other_okay_error(wrap_error)
4931+
self.assertIsInstance(wrap_error, ssl.SSLError)
4932+
self.assertIn("before TLS handshake with data", wrap_error.args[1])
4933+
self.assertIn("before TLS handshake with data", wrap_error.reason)
4934+
self.assertNotEqual(0, wrap_error.args[0])
4935+
self.assertIsNone(wrap_error.library, msg="attr must exist")
4936+
4937+
def test_preauth_data_to_tls_client(self):
4938+
client_can_continue_with_wrap_socket = threading.Event()
4939+
4940+
def call_after_accept(conn_to_client):
4941+
# This forces an immediate connection close via RST on .close().
4942+
set_socket_so_linger_on_with_zero_timeout(conn_to_client)
4943+
conn_to_client.send(
4944+
b"HTTP/1.0 307 Temporary Redirect\r\n"
4945+
b"Location: https://example.com/someone-elses-server\r\n"
4946+
b"\r\n")
4947+
conn_to_client.close() # RST
4948+
client_can_continue_with_wrap_socket.set()
4949+
return True # Tell the server to stop.
4950+
4951+
server = self.SingleConnectionTestServerThread(
4952+
call_after_accept=call_after_accept,
4953+
name="preauth_data_to_tls_client")
4954+
server.__enter__() # starts it
4955+
self.addCleanup(server.__exit__) # ... & unittest.TestCase stops it.
4956+
4957+
# Redundant; call_after_accept sets SO_LINGER on the accepted conn.
4958+
set_socket_so_linger_on_with_zero_timeout(server.listener)
4959+
4960+
with socket.socket() as client:
4961+
client.connect(server.listener.getsockname())
4962+
if not client_can_continue_with_wrap_socket.wait(2.0):
4963+
self.fail("test server took too long.")
4964+
ssl_ctx = ssl.create_default_context()
4965+
try:
4966+
tls_client = ssl_ctx.wrap_socket(
4967+
client, server_hostname="localhost")
4968+
except OSError as err: # SSLError inherits from OSError
4969+
wrap_error = err
4970+
received_data = b""
4971+
else:
4972+
wrap_error = None
4973+
received_data = tls_client.recv(400)
4974+
tls_client.close()
4975+
4976+
server.join()
4977+
self.assertEqual(b"", received_data)
4978+
self.assertIsInstance(wrap_error, OSError) # All platforms.
4979+
self.non_linux_skip_if_other_okay_error(wrap_error)
4980+
self.assertIsInstance(wrap_error, ssl.SSLError)
4981+
self.assertIn("before TLS handshake with data", wrap_error.args[1])
4982+
self.assertIn("before TLS handshake with data", wrap_error.reason)
4983+
self.assertNotEqual(0, wrap_error.args[0])
4984+
self.assertIsNone(wrap_error.library, msg="attr must exist")
4985+
4986+
def test_https_client_non_tls_response_ignored(self):
4987+
4988+
server_responding = threading.Event()
4989+
4990+
class SynchronizedHTTPSConnection(http.client.HTTPSConnection):
4991+
def connect(self):
4992+
http.client.HTTPConnection.connect(self)
4993+
# Wait for our fault injection server to have done its thing.
4994+
if not server_responding.wait(1.0) and support.verbose:
4995+
sys.stdout.write("server_responding event never set.")
4996+
self.sock = self._context.wrap_socket(
4997+
self.sock, server_hostname=self.host)
4998+
4999+
def call_after_accept(conn_to_client):
5000+
# This forces an immediate connection close via RST on .close().
5001+
set_socket_so_linger_on_with_zero_timeout(conn_to_client)
5002+
conn_to_client.send(
5003+
b"HTTP/1.0 402 Payment Required\r\n"
5004+
b"\r\n")
5005+
conn_to_client.close() # RST
5006+
server_responding.set()
5007+
return True # Tell the server to stop.
5008+
5009+
server = self.SingleConnectionTestServerThread(
5010+
call_after_accept=call_after_accept,
5011+
name="non_tls_http_RST_responder")
5012+
server.__enter__() # starts it
5013+
self.addCleanup(server.__exit__) # ... & unittest.TestCase stops it.
5014+
# Redundant; call_after_accept sets SO_LINGER on the accepted conn.
5015+
set_socket_so_linger_on_with_zero_timeout(server.listener)
5016+
5017+
connection = SynchronizedHTTPSConnection(
5018+
f"localhost",
5019+
port=server.port,
5020+
context=ssl.create_default_context(),
5021+
timeout=2.0,
5022+
)
5023+
# There are lots of reasons this raises as desired, long before this
5024+
# test was added. Sending the request requires a successful TLS wrapped
5025+
# socket; that fails if the connection is broken. It may seem pointless
5026+
# to test this. It serves as an illustration of something that we never
5027+
# want to happen... properly not happening.
5028+
with self.assertRaises(OSError) as err_ctx:
5029+
connection.request("HEAD", "/test", headers={"Host": "localhost"})
5030+
response = connection.getresponse()
5031+
5032+
48185033
def test_main(verbose=False):
48195034
if support.verbose:
48205035
plats = {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.