Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:mod:`socket`: Fix code parsing AF_BLUETOOTH socket addresses.
52 changes: 42 additions & 10 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2044,15 +2044,21 @@ 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;
_BT_L2_MEMB(addr, bdaddr_type) = BDADDR_BREDR;
if (!PyArg_ParseTuple(args, "si|iB", &straddr,
&_BT_L2_MEMB(addr, psm),
&_BT_L2_MEMB(addr, cid),
&_BT_L2_MEMB(addr, bdaddr_type))) {
unsigned short psm;
unsigned short cid = 0;
unsigned char bdaddr_type = BDADDR_BREDR;
if (!PyArg_ParseTuple(args, "sH|HB", &straddr,
&psm,
&cid,
&bdaddr_type)) {
PyErr_Format(PyExc_OSError,
"%s(): wrong format", caller);
return 0;
}
_BT_L2_MEMB(addr, psm) = psm;
_BT_L2_MEMB(addr, cid) = cid;
_BT_L2_MEMB(addr, bdaddr_type) = bdaddr_type;

if (setbdaddr(straddr, &_BT_L2_MEMB(addr, bdaddr)) < 0)
return 0;

Expand All @@ -2065,12 +2071,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 = _BT_RC_MEMB(addr, channel);
# define FORMAT_CHANNEL "k"
#else
unsigned char channel = _BT_RC_MEMB(addr, 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;

Expand All @@ -2092,13 +2107,30 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
straddr = PyBytes_AS_STRING(args);
if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0)
return 0;
#elif defined(__FreeBSD__)
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
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 (len >= sizeof(_BT_HCI_MEMB(addr, node))) {
PyErr_Format(PyExc_OSError, "%s: "
"node too long", caller);
return 0;
}
strcpy(_BT_HCI_MEMB(addr, node), straddr);
#else /* __NetBSD__ || __DragonFly__ */
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) {
unsigned short dev = _BT_HCI_MEMB(addr, dev);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is it defined?

Copy link
Member

@picnixz picnixz Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bunch of define at the top of the file:

#if (defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H)) \
     && !defined(__NetBSD__) && !defined(__DragonFly__)
#define USE_BLUETOOTH 1
#if defined(__FreeBSD__)
...
#define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb)
...
#elif defined(__NetBSD__) || defined(__DragonFly__) // <- unreachable
... 
#define _BT_HCI_MEMB(sa, memb) ((sa)->bt_##memb)
#else
...
#define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb)
...
#endif
#endif

But AFAICT, the elif defined(__NetBSD__) || defined(__DragonFly__) is not possible at all since we're still in the big #if where we want !defined(__NetBSD__) && !defined(__DragonFly__). So indeed, it looks like the macro wouldn't be defined here.

I think we should remove !defined(__NetBSD__) && !defined(__DragonFly__)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know about _BT_HCI_MEMB. I asked on what platform the *_dev member is defined, what its name and the structure name. Its turned out that it is hci_node on FreeBSD and NetBSD. hci_dev should exist on Linux.

if (!PyArg_ParseTuple(args, "H", &dev)) {
PyErr_Format(PyExc_OSError,
"%s(): wrong format", caller);
return 0;
}
_BT_HCI_MEMB(addr, dev) = dev;
#endif /* !(__NetBSD__ || __DragonFly__) */
*len_ret = sizeof *addr;
return 1;
Expand Down
Loading