[3.13] gh-111178: Fix getsockaddrarg() undefined behavior (#131668) (#131977)

gh-111178: Fix getsockaddrarg() undefined behavior (#131668)

Don't pass direct references to sockaddr members since their type may
not match PyArg_ParseTuple() types. Instead, use temporary 'int' and
'unsigned char' variables, and update sockaddr members afterwards.

On FreeBSD, treat BTPROTO_HCI node name as a bytes string,
not as an integer.

(cherry picked from commit 8cd29c2b53)
This commit is contained in:
Victor Stinner 2025-04-01 16:40:00 +02:00 committed by GitHub
parent 05e7fa2c2f
commit c318a03b17
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 50 additions and 11 deletions

View file

@ -1485,11 +1485,15 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
struct sockaddr_hci *a = (struct sockaddr_hci *) addr;
#if defined(__NetBSD__) || defined(__DragonFly__)
return makebdaddr(&_BT_HCI_MEMB(a, bdaddr));
#else /* __NetBSD__ || __DragonFly__ */
#elif defined(__FreeBSD__)
char *node = _BT_HCI_MEMB(a, node);
size_t len = strnlen(node, sizeof(_BT_HCI_MEMB(a, node)));
return PyBytes_FromStringAndSize(node, (Py_ssize_t)len);
#else
PyObject *ret = NULL;
ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev));
return ret;
#endif /* !(__NetBSD__ || __DragonFly__) */
#endif
}
#if !defined(__FreeBSD__)
@ -2005,12 +2009,14 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
struct sockaddr_l2 *addr = &addrbuf->bt_l2;
memset(addr, 0, sizeof(struct sockaddr_l2));
_BT_L2_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "si", &straddr,
&_BT_L2_MEMB(addr, psm))) {
unsigned short psm;
if (!PyArg_ParseTuple(args, "sH", &straddr, &psm)) {
PyErr_Format(PyExc_OSError,
"%s(): wrong format", caller);
return 0;
}
_BT_L2_MEMB(addr, psm) = psm;
if (setbdaddr(straddr, &_BT_L2_MEMB(addr, bdaddr)) < 0)
return 0;
@ -2023,12 +2029,21 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
const char *straddr;
struct sockaddr_rc *addr = &addrbuf->bt_rc;
_BT_RC_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "si", &straddr,
&_BT_RC_MEMB(addr, channel))) {
PyErr_Format(PyExc_OSError,
"%s(): wrong format", caller);
#ifdef MS_WINDOWS
unsigned long channel;
# define FORMAT_CHANNEL "k"
#else
unsigned char channel;
# define FORMAT_CHANNEL "B"
#endif
if (!PyArg_ParseTuple(args, "s" FORMAT_CHANNEL,
&straddr, &channel)) {
PyErr_Format(PyExc_OSError, "%s(): wrong format", caller);
return 0;
}
#undef FORMAT_CHANNEL
_BT_RC_MEMB(addr, channel) = channel;
if (setbdaddr(straddr, &_BT_RC_MEMB(addr, bdaddr)) < 0)
return 0;
@ -2050,14 +2065,37 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
straddr = PyBytes_AS_STRING(args);
if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0)
return 0;
#else /* __NetBSD__ || __DragonFly__ */
#elif defined(__FreeBSD__)
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) {
if (!PyBytes_Check(args)) {
PyErr_Format(PyExc_OSError, "%s: "
"wrong node format", caller);
return 0;
}
const char *straddr = PyBytes_AS_STRING(args);
size_t len = PyBytes_GET_SIZE(args);
if (strlen(straddr) != len) {
PyErr_Format(PyExc_ValueError, "%s: "
"node contains embedded null character", caller);
return 0;
}
if (len > sizeof(_BT_HCI_MEMB(addr, node))) {
PyErr_Format(PyExc_ValueError, "%s: "
"node too long", caller);
return 0;
}
strncpy(_BT_HCI_MEMB(addr, node), straddr,
sizeof(_BT_HCI_MEMB(addr, node)));
#else
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
unsigned short dev = _BT_HCI_MEMB(addr, dev);
if (!PyArg_ParseTuple(args, "H", &dev)) {
PyErr_Format(PyExc_OSError,
"%s(): wrong format", caller);
return 0;
}
#endif /* !(__NetBSD__ || __DragonFly__) */
_BT_HCI_MEMB(addr, dev) = dev;
#endif
*len_ret = sizeof *addr;
return 1;
}