Re: [PATCH] usb: fix possible oops in serial option driver

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

 



On 17:09 Wed 23 May     , Johan Hovold wrote:
> On Wed, May 23, 2012 at 07:12:39AM +0200, Jan Safrata wrote:
> > On 16:06 Tue 22 May     , Johan Hovold wrote:
> > > On Tue, May 22, 2012 at 02:04:37PM +0200, Jan Safrata wrote:
> > > > Call Trace:
> > > >  [<f85e7c60>] usb_wwan_dtr_rts+0x60/0xa0 [usb_wwan]
> > > 
> > > This is not right. You're fixing a race with disconnect in option's
> > > probe, but this indicates that there's a race with usb_wwan_dtr_rts (as
> > > well).
> >
> > > > @@ -1478,10 +1478,14 @@ static int option_send_setup(struct usb_serial_port *port)
> > > >  	struct usb_wwan_intf_private *intfdata =
> > > >  		(struct usb_wwan_intf_private *) serial->private;
> > > >  	struct usb_wwan_port_private *portdata;
> > > > -	int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
> > > > +	int ifNum;
> > > >  	int val = 0;
> > > >  	dbg("%s", __func__);
> > > >  
> > > > +	if (serial->disconnected)
> > > > +		return -ENODEV;
> > > > +
> > > > +	ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
> > > >  	if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
> > > >  			(struct option_blacklist_info *) intfdata->private)) {
> > > >  		dbg("No send_setup on blacklisted interface #%d\n", ifNum);
> > > 
> > > This is not quite right. You need to use the disconnect mutex as well,
> > > e.g.:
> > > 
> > > 	mutex_lock(&serial->disc_mutex);
> > > 	if (serial->disconnected) {
> > > 		mutex_unlock(&serial->disc_mutex);
> > > 		return -ENODEV;
> > > 	}
> > > 	ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
> > > 	...
> > > 	ret = usb_control_msg(serial->dev, ...)
> > > 	mutex_unlock(&serial->disc_mutex);
> > > 
> > > 	return ret;
> > > 
> > > Johan
> > 
> > The mutex cannot be used in the option_send_setup() function, because it
> > is already held in usb_wwan_dtr_rts() which calls the option_send_setup(),
> > so simple check of serial->disconnected flag should be ok there.
> 
> Ah. I misread option_probe (only sets the send_setup pointer).
> 
> Hmmm. And you can't push the locking down into send_setup because it's
> also called from open (which is also called with disc_mutex held)...
> 
> What about the other call sites in usb_wwan (in set_termios and tiocmset)?
> Shouldn't these be protected by the disc_mutex as well? And wouldn't it
> then be cleaner to check the disconnected flag where the lock is taken
> (i.e., in usb_wwan)?

I've also thought about set_termios and tiocmset, but it seems that the
oops does not happen with them - I guess that's because tty_vhangup() is
called from usb_serial_disconnect(), replacing tty fops with
hung_up_tty_fops, so that set_termios and tiocmset could not be called
anymore (from tty ioctl).

The oops I was trying to fix happens only with open() and only when the
tty device is already opened at least one time (as the code to reproduce
demonstrates). In that case tty_open() calls tty_release() getting to
usb_wwan_dtr_rts() in disconnected state.

My understanding of locking in tty layer and it's subdrivers is not so deep
so I did not dare to change something in that - it might be that checking of
serial->disconnected would not be needed in option_send_setup() nor in
usb_wwan_dtr_rts() if the protection via hung_up_tty_fops would not
leave a hole in tty_open/tty_release. Maybe the proper fix should be
done somewhere in tty_release/tty_port_close_start/tty_port_lower_dtr_rts?

Jan

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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux