[patch v3] fix async usb removal

Samuel Thibault samuel.thibault at ens-lyon.org
Sat Aug 12 03:55:44 EDT 2017


Hello,

Okash Khawaja, on sam. 12 août 2017 08:49:02 +0100, wrote:
> When an external USB synth is unplugged while the module is loaded, we
> get a null pointer deref. This is because the tty disappears while
> speakup tries to use to to communicate with the synth. This patch fixes
> it by checking tty for null before using it. Since tty can become null
> between the check and its usage, a mutex is introduced. tty usage is
> now surrounded by the mutex, as is the code in speakup_ldisc_close which
> sets the tty to null. The mutex also serialises calls to tty from
> speakup code. 
> 
> In case of tty being null, this sets synth->alive to zero and starts
> ttys.

Perhaps rather say "restarts ttys in case they were stopped by speakup".

> Signed-off-by: Okash Khawaja <okash.khawaja at gmail.com>

Reviewed-by: Samuel Thibault <samuel.thibault at ens-lyon.org>

> ---
>  drivers/staging/speakup/spk_ttyio.c |   50 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
> 
> --- a/drivers/staging/speakup/spk_ttyio.c
> +++ b/drivers/staging/speakup/spk_ttyio.c
> @@ -15,6 +15,11 @@ struct spk_ldisc_data {
>  
>  static struct spk_synth *spk_ttyio_synth;
>  static struct tty_struct *speakup_tty;
> +/* mutex to protect against speakup_tty disappearing from underneath us while
> + * we are using it. this can happen when the device physically unplugged,
> + * while in use. it also serialises access to speakup_tty.
> + */
> +static DEFINE_MUTEX(speakup_tty_mutex);
>  
>  static int ser_to_dev(int ser, dev_t *dev_no)
>  {
> @@ -60,8 +65,10 @@ static int spk_ttyio_ldisc_open(struct t
>  
>  static void spk_ttyio_ldisc_close(struct tty_struct *tty)
>  {
> +	mutex_lock(&speakup_tty_mutex);
>  	kfree(speakup_tty->disc_data);
>  	speakup_tty = NULL;
> +	mutex_unlock(&speakup_tty_mutex);
>  }
>  
>  static int spk_ttyio_receive_buf2(struct tty_struct *tty,
> @@ -189,9 +196,11 @@ void spk_ttyio_unregister_ldisc(void)
>  
>  static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
>  {
> +	mutex_lock(&speakup_tty_mutex);
>  	if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
>  		int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
>  
> +		mutex_unlock(&speakup_tty_mutex);
>  		if (ret == 0)
>  			/* No room */
>  			return 0;
> @@ -207,17 +216,50 @@ static int spk_ttyio_out(struct spk_synt
>  		}
>  		return 1;
>  	}
> +
> +	mutex_unlock(&speakup_tty_mutex);
> +	return 0;
> +}
> +
> +static int check_tty(struct tty_struct *tty)
> +{
> +	if (!tty) {
> +		pr_warn("%s: I/O error, deactivating speakup\n",
> +			spk_ttyio_synth->long_name);
> +		/* No synth any more, so nobody will restart TTYs, and we thus
> +		 * need to do it ourselves.  Now that there is no synth we can
> +		 * let application flood anyway
> +		 */
> +		spk_ttyio_synth->alive = 0;
> +		speakup_start_ttys();
> +		return 1;
> +	}
> +
>  	return 0;
>  }
>  
>  static void spk_ttyio_send_xchar(char ch)
>  {
> +	mutex_lock(&speakup_tty_mutex);
> +	if (check_tty(speakup_tty)) {
> +		mutex_unlock(&speakup_tty_mutex);
> +		return;
> +	}
> +
>  	speakup_tty->ops->send_xchar(speakup_tty, ch);
> +	mutex_unlock(&speakup_tty_mutex);
>  }
>  
>  static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
>  {
> +	mutex_lock(&speakup_tty_mutex);
> +	if (check_tty(speakup_tty)) {
> +		mutex_unlock(&speakup_tty_mutex);
> +		return;
> +	}
> +
>  	speakup_tty->ops->tiocmset(speakup_tty, set, clear);
> +	mutex_unlock(&speakup_tty_mutex);
>  }
>  
>  static unsigned char ttyio_in(int timeout)
> @@ -257,8 +299,16 @@ static unsigned char spk_ttyio_in_nowait
>  
>  static void spk_ttyio_flush_buffer(void)
>  {
> +	mutex_lock(&speakup_tty_mutex);
> +	if (check_tty(speakup_tty)) {
> +		mutex_unlock(&speakup_tty_mutex);
> +		return;
> +	}
> +
>  	if (speakup_tty->ops->flush_buffer)
>  		speakup_tty->ops->flush_buffer(speakup_tty);
> +
> +	mutex_unlock(&speakup_tty_mutex);
>  }
>  
>  int spk_ttyio_synth_probe(struct spk_synth *synth)
> 

-- 
Samuel
As usual, this being a 1.3.x release, I haven't even compiled this
kernel yet.  So if it works, you should be doubly impressed.
(Linus Torvalds, announcing kernel 1.3.3 on the linux-kernel mailing list.)


More information about the Speakup mailing list