Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/library/socket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,9 @@ The :mod:`!socket` module also offers various network-related services:
for IPv6 multicast addresses, string representing an address will not
contain ``%scope_id`` part.

.. versionchanged:: next
Null characters are now rejected in the *host* and *port* parameters.

.. _Happy Eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs

.. function:: getfqdn([name])
Expand Down
33 changes: 33 additions & 0 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -2104,6 +2104,39 @@ def test_getnameinfo_ipv6_scopeid_numeric(self):
nameinfo = socket.getnameinfo(sockaddr, socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
self.assertEqual(nameinfo, ('ff02::1de:c0:face:8d%' + str(ifindex), '1234'))

def test_getaddrinfo_null_bytes(self):
# getaddrinfo() must reject embedded null bytes instead of silently
# truncating the host or port at the C boundary. The checks run
# before any name resolution, so no network access is needed.
hosts = [
# embedded
'local\0host', b'local\0host',
# trailing
'localhost\0', b'localhost\0',
# leading (truncates to '')
'\0localhost', b'\0localhost',
'\0', b'\0',
# non-ASCII, goes through IDNA
'b\xfccher\0.example',
]
for host in hosts:
with self.subTest(host=host):
with self.assertRaisesRegex(ValueError, 'host'):
socket.getaddrinfo(host, 80)

ports = [
'8\x000',
b'8\x000',
'http\0',
b'http\0',
'\0',
b'\0'
]
for port in ports:
with self.subTest(port=port):
with self.assertRaisesRegex(ValueError, 'port'):
socket.getaddrinfo("localhost", port)

def test_str_for_enums(self):
# Make sure that the AF_* and SOCK_* constants have enum-like string
# reprs.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.. cve: CVE-2026-116566
:func:`socket.getaddrinfo` now rejects null bytes within *host* and *port*
parameters as this previously caused the values to be silently truncated.
20 changes: 17 additions & 3 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -7018,6 +7018,7 @@ _socket_getaddrinfo_impl(PyObject *module, PyObject *hobj, PyObject *pobj,
struct addrinfo *res0 = NULL;
PyObject *pstr = NULL;
const char *hptr, *pptr;
Py_ssize_t hlen = 0, plen = 0;
int error;
PyObject *all = (PyObject *)NULL;
PyObject *idna = NULL;
Expand All @@ -7030,13 +7031,20 @@ _socket_getaddrinfo_impl(PyObject *module, PyObject *hobj, PyObject *pobj,
return NULL;
assert(PyBytes_Check(idna));
hptr = PyBytes_AS_STRING(idna);
hlen = PyBytes_GET_SIZE(idna);
} else if (PyBytes_Check(hobj)) {
hptr = PyBytes_AsString(hobj);
hptr = PyBytes_AS_STRING(hobj);
hlen = PyBytes_GET_SIZE(hobj);
} else {
PyErr_SetString(PyExc_TypeError,
"getaddrinfo() argument 1 must be string or None");
return NULL;
}
if (hptr != NULL && strlen(hptr) != (size_t)hlen) {
PyErr_SetString(PyExc_ValueError,
"getaddrinfo() host must not contain null characters");
goto err;
}
if (PyIndex_Check(pobj)) {
pstr = PyNumber_Index(pobj);
if (pstr == NULL)
Expand All @@ -7046,21 +7054,27 @@ _socket_getaddrinfo_impl(PyObject *module, PyObject *hobj, PyObject *pobj,
if (pstr == NULL)
goto err;
assert(PyUnicode_Check(pstr));
pptr = PyUnicode_AsUTF8(pstr);
pptr = PyUnicode_AsUTF8AndSize(pstr, &plen);
if (pptr == NULL)
goto err;
} else if (PyUnicode_Check(pobj)) {
pptr = PyUnicode_AsUTF8(pobj);
pptr = PyUnicode_AsUTF8AndSize(pobj, &plen);
if (pptr == NULL)
goto err;
} else if (PyBytes_Check(pobj)) {
pptr = PyBytes_AS_STRING(pobj);
plen = PyBytes_GET_SIZE(pobj);
} else if (pobj == Py_None) {
pptr = (char *)NULL;
} else {
PyErr_SetString(PyExc_OSError, "Int or String expected");
goto err;
}
if (pptr != NULL && strlen(pptr) != (size_t)plen) {
PyErr_SetString(PyExc_ValueError,
"getaddrinfo() port must not contain null characters");
goto err;
}
#if defined(__APPLE__) && defined(AI_NUMERICSERV)
if ((flags & AI_NUMERICSERV) && (pptr == NULL || (pptr[0] == '0' && pptr[1] == 0))) {
/* On OSX up to at least OSX 10.8 getaddrinfo crashes
Expand Down
Loading