[PATCH] Bluetooth: RFCOMM: validate skb length in MCC handlers

SeungJu Cheon posted 1 patch 2 months, 1 week ago
There is a newer version of this series
net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++--------
1 file changed, 32 insertions(+), 8 deletions(-)
[PATCH] Bluetooth: RFCOMM: validate skb length in MCC handlers
Posted by SeungJu Cheon 2 months, 1 week ago
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
Re: [PATCH] Bluetooth: RFCOMM: validate skb length in MCC handlers
Posted by Luiz Augusto von Dentz 2 months, 1 week ago
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
Re: [PATCH] Bluetooth: RFCOMM: validate skb length in MCC handlers
Posted by Paul Menzel 2 months, 1 week ago
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
Re: [PATCH] Bluetooth: RFCOMM: validate skb length in MCC handlers
Posted by SeungJu Cheon 2 months, 1 week ago
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..