Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp798194ybz; Wed, 22 Apr 2020 08:11:29 -0700 (PDT) X-Google-Smtp-Source: APiQypL/cj/BX3U0WHueueS7+fOIXooeOFVX71HUbVPVKu0m4MVJNvmaApPe6kRGLyA3yZquMpe8 X-Received: by 2002:a17:906:5601:: with SMTP id f1mr25778876ejq.152.1587568288952; Wed, 22 Apr 2020 08:11:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1587568288; cv=none; d=google.com; s=arc-20160816; b=pGvmy16Kn2SdECxGwI6OX1JWon3BzKX3CYLzupvNiuYjxeJXznHoRIuapWMO1AWk+L +YQGVfwQBv5wKpFIeEXEwTZ+HnMH4/4vhPwArMCTAcyppJxR75fAFRzQ+pAln/wjSVa/ vcvPUFeUXFBTDxBfGykolQilIpbKI2LnW76IPS5mfxw7M93fPTHkVhpxe9ahXZouZW8z y0Pn6BKLboN4pAr8dZiIzXo92uVXVr/vKiWMZ35hZ+QjdC6JYrWpgjOTyh8qXr9XIYlD NFo1jzLlA7ouLA7cSXR2r/sZ79yP8Jv3dT93ZoyVKJyd8QRT1ZePajBrnvDpyliqiYq+ BdFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:message-id:in-reply-to :subject:cc:to:from:date; bh=mNc3LDC9J1al4ToTIUYi55fQ1paqdAgY/LHVkgNqIJw=; b=hWxzVhnk8jFLdegigIGiDwHsMV+Wgux1OtWTmwfrcs+GyYiIhBVeda4UfTUBpAjC7j qc925D4bcLcOaAfSWw8v4QeEVlJwe4xBVF5ay8TjQ3gvaqc9aCooQB/6fOk4+62mIz5r 7wPQZluz8Cq5K58jrwDWbvft5jJMr9UnfYYWJF6nbLTfxFI7TXXBvkJN/s8SMelbM45t Ce9HU7TC5ti7CGLK3Qv6WhYZRSbr1epN8Mg0hOO1sOgWNyhnf7alMp+LtwLq7rENBubb qIgAwMM/yLuErOQF0mwlUxEpvGrFZNa6xTSayCX2eJEsu0j1oMRa/6ISx5OUEXUpoGTG 71ww== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d24si3573249edv.539.2020.04.22.08.10.45; Wed, 22 Apr 2020 08:11:28 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727089AbgDVPCR (ORCPT + 99 others); Wed, 22 Apr 2020 11:02:17 -0400 Received: from netrider.rowland.org ([192.131.102.5]:51641 "HELO netrider.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1726327AbgDVPCR (ORCPT ); Wed, 22 Apr 2020 11:02:17 -0400 Received: (qmail 24632 invoked by uid 500); 22 Apr 2020 11:02:15 -0400 Received: from localhost (sendmail-bs@127.0.0.1) by localhost with SMTP; 22 Apr 2020 11:02:15 -0400 Date: Wed, 22 Apr 2020 11:02:15 -0400 (EDT) From: Alan Stern X-X-Sender: stern@netrider.rowland.org To: syzbot , Dmitry Torokhov , Jiri Kosina cc: Julian Squires , Hans de Goede , Benjamin Tissoires , , , , , Kernel development list , USB list , , Ping Cheng , , Subject: Re: KASAN: use-after-free Read in usbhid_close (3) In-Reply-To: Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Sun, 19 Apr 2020, Alan Stern wrote: > Jiri, you should know: Are HID drivers supposed to work okay when the > ->close callback is issued after (or concurrently with) the ->stop > callback? No response. I'll assume that strange callback orderings should be supported. Let's see if the patch below fixes the race in usbhid. Alan Stern #syz test: https://github.com/google/kasan.git 0fa84af8 Index: usb-devel/drivers/hid/usbhid/hid-core.c =================================================================== --- usb-devel.orig/drivers/hid/usbhid/hid-core.c +++ usb-devel/drivers/hid/usbhid/hid-core.c @@ -682,16 +682,21 @@ static int usbhid_open(struct hid_device struct usbhid_device *usbhid = hid->driver_data; int res; + mutex_lock(&usbhid->mutex); + set_bit(HID_OPENED, &usbhid->iofl); - if (hid->quirks & HID_QUIRK_ALWAYS_POLL) - return 0; + if (hid->quirks & HID_QUIRK_ALWAYS_POLL) { + res = 0; + goto Done; + } res = usb_autopm_get_interface(usbhid->intf); /* the device must be awake to reliably request remote wakeup */ if (res < 0) { clear_bit(HID_OPENED, &usbhid->iofl); - return -EIO; + res = -EIO; + goto Done; } usbhid->intf->needs_remote_wakeup = 1; @@ -725,6 +730,9 @@ static int usbhid_open(struct hid_device msleep(50); clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); + + Done: + mutex_unlock(&usbhid->mutex); return res; } @@ -732,6 +740,8 @@ static void usbhid_close(struct hid_devi { struct usbhid_device *usbhid = hid->driver_data; + mutex_lock(&usbhid->mutex); + /* * Make sure we don't restart data acquisition due to * a resumption we no longer care about by avoiding racing @@ -743,12 +753,13 @@ static void usbhid_close(struct hid_devi clear_bit(HID_IN_POLLING, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); - if (hid->quirks & HID_QUIRK_ALWAYS_POLL) - return; + if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) { + hid_cancel_delayed_stuff(usbhid); + usb_kill_urb(usbhid->urbin); + usbhid->intf->needs_remote_wakeup = 0; + } - hid_cancel_delayed_stuff(usbhid); - usb_kill_urb(usbhid->urbin); - usbhid->intf->needs_remote_wakeup = 0; + mutex_unlock(&usbhid->mutex); } /* @@ -1057,6 +1068,8 @@ static int usbhid_start(struct hid_devic unsigned int n, insize = 0; int ret; + mutex_lock(&usbhid->mutex); + clear_bit(HID_DISCONNECTED, &usbhid->iofl); usbhid->bufsize = HID_MIN_BUFFER_SIZE; @@ -1177,6 +1190,8 @@ static int usbhid_start(struct hid_devic usbhid_set_leds(hid); device_set_wakeup_enable(&dev->dev, 1); } + + mutex_unlock(&usbhid->mutex); return 0; fail: @@ -1187,6 +1202,7 @@ fail: usbhid->urbout = NULL; usbhid->urbctrl = NULL; hid_free_buffers(dev, hid); + mutex_unlock(&usbhid->mutex); return ret; } @@ -1202,6 +1218,8 @@ static void usbhid_stop(struct hid_devic usbhid->intf->needs_remote_wakeup = 0; } + mutex_lock(&usbhid->mutex); + clear_bit(HID_STARTED, &usbhid->iofl); spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ set_bit(HID_DISCONNECTED, &usbhid->iofl); @@ -1222,6 +1240,8 @@ static void usbhid_stop(struct hid_devic usbhid->urbout = NULL; hid_free_buffers(hid_to_usb_dev(hid), hid); + + mutex_unlock(&usbhid->mutex); } static int usbhid_power(struct hid_device *hid, int lvl) @@ -1382,6 +1402,7 @@ static int usbhid_probe(struct usb_inter INIT_WORK(&usbhid->reset_work, hid_reset); timer_setup(&usbhid->io_retry, hid_retry_timeout, 0); spin_lock_init(&usbhid->lock); + mutex_init(&usbhid->mutex); ret = hid_add_device(hid); if (ret) { Index: usb-devel/drivers/hid/usbhid/usbhid.h =================================================================== --- usb-devel.orig/drivers/hid/usbhid/usbhid.h +++ usb-devel/drivers/hid/usbhid/usbhid.h @@ -80,6 +80,7 @@ struct usbhid_device { dma_addr_t outbuf_dma; /* Output buffer dma */ unsigned long last_out; /* record of last output for timeouts */ + struct mutex mutex; /* start/stop/open/close */ spinlock_t lock; /* fifo spinlock */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ struct timer_list io_retry; /* Retry timer */