net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-)
rfcomm_recv_pn(), rfcomm_recv_rpn(), rfcomm_recv_rls(), and
rfcomm_recv_msc() cast skb->data to their respective structs
without first checking skb->len. A remote device can send a
short MCC frame, causing out-of-bounds reads from the skb buffer.
For rfcomm_recv_pn(), the uninitialized pn->mtu value is stored
in d->mtu via rfcomm_apply_pn(), then echoed back to the remote
device in the PN response, leaking kernel heap data.
This results in use of uninitialized memory, as reported by KMSAN.
Add explicit skb->len checks against the expected structure size
at the start of each handler before accessing the payload.
=====================================================
BUG: KMSAN: uninit-value in rfcomm_run+0x7eae/0xee90
rfcomm_run+0x7eae/0xee90
kthread+0x53f/0x600
ret_from_fork+0x20f/0x910
ret_from_fork_asm+0x1a/0x30
Uninit was created at:
kmem_cache_alloc_node_noprof+0x3cd/0x12d0
__alloc_skb+0x855/0x1190
vhci_write+0x125/0x960
vfs_write+0xbe1/0x15c0
ksys_write+0x1d9/0x470
__x64_sys_write+0x97/0xf0
x64_sys_call+0x2ff0/0x3ea0
do_syscall_64+0x134/0xf80
entry_SYSCALL_64_after_hwframe+0x77/0x7f
CPU: 0 UID: 0 PID: 3374 Comm: krfcommd Tainted: G W 7.0.0-rc7
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
Kernel panic - not syncing: kmsan.panic set ...
=====================================================
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
---
net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++--------
1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 611a9a94151e..daeba71a1514 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1431,9 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
{
- struct rfcomm_pn *pn = (void *) skb->data;
+ struct rfcomm_pn *pn;
struct rfcomm_dlc *d;
- u8 dlci = pn->dlci;
+ u8 dlci;
+
+ if (skb->len < sizeof(*pn))
+ return -EINVAL;
+
+ pn = (void *) skb->data;
+ dlci = pn->dlci;
BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
@@ -1483,8 +1489,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
{
- struct rfcomm_rpn *rpn = (void *) skb->data;
- u8 dlci = __get_dlci(rpn->dlci);
+ struct rfcomm_rpn *rpn;
+ u8 dlci;
u8 bit_rate = 0;
u8 data_bits = 0;
@@ -1495,6 +1501,12 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
u8 xoff_char = 0;
u16 rpn_mask = RFCOMM_RPN_PM_ALL;
+ if (skb->len < sizeof(*rpn))
+ return -EINVAL;
+
+ rpn = (void *) skb->data;
+ dlci = __get_dlci(rpn->dlci);
+
BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
rpn->xon_char, rpn->xoff_char, rpn->param_mask);
@@ -1589,8 +1601,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
{
- struct rfcomm_rls *rls = (void *) skb->data;
- u8 dlci = __get_dlci(rls->dlci);
+ struct rfcomm_rls *rls;
+ u8 dlci;
+
+ if (skb->len < sizeof(*rls))
+ return -EINVAL;
+
+ rls = (void *) skb->data;
+ dlci = __get_dlci(rls->dlci);
BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
@@ -1608,9 +1626,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb
static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
{
- struct rfcomm_msc *msc = (void *) skb->data;
+ struct rfcomm_msc *msc;
struct rfcomm_dlc *d;
- u8 dlci = __get_dlci(msc->dlci);
+ u8 dlci;
+
+ if (skb->len < sizeof(*msc))
+ return -EINVAL;
+
+ msc = (void *) skb->data;
+ dlci = __get_dlci(msc->dlci);
BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
--
2.52.0
Hi,
On Sun, Apr 12, 2026 at 12:55 AM SeungJu Cheon <suunj1331@gmail.com> wrote:
>
> rfcomm_recv_pn(), rfcomm_recv_rpn(), rfcomm_recv_rls(), and
> rfcomm_recv_msc() cast skb->data to their respective structs
> without first checking skb->len. A remote device can send a
> short MCC frame, causing out-of-bounds reads from the skb buffer.
>
> For rfcomm_recv_pn(), the uninitialized pn->mtu value is stored
> in d->mtu via rfcomm_apply_pn(), then echoed back to the remote
> device in the PN response, leaking kernel heap data.
>
> This results in use of uninitialized memory, as reported by KMSAN.
>
> Add explicit skb->len checks against the expected structure size
> at the start of each handler before accessing the payload.
>
> =====================================================
> BUG: KMSAN: uninit-value in rfcomm_run+0x7eae/0xee90
> rfcomm_run+0x7eae/0xee90
> kthread+0x53f/0x600
> ret_from_fork+0x20f/0x910
> ret_from_fork_asm+0x1a/0x30
>
> Uninit was created at:
> kmem_cache_alloc_node_noprof+0x3cd/0x12d0
> __alloc_skb+0x855/0x1190
> vhci_write+0x125/0x960
> vfs_write+0xbe1/0x15c0
> ksys_write+0x1d9/0x470
> __x64_sys_write+0x97/0xf0
> x64_sys_call+0x2ff0/0x3ea0
> do_syscall_64+0x134/0xf80
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> CPU: 0 UID: 0 PID: 3374 Comm: krfcommd Tainted: G W 7.0.0-rc7
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
> Kernel panic - not syncing: kmsan.panic set ...
> =====================================================
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
> ---
> net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++--------
> 1 file changed, 32 insertions(+), 8 deletions(-)
>
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 611a9a94151e..daeba71a1514 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -1431,9 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
>
> static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_pn *pn = (void *) skb->data;
> + struct rfcomm_pn *pn;
> struct rfcomm_dlc *d;
> - u8 dlci = pn->dlci;
> + u8 dlci;
> +
> + if (skb->len < sizeof(*pn))
> + return -EINVAL;
> +
> + pn = (void *) skb->data;
> + dlci = pn->dlci;
How about using skb_pull_data?
> BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
>
> @@ -1483,8 +1489,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
>
> static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
> {
> - struct rfcomm_rpn *rpn = (void *) skb->data;
> - u8 dlci = __get_dlci(rpn->dlci);
> + struct rfcomm_rpn *rpn;
> + u8 dlci;
>
> u8 bit_rate = 0;
> u8 data_bits = 0;
> @@ -1495,6 +1501,12 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
> u8 xoff_char = 0;
> u16 rpn_mask = RFCOMM_RPN_PM_ALL;
>
> + if (skb->len < sizeof(*rpn))
> + return -EINVAL;
> +
> + rpn = (void *) skb->data;
> + dlci = __get_dlci(rpn->dlci);
Ditto
> BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
> dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
> rpn->xon_char, rpn->xoff_char, rpn->param_mask);
> @@ -1589,8 +1601,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
>
> static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_rls *rls = (void *) skb->data;
> - u8 dlci = __get_dlci(rls->dlci);
> + struct rfcomm_rls *rls;
> + u8 dlci;
> +
> + if (skb->len < sizeof(*rls))
> + return -EINVAL;
> +
> + rls = (void *) skb->data;
> + dlci = __get_dlci(rls->dlci);
Ditto
> BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
>
> @@ -1608,9 +1626,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb
>
> static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_msc *msc = (void *) skb->data;
> + struct rfcomm_msc *msc;
> struct rfcomm_dlc *d;
> - u8 dlci = __get_dlci(msc->dlci);
> + u8 dlci;
> +
> + if (skb->len < sizeof(*msc))
> + return -EINVAL;
> +
> + msc = (void *) skb->data;
> + dlci = __get_dlci(msc->dlci);
Ditto.
> BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
>
> --
> 2.52.0
>
--
Luiz Augusto von Dentz
Dear SeungJu,
Thank you for the patch.
Am 12.04.26 um 06:54 schrieb SeungJu Cheon:
> rfcomm_recv_pn(), rfcomm_recv_rpn(), rfcomm_recv_rls(), and
> rfcomm_recv_msc() cast skb->data to their respective structs
> without first checking skb->len. A remote device can send a
> short MCC frame, causing out-of-bounds reads from the skb buffer.
Nice catch. Do you have a reproducer to create such a short MCC frame?
> For rfcomm_recv_pn(), the uninitialized pn->mtu value is stored
> in d->mtu via rfcomm_apply_pn(), then echoed back to the remote
> device in the PN response, leaking kernel heap data.
>
> This results in use of uninitialized memory, as reported by KMSAN.
>
> Add explicit skb->len checks against the expected structure size
> at the start of each handler before accessing the payload.
>
> =====================================================
> BUG: KMSAN: uninit-value in rfcomm_run+0x7eae/0xee90
> rfcomm_run+0x7eae/0xee90
> kthread+0x53f/0x600
> ret_from_fork+0x20f/0x910
> ret_from_fork_asm+0x1a/0x30
>
> Uninit was created at:
> kmem_cache_alloc_node_noprof+0x3cd/0x12d0
> __alloc_skb+0x855/0x1190
> vhci_write+0x125/0x960
> vfs_write+0xbe1/0x15c0
> ksys_write+0x1d9/0x470
> __x64_sys_write+0x97/0xf0
> x64_sys_call+0x2ff0/0x3ea0
> do_syscall_64+0x134/0xf80
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> CPU: 0 UID: 0 PID: 3374 Comm: krfcommd Tainted: G W 7.0.0-rc7
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
> Kernel panic - not syncing: kmsan.panic set ...
> =====================================================
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
> ---
> net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++--------
> 1 file changed, 32 insertions(+), 8 deletions(-)
>
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 611a9a94151e..daeba71a1514 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -1431,9 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
>
> static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_pn *pn = (void *) skb->data;
> + struct rfcomm_pn *pn;
> struct rfcomm_dlc *d;
> - u8 dlci = pn->dlci;
> + u8 dlci;
> +
> + if (skb->len < sizeof(*pn))
> + return -EINVAL;
> +
> + pn = (void *) skb->data;
> + dlci = pn->dlci;
gemini/gemini-3.1-pro-preview comments [1]. No idea if it’s a valid comment:
> Before these handlers are reached, rfcomm_recv_mcc() unconditionally casts
> skb->data to struct rfcomm_mcc * and reads mcc->type and mcc->len. Does
> this leave an out-of-bounds read unpatched if a remote device sends an MCC
> frame with 0 or 1 bytes of payload?
> Additionally, if rfcomm_recv_frame() unconditionally trims the FCS with
> skb->len--; skb->tail--;, could a 0-byte payload cause skb->len to
> underflow to UINT_MAX?
> Since skb->len is unsigned, this new check (UINT_MAX < 8) would evaluate to
> false, potentially bypassing this protection entirely.
>
> BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
>
> @@ -1483,8 +1489,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
>
> static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
> {
> - struct rfcomm_rpn *rpn = (void *) skb->data;
> - u8 dlci = __get_dlci(rpn->dlci);
> + struct rfcomm_rpn *rpn;
> + u8 dlci;
>
> u8 bit_rate = 0;
> u8 data_bits = 0;
> @@ -1495,6 +1501,12 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
> u8 xoff_char = 0;
> u16 rpn_mask = RFCOMM_RPN_PM_ALL;
>
> + if (skb->len < sizeof(*rpn))
> + return -EINVAL;
gemini/gemini-3.1-pro-preview comments [1]:
> Does this unconditionally drop legitimate 1-byte Remote Port Negotiation
> (RPN) requests?
> Looking at the existing code further down in rfcomm_recv_rpn():
> if (len == 1) {
> /* This is a request, return default (according to ETSI TS 07.10) settings */
> ...
> Since sizeof(struct rfcomm_rpn) is 8 bytes, enforcing this minimum length
> would reject valid 1-byte queries allowed by the ETSI TS 07.10 standard.
> +
> + rpn = (void *) skb->data;
> + dlci = __get_dlci(rpn->dlci);
> +
> BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
> dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
> rpn->xon_char, rpn->xoff_char, rpn->param_mask);
> @@ -1589,8 +1601,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
>
> static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_rls *rls = (void *) skb->data;
> - u8 dlci = __get_dlci(rls->dlci);
> + struct rfcomm_rls *rls;
> + u8 dlci;
> +
> + if (skb->len < sizeof(*rls))
> + return -EINVAL;
> +
> + rls = (void *) skb->data;
> + dlci = __get_dlci(rls->dlci);
>
> BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
>
> @@ -1608,9 +1626,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb
>
> static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_msc *msc = (void *) skb->data;
> + struct rfcomm_msc *msc;
> struct rfcomm_dlc *d;
> - u8 dlci = __get_dlci(msc->dlci);
> + u8 dlci;
> +
> + if (skb->len < sizeof(*msc))
> + return -EINVAL;
> +
> + msc = (void *) skb->data;
> + dlci = __get_dlci(msc->dlci);
>
> BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
>
Kind regards,
Paul
[1]:
https://sashiko.dev/#/patchset/20260412045457.53100-1-suunj1331%40gmail.com
Hi Paul,
Thanks for the review.
> Nice catch. Do you have a reproducer to create such a short MCC frame?
Yes, a PoC is attached. It uses VHCI to inject malformed (short) MCC frames.
> Before these handlers are reached, rfcomm_recv_mcc() unconditionally casts
> skb->data to struct rfcomm_mcc * and reads mcc->type and mcc->len.
Good point. I'll add a sizeof(struct rfcomm_mcc) check in rfcomm_recv_mcc()
before accessing these fields in v2.
> if rfcomm_recv_frame() unconditionally trims the FCS with skb->len--;
> could a 0-byte payload cause skb->len to underflow to UINT_MAX?
I'll review rfcomm_recv_frame() and add a minimum length check if needed.
> Does this unconditionally drop legitimate 1-byte RPN requests?
You're right. In v2, I'll update rfcomm_recv_rpn() to first check 1 byte
for DLCI, then validate full struct size only when len > 1.
Thanks,
SeungJu
On Sun, Apr 12, 2026 at 4:38 PM Paul Menzel <pmenzel@molgen.mpg.de> wrote:
> Dear SeungJu,
>
>
> Thank you for the patch.
>
> Am 12.04.26 um 06:54 schrieb SeungJu Cheon:
> > rfcomm_recv_pn(), rfcomm_recv_rpn(), rfcomm_recv_rls(), and
> > rfcomm_recv_msc() cast skb->data to their respective structs
> > without first checking skb->len. A remote device can send a
> > short MCC frame, causing out-of-bounds reads from the skb buffer.
>
> Nice catch. Do you have a reproducer to create such a short MCC frame?
>
> > For rfcomm_recv_pn(), the uninitialized pn->mtu value is stored
> > in d->mtu via rfcomm_apply_pn(), then echoed back to the remote
> > device in the PN response, leaking kernel heap data.
> >
> > This results in use of uninitialized memory, as reported by KMSAN.
> >
> > Add explicit skb->len checks against the expected structure size
> > at the start of each handler before accessing the payload.
> >
> > =====================================================
> > BUG: KMSAN: uninit-value in rfcomm_run+0x7eae/0xee90
> > rfcomm_run+0x7eae/0xee90
> > kthread+0x53f/0x600
> > ret_from_fork+0x20f/0x910
> > ret_from_fork_asm+0x1a/0x30
> >
> > Uninit was created at:
> > kmem_cache_alloc_node_noprof+0x3cd/0x12d0
> > __alloc_skb+0x855/0x1190
> > vhci_write+0x125/0x960
> > vfs_write+0xbe1/0x15c0
> > ksys_write+0x1d9/0x470
> > __x64_sys_write+0x97/0xf0
> > x64_sys_call+0x2ff0/0x3ea0
> > do_syscall_64+0x134/0xf80
> > entry_SYSCALL_64_after_hwframe+0x77/0x7f
> >
> > CPU: 0 UID: 0 PID: 3374 Comm: krfcommd Tainted: G W
> 7.0.0-rc7
> > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
> > Kernel panic - not syncing: kmsan.panic set ...
> > =====================================================
> >
> > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
> > ---
> > net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++--------
> > 1 file changed, 32 insertions(+), 8 deletions(-)
> >
> > diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> > index 611a9a94151e..daeba71a1514 100644
> > --- a/net/bluetooth/rfcomm/core.c
> > +++ b/net/bluetooth/rfcomm/core.c
> > @@ -1431,9 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d,
> int cr, struct rfcomm_pn *pn)
> >
> > static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct
> sk_buff *skb)
> > {
> > - struct rfcomm_pn *pn = (void *) skb->data;
> > + struct rfcomm_pn *pn;
> > struct rfcomm_dlc *d;
> > - u8 dlci = pn->dlci;
> > + u8 dlci;
> > +
> > + if (skb->len < sizeof(*pn))
> > + return -EINVAL;
> > +
> > + pn = (void *) skb->data;
> > + dlci = pn->dlci;
>
> gemini/gemini-3.1-pro-preview comments [1]. No idea if it’s a valid
> comment:
>
> > Before these handlers are reached, rfcomm_recv_mcc() unconditionally
> casts
> > skb->data to struct rfcomm_mcc * and reads mcc->type and mcc->len. Does
> > this leave an out-of-bounds read unpatched if a remote device sends an
> MCC
> > frame with 0 or 1 bytes of payload?
> > Additionally, if rfcomm_recv_frame() unconditionally trims the FCS with
> > skb->len--; skb->tail--;, could a 0-byte payload cause skb->len to
> > underflow to UINT_MAX?
> > Since skb->len is unsigned, this new check (UINT_MAX < 8) would evaluate
> to
> > false, potentially bypassing this protection entirely.
> >
> > BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
> >
> > @@ -1483,8 +1489,8 @@ static int rfcomm_recv_pn(struct rfcomm_session
> *s, int cr, struct sk_buff *skb)
> >
> > static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len,
> struct sk_buff *skb)
> > {
> > - struct rfcomm_rpn *rpn = (void *) skb->data;
> > - u8 dlci = __get_dlci(rpn->dlci);
> > + struct rfcomm_rpn *rpn;
> > + u8 dlci;
> >
> > u8 bit_rate = 0;
> > u8 data_bits = 0;
> > @@ -1495,6 +1501,12 @@ static int rfcomm_recv_rpn(struct rfcomm_session
> *s, int cr, int len, struct sk_
> > u8 xoff_char = 0;
> > u16 rpn_mask = RFCOMM_RPN_PM_ALL;
> >
> > + if (skb->len < sizeof(*rpn))
> > + return -EINVAL;
>
> gemini/gemini-3.1-pro-preview comments [1]:
>
> > Does this unconditionally drop legitimate 1-byte Remote Port Negotiation
> > (RPN) requests?
> > Looking at the existing code further down in rfcomm_recv_rpn():
> > if (len == 1) {
> > /* This is a request, return default (according to ETSI TS
> 07.10) settings */
> > ...
> > Since sizeof(struct rfcomm_rpn) is 8 bytes, enforcing this minimum length
> > would reject valid 1-byte queries allowed by the ETSI TS 07.10 standard.
>
>
> > +
> > + rpn = (void *) skb->data;
> > + dlci = __get_dlci(rpn->dlci);
> > +
> > BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc
> 0x%x xoffc 0x%x pm 0x%x",
> > dlci, cr, len, rpn->bit_rate, rpn->line_settings,
> rpn->flow_ctrl,
> > rpn->xon_char, rpn->xoff_char, rpn->param_mask);
> > @@ -1589,8 +1601,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session
> *s, int cr, int len, struct sk_
> >
> > static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct
> sk_buff *skb)
> > {
> > - struct rfcomm_rls *rls = (void *) skb->data;
> > - u8 dlci = __get_dlci(rls->dlci);
> > + struct rfcomm_rls *rls;
> > + u8 dlci;
> > +
> > + if (skb->len < sizeof(*rls))
> > + return -EINVAL;
> > +
> > + rls = (void *) skb->data;
> > + dlci = __get_dlci(rls->dlci);
> >
> > BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
> >
> > @@ -1608,9 +1626,15 @@ static int rfcomm_recv_rls(struct rfcomm_session
> *s, int cr, struct sk_buff *skb
> >
> > static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct
> sk_buff *skb)
> > {
> > - struct rfcomm_msc *msc = (void *) skb->data;
> > + struct rfcomm_msc *msc;
> > struct rfcomm_dlc *d;
> > - u8 dlci = __get_dlci(msc->dlci);
> > + u8 dlci;
> > +
> > + if (skb->len < sizeof(*msc))
> > + return -EINVAL;
> > +
> > + msc = (void *) skb->data;
> > + dlci = __get_dlci(msc->dlci);
> >
> > BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
> >
>
>
> Kind regards,
>
> Paul
>
>
> [1]:
> https://sashiko.dev/#/patchset/20260412045457.53100-1-suunj1331%40gmail.com
>
[ 441.374768][ T3375] =====================================================
[ 441.375140][ T3375] BUG: KMSAN: uninit-value in rfcomm_run+0x7eae/0xee90
[ 441.375422][ T3375] rfcomm_run+0x7eae/0xee90
[ 441.375620][ T3375] kthread+0x53f/0x600
[ 441.375801][ T3375] ret_from_fork+0x20f/0x910
[ 441.375998][ T3375] ret_from_fork_asm+0x1a/0x30
[ 441.376213][ T3375]
[ 441.376314][ T3375] Uninit was created at:
[ 441.376520][ T3375] kmem_cache_alloc_node_noprof+0x3cd/0x12d0
[ 441.376771][ T3375] __alloc_skb+0x855/0x1190
[ 441.376968][ T3375] vhci_write+0x125/0x960
[ 441.377165][ T3375] vfs_write+0xbe1/0x15c0
[ 441.377353][ T3375] ksys_write+0x1d9/0x470
[ 441.377541][ T3375] __x64_sys_write+0x97/0xf0
[ 441.377742][ T3375] x64_sys_call+0x2ff0/0x3ea0
[ 441.377945][ T3375] do_syscall_64+0x134/0xf80
[ 441.378152][ T3375] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 441.378396][ T3375]
[ 441.378503][ T3375] CPU: 1 UID: 0 PID: 3375 Comm: krfcommd Tainted: G W 7.0.0-rc7-00227-g9a9c8ce300cd #5 PREEMPT(full)
[ 441.378984][ T3375] Tainted: [W]=WARN
[ 441.379143][ T3375] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
[ 441.379513][ T3375] =====================================================
[ 441.379782][ T3375] Disabling lock debugging due to kernel taint
[ 441.380022][ T3375] Kernel panic - not syncing: kmsan.panic set ...
[ 441.380282][ T3375] CPU: 1 UID: 0 PID: 3375 Comm: krfcommd Tainted: G B W 7.0.0-rc7-00227-g9a9c8ce300cd #5 PREEMPT(full)
[ 441.380763][ T3375] Tainted: [B]=BAD_PAGE, [W]=WARN
[ 441.380969][ T3375] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-9.fc43 06/10/2025
[ 441.381339][ T3375] Call Trace:
[ 441.381477][ T3375] <TASK>
[ 441.381602][ T3375] __dump_stack+0x26/0x30
[ 441.381796][ T3375] dump_stack_lvl+0x50/0x1c0
[ 441.382000][ T3375] ? dump_stack+0x12/0x25
[ 441.382195][ T3375] dump_stack+0x1e/0x25
[ 441.382382][ T3375] vpanic+0x7b4/0x1430
[ 441.382573][ T3375] panic+0x15d/0x160
[ 441.382765][ T3375] ? __msan_metadata_ptr_for_store_1+0x27/0x40
[ 441.383042][ T3375] kmsan_report+0x31a/0x320
[ 441.383266][ T3375] ? __msan_warning+0x1b/0x30
[ 441.383481][ T3375] ? rfcomm_run+0x7eae/0xee90
[ 441.383694][ T3375] ? kthread+0x53f/0x600
[ 441.383889][ T3375] ? ret_from_fork+0x20f/0x910
[ 441.384104][ T3375] ? ret_from_fork_asm+0x1a/0x30
[ 441.384325][ T3375] ? __msan_warning+0x1b/0x30
[ 441.384536][ T3375] ? filter_irq_stacks+0x13f/0x190
[ 441.384764][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.384984][ T3375] ? kmsan_internal_set_shadow_origin+0x7a/0x110
[ 441.385262][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.385482][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.385699][ T3375] ? kmsan_internal_set_shadow_origin+0x7a/0x110
[ 441.385975][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.386200][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.386421][ T3375] ? kmsan_get_shadow_origin_ptr+0x4a/0xb0
[ 441.386669][ T3375] ? __msan_metadata_ptr_for_store_8+0x27/0x40
[ 441.386936][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.387162][ T3375] __msan_warning+0x1b/0x30
[ 441.387366][ T3375] rfcomm_run+0x7eae/0xee90
[ 441.387582][ T3375] ? kmsan_get_metadata+0xf1/0x160
[ 441.387807][ T3375] ? __pfx_woken_wake_function+0x10/0x10
[ 441.388054][ T3375] kthread+0x53f/0x600
[ 441.388244][ T3375] ? __pfx_rfcomm_run+0x10/0x10
[ 441.388464][ T3375] ? __pfx_kthread+0x10/0x10
[ 441.388670][ T3375] ret_from_fork+0x20f/0x910
[ 441.388874][ T3375] ? __switch_to+0x51c/0x750
[ 441.389087][ T3375] ? __pfx_kthread+0x10/0x10
[ 441.389295][ T3375] ret_from_fork_asm+0x1a/0x30
[ 441.389514][ T3375] </TASK>
[ 441.389958][ T3375] Kernel Offset: disabled
[ 441.390138][ T3375] Rebooting in 86400 seconds..
© 2016 - 2026 Red Hat, Inc.