mirror of https://github.com/python/cpython
gh-94821: Fix autobind of empty unix domain address (GH-94826)
When binding a unix socket to an empty address on Linux, the socket is
automatically bound to an available address in the abstract namespace.
>>> s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
>>> s.bind("")
>>> s.getsockname()
b'\x0075499'
Since python 3.9, the socket is bound to the one address:
>>> s.getsockname()
b'\x00'
And trying to bind multiple sockets will fail with:
Traceback (most recent call last):
File "/home/nsoffer/src/cpython/Lib/test/test_socket.py", line 5553, in testAutobind
s2.bind("")
OSError: [Errno 98] Address already in use
Added 2 tests:
- Auto binding empty address on Linux
- Failing to bind an empty address on other platforms
Fixes f6b3a07b7d
(bpo-44493: Add missing terminated NUL in sockaddr_un's length (GH-26866)
This commit is contained in:
parent
dc54193095
commit
c22f134211
|
@ -5543,6 +5543,20 @@ class TestLinuxAbstractNamespace(unittest.TestCase):
|
||||||
s.bind(bytearray(b"\x00python\x00test\x00"))
|
s.bind(bytearray(b"\x00python\x00test\x00"))
|
||||||
self.assertEqual(s.getsockname(), b"\x00python\x00test\x00")
|
self.assertEqual(s.getsockname(), b"\x00python\x00test\x00")
|
||||||
|
|
||||||
|
def testAutobind(self):
|
||||||
|
# Check that binding to an empty string binds to an available address
|
||||||
|
# in the abstract namespace as specified in unix(7) "Autobind feature".
|
||||||
|
abstract_address = b"^\0[0-9a-f]{5}"
|
||||||
|
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s1:
|
||||||
|
s1.bind("")
|
||||||
|
self.assertRegex(s1.getsockname(), abstract_address)
|
||||||
|
# Each socket is bound to a different abstract address.
|
||||||
|
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s2:
|
||||||
|
s2.bind("")
|
||||||
|
self.assertRegex(s2.getsockname(), abstract_address)
|
||||||
|
self.assertNotEqual(s1.getsockname(), s2.getsockname())
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'test needs socket.AF_UNIX')
|
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'test needs socket.AF_UNIX')
|
||||||
class TestUnixDomain(unittest.TestCase):
|
class TestUnixDomain(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -5612,6 +5626,11 @@ class TestUnixDomain(unittest.TestCase):
|
||||||
self.addCleanup(os_helper.unlink, path)
|
self.addCleanup(os_helper.unlink, path)
|
||||||
self.assertEqual(self.sock.getsockname(), path)
|
self.assertEqual(self.sock.getsockname(), path)
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.platform == 'linux', 'Linux specific test')
|
||||||
|
def testEmptyAddress(self):
|
||||||
|
# Test that binding empty address fails.
|
||||||
|
self.assertRaises(OSError, self.sock.bind, "")
|
||||||
|
|
||||||
|
|
||||||
class BufferIOTest(SocketConnectedTest):
|
class BufferIOTest(SocketConnectedTest):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix binding of unix socket to empty address on Linux to use an available
|
||||||
|
address from the abstract namespace, instead of "\0".
|
|
@ -1724,8 +1724,10 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
||||||
|
|
||||||
struct sockaddr_un* addr = &addrbuf->un;
|
struct sockaddr_un* addr = &addrbuf->un;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if (path.len > 0 && *(const char *)path.buf == 0) {
|
if (path.len == 0 || *(const char *)path.buf == 0) {
|
||||||
/* Linux abstract namespace extension */
|
/* Linux abstract namespace extension:
|
||||||
|
- Empty address auto-binding to an abstract address
|
||||||
|
- Address that starts with null byte */
|
||||||
if ((size_t)path.len > sizeof addr->sun_path) {
|
if ((size_t)path.len > sizeof addr->sun_path) {
|
||||||
PyErr_SetString(PyExc_OSError,
|
PyErr_SetString(PyExc_OSError,
|
||||||
"AF_UNIX path too long");
|
"AF_UNIX path too long");
|
||||||
|
|
Loading…
Reference in New Issue