linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* second race in hiddev
@ 2009-01-09 10:21 Oliver Neukum
       [not found] ` <200901091121.56576.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Oliver Neukum @ 2009-01-09 10:21 UTC (permalink / raw)
  To: Jiri Kosina, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, Alan Stern

Hi,

upon further thought this code is still racy.

	retval = usb_register_dev(usbhid->intf, &hiddev_class);

here you open a window during which open can happen

	if (retval) {
		err_hid("Not able to get a minor for this device.");
		hid->hiddev = NULL;
		kfree(hiddev);
		return -1;
	} else {
		hid->minor = usbhid->intf->minor;
		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;

and will fail because hiddev_table hasn't been updated
	}

The obvious fix of using a mutex to guard hiddev_table doesn't work because
usb_open() and usb_register_dev() take minor_rwsem and we'd have an AB-BA
deadlock. We need a lock usb_open() also takes in the right order and that leaves
only one option, BKL. I don't like it but I see no alternative.

	Regards
		Oliver

Signed-off-by: Oliver Neukum <oneukum-l3A5Bk7waGM@public.gmane.org>

---

@@ -878,16 +878,19 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
 	hiddev->hid = hid;
 	hiddev->exist = 1;
 
+	lock_kernel();
 	retval = usb_register_dev(usbhid->intf, &hiddev_class);
 	if (retval) {
 		err_hid("Not able to get a minor for this device.");
 		hid->hiddev = NULL;
+		unlock_kernel();
 		kfree(hiddev);
 		return -1;
 	} else {
 		hid->minor = usbhid->intf->minor;
 		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
 	}
+	unlock_kernel();
 
 	return 0;
 }
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: second race in hiddev
       [not found] ` <200901091121.56576.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
@ 2009-01-21  9:05   ` Jiri Kosina
  2009-01-21  9:26     ` Oliver Neukum
  0 siblings, 1 reply; 4+ messages in thread
From: Jiri Kosina @ 2009-01-21  9:05 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, Alan Stern

On Fri, 9 Jan 2009, Oliver Neukum wrote:

> upon further thought this code is still racy.
> 
> 	retval = usb_register_dev(usbhid->intf, &hiddev_class);
> 
> here you open a window during which open can happen
> 
> 	if (retval) {
> 		err_hid("Not able to get a minor for this device.");
> 		hid->hiddev = NULL;
> 		kfree(hiddev);
> 		return -1;
> 	} else {
> 		hid->minor = usbhid->intf->minor;
> 		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
> 
> and will fail because hiddev_table hasn't been updated

Indeed, thanks for catching that. It's a small race window and not very 
probably to be hit (or users aren't that fast, right? :) ).

> The obvious fix of using a mutex to guard hiddev_table doesn't work 
> because usb_open() and usb_register_dev() take minor_rwsem and we'd have 
> an AB-BA deadlock. We need a lock usb_open() also takes in the right 
> order and that leaves only one option, BKL. I don't like it but I see no 
> alternative.
[ ... ]
> @@ -878,16 +878,19 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
>  	hiddev->hid = hid;
>  	hiddev->exist = 1;
>  
> +	lock_kernel();
>  	retval = usb_register_dev(usbhid->intf, &hiddev_class);
>  	if (retval) {
>  		err_hid("Not able to get a minor for this device.");
>  		hid->hiddev = NULL;
> +		unlock_kernel();
>  		kfree(hiddev);
>  		return -1;
>  	} else {
>  		hid->minor = usbhid->intf->minor;
>  		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
>  	}
> +	unlock_kernel();

This is really not nice and I would like to avoid pulling BKL in as much 
as possible.

What exactly is the lock_kernel() in usb_open() protecting from anyway? 
Why isn't minor_rwsem sufficient protection?

-- 
Jiri Kosina
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: second race in hiddev
  2009-01-21  9:05   ` Jiri Kosina
@ 2009-01-21  9:26     ` Oliver Neukum
       [not found]       ` <200901211026.35066.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Oliver Neukum @ 2009-01-21  9:26 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-usb, linux-input, Alan Stern

Am Wednesday 21 January 2009 10:05:22 schrieb Jiri Kosina:
> On Fri, 9 Jan 2009, Oliver Neukum wrote:
> 
> > upon further thought this code is still racy.
> > 
> > 	retval = usb_register_dev(usbhid->intf, &hiddev_class);
> > 
> > here you open a window during which open can happen
> > 
> > 	if (retval) {
> > 		err_hid("Not able to get a minor for this device.");
> > 		hid->hiddev = NULL;
> > 		kfree(hiddev);
> > 		return -1;
> > 	} else {
> > 		hid->minor = usbhid->intf->minor;
> > 		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
> > 
> > and will fail because hiddev_table hasn't been updated
> 
> Indeed, thanks for catching that. It's a small race window and not very 
> probably to be hit (or users aren't that fast, right? :) ).

Users may not be that fast. Udev scripts may be. At least I hope we
want our udev fast and we've seen SMIs running for hundreds
of milliseconds.

> > The obvious fix of using a mutex to guard hiddev_table doesn't work 
> > because usb_open() and usb_register_dev() take minor_rwsem and we'd have 
> > an AB-BA deadlock. We need a lock usb_open() also takes in the right 
> > order and that leaves only one option, BKL. I don't like it but I see no 
> > alternative.
> [ ... ]
> > @@ -878,16 +878,19 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
> >  	hiddev->hid = hid;
> >  	hiddev->exist = 1;
> >  
> > +	lock_kernel();
> >  	retval = usb_register_dev(usbhid->intf, &hiddev_class);
> >  	if (retval) {
> >  		err_hid("Not able to get a minor for this device.");
> >  		hid->hiddev = NULL;
> > +		unlock_kernel();
> >  		kfree(hiddev);
> >  		return -1;
> >  	} else {
> >  		hid->minor = usbhid->intf->minor;
> >  		hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
> >  	}
> > +	unlock_kernel();
> 
> This is really not nice and I would like to avoid pulling BKL in as much 
> as possible.
> 
> What exactly is the lock_kernel() in usb_open() protecting from anyway?

I guess it wasn't removed because
a) disconnect() used to take BKL
b) nobody was ready to check all open() methods for dependency on BKL
 
> Why isn't minor_rwsem sufficient protection?

It is dropped too early. It is held only while a device is registered, not
during enough of probing.

	Regards
		Oliver

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: second race in hiddev
       [not found]       ` <200901211026.35066.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
@ 2009-02-12 12:21         ` Jiri Kosina
  0 siblings, 0 replies; 4+ messages in thread
From: Jiri Kosina @ 2009-02-12 12:21 UTC (permalink / raw)
  To: Oliver Neukum
  Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA, Alan Stern

On Wed, 21 Jan 2009, Oliver Neukum wrote:

> I guess it wasn't removed because
> a) disconnect() used to take BKL
> b) nobody was ready to check all open() methods for dependency on BKL
>  
> > Why isn't minor_rwsem sufficient protection?
> 
> It is dropped too early. It is held only while a device is registered, not
> during enough of probing.

There really doesn't seem to be any other option with usb_open() relying 
on lock_kernel() still.

I have added comment to the code and applied the patch, thanks a lot 
Oliver.

-- 
Jiri Kosina
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-02-12 12:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-09 10:21 second race in hiddev Oliver Neukum
     [not found] ` <200901091121.56576.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2009-01-21  9:05   ` Jiri Kosina
2009-01-21  9:26     ` Oliver Neukum
     [not found]       ` <200901211026.35066.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2009-02-12 12:21         ` Jiri Kosina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).