Re: [PATCH v2] Bluetooth: RFCOMM: Use skb_trim to trim checksum

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Eric,

On 10.06.22 15:59, Eric Dumazet wrote:
> On Fri, Jun 10, 2022 at 4:08 AM Soenke Huster <soenke.huster@xxxxxxxxx> wrote:
>>
>> As skb->tail might be zero, it can underflow. This leads to a page
>> fault: skb_tail_pointer simply adds skb->tail (which is now MAX_UINT)
>> to skb->head.
>>
>>     BUG: unable to handle page fault for address: ffffed1021de29ff
>>     #PF: supervisor read access in kernel mode
>>     #PF: error_code(0x0000) - not-present page
>>     RIP: 0010:rfcomm_run+0x831/0x4040 (net/bluetooth/rfcomm/core.c:1751)
>>
>> By using skb_trim instead of the direct manipulation, skb->tail
>> is reset. Thus, the correct pointer to the checksum is used.
>>
>> Signed-off-by: Soenke Huster <soenke.huster@xxxxxxxxx>
>> ---
>> v2: Clarified how the bug triggers, minimize code change
>>
>>  net/bluetooth/rfcomm/core.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
>> index 7324764384b6..443b55edb3ab 100644
>> --- a/net/bluetooth/rfcomm/core.c
>> +++ b/net/bluetooth/rfcomm/core.c
>> @@ -1747,7 +1747,7 @@ static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
>>         type = __get_type(hdr->ctrl);
>>
>>         /* Trim FCS */
>> -       skb->len--; skb->tail--;
>> +       skb_trim(skb, skb->len - 1);
>>         fcs = *(u8 *)skb_tail_pointer(skb);
>>
>>         if (__check_fcs(skb->data, type, fcs)) {
>> --
>> 2.36.1
>>
> 
> Again, I do not see how skb->tail could possibly zero at this point.
> 
> If it was, skb with illegal layout has been queued in the first place,
> we need to fix the producer, not the consumer.
> 

Sorry, I thought that might be a right place as there is not much code in the kernel
that manipulates ->tail directly.

> A driver missed an skb_put() perhaps.
> 

I am using the (I guess quite unused) virtio_bt driver, and figured out that the following
fixes the bug:

--- a/drivers/bluetooth/virtio_bt.c
+++ b/drivers/bluetooth/virtio_bt.c
@@ -219,7 +219,7 @@ static void virtbt_rx_work(struct work_struct *work)
        if (!skb)
                return;
 
-       skb->len = len;
+       skb_put(skb, len);
        virtbt_rx_handle(vbt, skb);
 
        if (virtbt_add_inbuf(vbt) < 0)

I guess this is the root cause? I just used Bluetooth for a while in the VM
and no error occurred, everything worked fine.

> Can you please dump the skb here  ?
> 
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 7324764384b6773074032ad671777bf86bd3360e..358ccb4fe7214aea0bb4084188c7658316fe0ff7
> 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -1746,6 +1746,11 @@ static struct rfcomm_session
> *rfcomm_recv_frame(struct rfcomm_session *s,
>         dlci = __get_dlci(hdr->addr);
>         type = __get_type(hdr->ctrl);
> 
> +       if (!skb->tail) {
> +               DO_ONCE_LITE(skb_dump(KERN_ERR, skb, false));
> +               kfree_skb(skb);
> +               return s;
> +       }
>         /* Trim FCS */
>         skb->len--; skb->tail--;
>         fcs = *(u8 *)skb_tail_pointer(skb);

If it might still help:

skb len=4 headroom=9 headlen=4 tailroom=1728          
mac=(-1,-1) net=(0,-1) trans=-1                       
shinfo(txflags=0 nr_frags=0 gso(size=0 type=0 segs=0))
csum(0x0 ip_summed=0 complete_sw=0 valid=0 level=0)   
hash(0x0 sw=0 l4=0) proto=0x0000 pkttype=0 iif=0      
skb linear:   00000000: 03 3f 01 1c                   




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux