• Vladimir Zapolskiy's avatar
    usb: gadget: u_audio: protect stream runtime fields with stream spinlock · 56bc6158
    Vladimir Zapolskiy authored
    The change protects almost the whole body of u_audio_iso_complete()
    function by PCM stream lock, this is mainly sufficient to avoid a race
    between USB request completion and stream termination, the change
    prevents a possibility of invalid memory access in interrupt context
    by memcpy():
    
        Unable to handle kernel paging request at virtual address 00004e80
        pgd = c0004000
        [00004e80] *pgd=00000000
        Internal error: Oops: 817 [#1] PREEMPT SMP ARM
        CPU: 0 PID: 3 Comm: ksoftirqd/0 Tainted: G         C   3.14.54+ #117
        task: da180b80 ti: da192000 task.ti: da192000
        PC is at memcpy+0x50/0x330
        LR is at 0xcdd92b0e
        pc : [<c029ef30>]    lr : [<cdd92b0e>]    psr: 20000193
        sp : da193ce4  ip : dd86ae26  fp : 0000b180
        r10: daf81680  r9 : 00000000  r8 : d58a01ea
        r7 : 2c0b43e4  r6 : acdfb08b  r5 : 01a271cf  r4 : 87389377
        r3 : 69469782  r2 : 00000020  r1 : daf82fe0  r0 : 00004e80
        Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
        Control: 10c5387d  Table: 2b70804a  DAC: 00000015
        Process ksoftirqd/0 (pid: 3, stack limit = 0xda192238)
    
    Also added a check for potential !runtime condition, commonly it is
    done by PCM_RUNTIME_CHECK(substream) in the beginning, however this
    does not completely prevent from oopses in u_audio_iso_complete(),
    because the proper protection scheme must be implemented in PCM
    library functions.
    
    An example of *not fixed* oops due to substream->runtime->*
    dereference by snd_pcm_running(substream) from
    snd_pcm_period_elapsed(), where substream->runtime is gone while
    waiting the substream lock:
    
        Unable to handle kernel paging request at virtual address 6b6b6b6b
        pgd = db7e4000
        [6b6b6b6b] *pgd=00000000
        CPU: 0 PID: 193 Comm: klogd Tainted: G         C   3.14.54+ #118
        task: db5ac500 ti: db60c000 task.ti: db60c000
        PC is at snd_pcm_period_elapsed+0x48/0xd8 [snd_pcm]
        LR is at snd_pcm_period_elapsed+0x40/0xd8 [snd_pcm]
        pc : [<>]    lr : [<>]    psr: 60000193
        Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
        Control: 10c5387d  Table: 2b7e404a  DAC: 00000015
        Process klogd (pid: 193, stack limit = 0xdb60c238)
        [<>] (snd_pcm_period_elapsed [snd_pcm]) from [<>] (udc_irq+0x500/0xbbc)
        [<>] (udc_irq) from [<>] (ci_irq+0x280/0x304)
        [<>] (ci_irq) from [<>] (handle_irq_event_percpu+0xa4/0x40c)
        [<>] (handle_irq_event_percpu) from [<>] (handle_irq_event+0x3c/0x5c)
        [<>] (handle_irq_event) from [<>] (handle_fasteoi_irq+0xc4/0x110)
        [<>] (handle_fasteoi_irq) from [<>] (generic_handle_irq+0x20/0x30)
        [<>] (generic_handle_irq) from [<>] (handle_IRQ+0x80/0xc0)
        [<>] (handle_IRQ) from [<>] (gic_handle_irq+0x3c/0x60)
        [<>] (gic_handle_irq) from [<>] (__irq_svc+0x44/0x78)
    Signed-off-by: default avatarVladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
    [erosca: W/o this patch, with minimal instrumentation [1], I can
             consistently reproduce BUG: KASAN: use-after-free [2]]
    
    [1] Instrumentation to reproduce issue [2]:
     diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
     index a72295c953bb..bd0b308024fe 100644
     --- a/drivers/usb/gadget/function/u_audio.c
     +++ b/drivers/usb/gadget/function/u_audio.c
     @@ -16,6 +16,7 @@
      #include <sound/core.h>
      #include <sound/pcm.h>
      #include <sound/pcm_params.h>
     +#include <linux/delay.h>
    
      #include "u_audio.h"
    
     @@ -147,6 +148,8 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
    
     	spin_unlock_irqrestore(&prm->lock, flags);
    
     +	udelay(500); //delay here to increase probability of parallel activities
     +
     	/* Pack USB load in ALSA ring buffer */
     	pending = prm->dma_bytes - hw_ptr;
    
    [2] After applying [1], below BUG occurs on Rcar-H3-Salvator-X board:
    ==================================================================
    BUG: KASAN: use-after-free in u_audio_iso_complete+0x24c/0x520 [u_audio]
    Read of size 8 at addr ffff8006cafcc248 by task swapper/0/0
    
    CPU: 0 PID: 0 Comm: swapper/0 Tainted: G        WC      4.14.47+ #160
    Hardware name: Renesas Salvator-X board based on r8a7795 ES2.0+ (DT)
    Call trace:
    [<ffff2000080925ac>] dump_backtrace+0x0/0x364
    [<ffff200008092924>] show_stack+0x14/0x1c
    [<ffff200008f8dbcc>] dump_stack+0x108/0x174
    [<ffff2000083c71b8>] print_address_description+0x7c/0x32c
    [<ffff2000083c78e8>] kasan_report+0x324/0x354
    [<ffff2000083c6114>] __asan_load8+0x24/0x94
    [<ffff2000021d1b34>] u_audio_iso_complete+0x24c/0x520 [u_audio]
    [<ffff20000152fe50>] usb_gadget_giveback_request+0x480/0x4d0 [udc_core]
    [<ffff200001860ab8>] usbhsg_queue_done+0x100/0x130 [renesas_usbhs]
    [<ffff20000185f814>] usbhsf_pkt_handler+0x1a4/0x298 [renesas_usbhs]
    [<ffff20000185fb38>] usbhsf_irq_ready+0x128/0x178 [renesas_usbhs]
    [<ffff200001859cc8>] usbhs_interrupt+0x440/0x490 [renesas_usbhs]
    [<ffff2000081a0288>] __handle_irq_event_percpu+0x594/0xa58
    [<ffff2000081a07d0>] handle_irq_event_percpu+0x84/0x12c
    [<ffff2000081a0928>] handle_irq_event+0xb0/0x10c
    [<ffff2000081a8384>] handle_fasteoi_irq+0x1e0/0x2ec
    [<ffff20000819e5f8>] generic_handle_irq+0x2c/0x44
    [<ffff20000819f0d0>] __handle_domain_irq+0x190/0x194
    [<ffff20000808177c>] gic_handle_irq+0x80/0xac
    Exception stack(0xffff200009e97c80 to 0xffff200009e97dc0)
    7c80: 0000000000000000 0000000000000000 0000000000000003 ffff200008179298
    7ca0: ffff20000ae1c180 dfff200000000000 0000000000000000 ffff2000081f9a88
    7cc0: ffff200009eb5960 ffff200009e97cf0 0000000000001600 ffff0400041b064b
    7ce0: 0000000000000000 0000000000000002 0000000200000001 0000000000000001
    7d00: ffff20000842197c 0000ffff958c4970 0000000000000000 ffff8006da0d5b80
    7d20: ffff8006d4678498 0000000000000000 000000126bde0a8b ffff8006d4678480
    7d40: 0000000000000000 000000126bdbea64 ffff200008fd0000 ffff8006fffff980
    7d60: 00000000495f0018 ffff200009e97dc0 ffff200008b6c4ec ffff200009e97dc0
    7d80: ffff200008b6c4f0 0000000020000145 ffff8006da0d5b80 ffff8006d4678498
    7da0: ffffffffffffffff ffff8006d4678498 ffff200009e97dc0 ffff200008b6c4f0
    [<ffff200008084034>] el1_irq+0xb4/0x12c
    [<ffff200008b6c4f0>] cpuidle_enter_state+0x818/0x844
    [<ffff200008b6c59c>] cpuidle_enter+0x18/0x20
    [<ffff20000815f2e4>] call_cpuidle+0x98/0x9c
    [<ffff20000815f674>] do_idle+0x214/0x264
    [<ffff20000815facc>] cpu_startup_entry+0x20/0x24
    [<ffff200008fb09d8>] rest_init+0x30c/0x320
    [<ffff2000095f1338>] start_kernel+0x570/0x5b0
    ---<-snip->---
    
    Fixes: 132fcb46 ("usb: gadget: Add Audio Class 2.0 Driver")
    Signed-off-by: default avatarEugeniu Rosca <erosca@de.adit-jv.com>
    Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
    56bc6158
u_audio.c 15 KB