Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit220e31a

Browse files
miss-islingtonsethmlarsongpshead
authored
[3.12]gh-122133: Authenticate socket connection forsocket.socketpair() fallback (GH-122134) (GH-122425)
Authenticate socket connection for `socket.socketpair()` fallback when the platform does not have a native `socketpair` C API. We authenticate in-process using `getsocketname` and `getpeername` (thanks to Nathaniel J Smith for that suggestion).(cherry picked from commit78df104)Co-authored-by: Seth Michael Larson <seth@python.org>Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parentbad8497 commit220e31a

File tree

3 files changed

+147
-3
lines changed

3 files changed

+147
-3
lines changed

‎Lib/socket.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,23 @@ def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
650650
raise
651651
finally:
652652
lsock.close()
653+
654+
# Authenticating avoids using a connection from something else
655+
# able to connect to {host}:{port} instead of us.
656+
# We expect only AF_INET and AF_INET6 families.
657+
try:
658+
if (
659+
ssock.getsockname()!=csock.getpeername()
660+
orcsock.getsockname()!=ssock.getpeername()
661+
):
662+
raiseConnectionError("Unexpected peer connection")
663+
except:
664+
# getsockname() and getpeername() can fail
665+
# if either socket isn't connected.
666+
ssock.close()
667+
csock.close()
668+
raise
669+
653670
return (ssock,csock)
654671
__all__.append("socketpair")
655672

‎Lib/test/test_socket.py

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -558,19 +558,27 @@ class SocketPairTest(unittest.TestCase, ThreadableTest):
558558
def__init__(self,methodName='runTest'):
559559
unittest.TestCase.__init__(self,methodName=methodName)
560560
ThreadableTest.__init__(self)
561+
self.cli=None
562+
self.serv=None
563+
564+
defsocketpair(self):
565+
# To be overridden by some child classes.
566+
returnsocket.socketpair()
561567

562568
defsetUp(self):
563-
self.serv,self.cli=socket.socketpair()
569+
self.serv,self.cli=self.socketpair()
564570

565571
deftearDown(self):
566-
self.serv.close()
572+
ifself.serv:
573+
self.serv.close()
567574
self.serv=None
568575

569576
defclientSetUp(self):
570577
pass
571578

572579
defclientTearDown(self):
573-
self.cli.close()
580+
ifself.cli:
581+
self.cli.close()
574582
self.cli=None
575583
ThreadableTest.clientTearDown(self)
576584

@@ -4786,6 +4794,120 @@ def _testSend(self):
47864794
self.assertEqual(msg,MSG)
47874795

47884796

4797+
classPurePythonSocketPairTest(SocketPairTest):
4798+
4799+
# Explicitly use socketpair AF_INET or AF_INET6 to ensure that is the
4800+
# code path we're using regardless platform is the pure python one where
4801+
# `_socket.socketpair` does not exist. (AF_INET does not work with
4802+
# _socket.socketpair on many platforms).
4803+
defsocketpair(self):
4804+
# called by super().setUp().
4805+
try:
4806+
returnsocket.socketpair(socket.AF_INET6)
4807+
exceptOSError:
4808+
returnsocket.socketpair(socket.AF_INET)
4809+
4810+
# Local imports in this class make for easy security fix backporting.
4811+
4812+
defsetUp(self):
4813+
import_socket
4814+
self._orig_sp=getattr(_socket,'socketpair',None)
4815+
ifself._orig_spisnotNone:
4816+
# This forces the version using the non-OS provided socketpair
4817+
# emulation via an AF_INET socket in Lib/socket.py.
4818+
del_socket.socketpair
4819+
importimportlib
4820+
globalsocket
4821+
socket=importlib.reload(socket)
4822+
else:
4823+
pass# This platform already uses the non-OS provided version.
4824+
super().setUp()
4825+
4826+
deftearDown(self):
4827+
super().tearDown()
4828+
import_socket
4829+
ifself._orig_spisnotNone:
4830+
# Restore the default socket.socketpair definition.
4831+
_socket.socketpair=self._orig_sp
4832+
importimportlib
4833+
globalsocket
4834+
socket=importlib.reload(socket)
4835+
4836+
deftest_recv(self):
4837+
msg=self.serv.recv(1024)
4838+
self.assertEqual(msg,MSG)
4839+
4840+
def_test_recv(self):
4841+
self.cli.send(MSG)
4842+
4843+
deftest_send(self):
4844+
self.serv.send(MSG)
4845+
4846+
def_test_send(self):
4847+
msg=self.cli.recv(1024)
4848+
self.assertEqual(msg,MSG)
4849+
4850+
deftest_ipv4(self):
4851+
cli,srv=socket.socketpair(socket.AF_INET)
4852+
cli.close()
4853+
srv.close()
4854+
4855+
def_test_ipv4(self):
4856+
pass
4857+
4858+
@unittest.skipIf(nothasattr(_socket,'IPPROTO_IPV6')or
4859+
nothasattr(_socket,'IPV6_V6ONLY'),
4860+
"IPV6_V6ONLY option not supported")
4861+
@unittest.skipUnless(socket_helper.IPV6_ENABLED,'IPv6 required for this test')
4862+
deftest_ipv6(self):
4863+
cli,srv=socket.socketpair(socket.AF_INET6)
4864+
cli.close()
4865+
srv.close()
4866+
4867+
def_test_ipv6(self):
4868+
pass
4869+
4870+
deftest_injected_authentication_failure(self):
4871+
orig_getsockname=socket.socket.getsockname
4872+
inject_sock=None
4873+
4874+
definject_getsocketname(self):
4875+
nonlocalinject_sock
4876+
sockname=orig_getsockname(self)
4877+
# Connect to the listening socket ahead of the
4878+
# client socket.
4879+
ifinject_sockisNone:
4880+
inject_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
4881+
inject_sock.setblocking(False)
4882+
try:
4883+
inject_sock.connect(sockname[:2])
4884+
except (BlockingIOError,InterruptedError):
4885+
pass
4886+
inject_sock.setblocking(True)
4887+
returnsockname
4888+
4889+
sock1=sock2=None
4890+
try:
4891+
socket.socket.getsockname=inject_getsocketname
4892+
withself.assertRaises(OSError):
4893+
sock1,sock2=socket.socketpair()
4894+
finally:
4895+
socket.socket.getsockname=orig_getsockname
4896+
ifinject_sock:
4897+
inject_sock.close()
4898+
ifsock1:# This cleanup isn't needed on a successful test.
4899+
sock1.close()
4900+
ifsock2:
4901+
sock2.close()
4902+
4903+
def_test_injected_authentication_failure(self):
4904+
# No-op. Exists for base class threading infrastructure to call.
4905+
# We could refactor this test into its own lesser class along with the
4906+
# setUp and tearDown code to construct an ideal; it is simpler to keep
4907+
# it here and live with extra overhead one this _one_ failure test.
4908+
pass
4909+
4910+
47894911
classNonBlockingTCPTests(ThreadedTCPSocketTest):
47904912

47914913
def__init__(self,methodName='runTest'):
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Authenticate the socket connection for the ``socket.socketpair()`` fallback
2+
on platforms where ``AF_UNIX`` is not available like Windows.
3+
4+
Patch by Gregory P. Smith <greg@krypto.org> and Seth Larson <seth@python.org>. Reported by Ellie
5+
<el@horse64.org>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp