All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Herrmann <dh.herrmann@googlemail.com>
To: linux-input@vger.kernel.org
Cc: padovan@profusion.mobi, jkosina@suse.cz,
	dmitry.torokhov@gmail.com,
	David Herrmann <dh.herrmann@googlemail.com>
Subject: Re: [RFC] [PATCH] HID: Fix race condition between driver core and ll-driver
Date: Thu, 14 Jul 2011 10:48:24 +0200	[thread overview]
Message-ID: <CANq1E4QLsSezP-pSFsNWPT924Xc9y=j8jHi2R-k4ieZzewO5PA@mail.gmail.com> (raw)
In-Reply-To: <1310567061-2679-1-git-send-email-dh.herrmann@googlemail.com>

On Wed, Jul 13, 2011 at 4:24 PM, David Herrmann
<dh.herrmann@googlemail.com> wrote:
> HID low level drivers register new devices with the HID core which then
> adds the devices to the HID bus. The HID bus normally immediately probes
> an appropriate driver which then handles HID input for this device.
> The ll driver now uses the hid_input_report() function to report input
> events for a specific device. However, if the HID bus unloads the driver
> at the same time (for instance via a call to
>  /sys/bus/hid/devices/<dev>/unbind) then the hdev->driver pointer may be
> used by hid_input_report() and hid_device_remove() at the same time
> which may cause hdev->driver to point to invalid memory.
>
> This fix adds a semaphore to every hid device which protects
> hdev->driver from asynchronous access. This semaphore is locked during
> driver *_probe and *_remove and also inside hid_input_report(). The
> *_probe and *_remove functions may sleep so the semaphore is good here,
> however, hid_input_report() is in atomic context and hence only uses
> down_trylock(). If it cannot acquire the lock it simply drops the input
> package.
>
> The low-level drivers report input events synchronously so
> hid_input_report() should never be entered twice at the same time on the
> same device. Hence, the lock should always be available. But if the
> driver is currently probed/removed then the lock is not available and
> dropping the package should be safe because this is what would have
> happened if the package arrived some milliseconds earlier/later.
>
> This also fixes another race condition while probing drivers:
> First the *_probe function of the driver is called and only if that
> succeeds, the related input device of hidinput is registered. If the low
> level driver reports input events after the *_probe function returned
> but before the input device is registered, then a NULL pointer
> dereference will occur. (Equivalently on driver remove function).
> This is not possible anymore, since the semaphore lock drops all
> incoming packages until the driver/device is fully initialized.
>
> Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
> ---
>  drivers/hid/hid-core.c |   41 ++++++++++++++++++++++++++++++++++-------
>  include/linux/hid.h    |    2 ++
>  2 files changed, 36 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 2a268fc..59b1a5b 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -29,6 +29,7 @@
>  #include <linux/wait.h>
>  #include <linux/vmalloc.h>
>  #include <linux/sched.h>
> +#include <linux/semaphore.h>
>
>  #include <linux/hid.h>
>  #include <linux/hiddev.h>
> @@ -1087,14 +1088,23 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
>        unsigned int i;
>        int ret;

This must be "int ret = 0;".

>
> -       if (!hid || !hid->driver)
> +       if (!hid)
>                return -ENODEV;
> +
> +       if (down_trylock(&hid->driver_lock))
> +               return -EBUSY;
> +
> +       if (!hid->driver) {
> +               ret = -ENODEV;
> +               goto unlock;
> +       }
>        report_enum = hid->report_enum + type;
>        hdrv = hid->driver;
>
>        if (!size) {
>                dbg_hid("empty report\n");
> -               return -1;
> +               ret = -1;
> +               goto unlock;
>        }
>
>        buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
> @@ -1118,17 +1128,23 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
>  nomem:
>        report = hid_get_report(report_enum, data);
>
> -       if (!report)
> -               return -1;
> +       if (!report) {
> +               ret = -1;
> +               goto unlock;
> +       }
>
>        if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
>                ret = hdrv->raw_event(hid, report, data, size);
> -               if (ret != 0)
> -                       return ret < 0 ? ret : 0;
> +               if (ret != 0) {
> +                       ret = ret < 0 ? ret : 0;
> +                       goto unlock;
> +               }
>        }
>
>        hid_report_raw_event(hid, type, data, size, interrupt);
>
> +unlock:
> +       up(&hid->driver_lock);
>        return 0;

And this must be "return ret;" of course.

>
> Regards
> David
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2011-07-14  8:48 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-13 14:24 [RFC] [PATCH] HID: Fix race condition between driver core and ll-driver David Herrmann
2011-07-14  8:48 ` David Herrmann [this message]
2011-07-25 11:37   ` David Herrmann
2011-07-26  9:51     ` Jiri Kosina
2011-08-10 12:04   ` Jiri Kosina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CANq1E4QLsSezP-pSFsNWPT924Xc9y=j8jHi2R-k4ieZzewO5PA@mail.gmail.com' \
    --to=dh.herrmann@googlemail.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jkosina@suse.cz \
    --cc=linux-input@vger.kernel.org \
    --cc=padovan@profusion.mobi \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.