Skip to content

Commit

Permalink
speakup: Reject setting the speakup line discipline outside of speakup
Browse files Browse the repository at this point in the history
Speakup exposing a line discipline allows userland to try to use it,
while it is deemed to be useless, and thus uselessly exposes potential
bugs. One of them is simply that in such a case if the line sends data,
spk_ttyio_receive_buf2 is called and crashes since spk_ttyio_synth
is NULL.

This change restricts the use of the speakup line discipline to
speakup drivers, thus avoiding such kind of issues altogether.

Cc: stable@vger.kernel.org
Reported-by: Shisong Qin <qinshisong1205@gmail.com>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Tested-by: Shisong Qin <qinshisong1205@gmail.com>
Link: https://lore.kernel.org/r/20201129193523.hm3f6n5xrn6fiyyc@function
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Samuel Thibault authored and Greg Kroah-Hartman committed Nov 30, 2020
1 parent b650545 commit f099209
Showing 1 changed file with 23 additions and 14 deletions.
37 changes: 23 additions & 14 deletions drivers/accessibility/speakup/spk_ttyio.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,20 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty)
{
struct spk_ldisc_data *ldisc_data;

if (tty != speakup_tty)
/* Somebody tried to use this line discipline outside speakup */
return -ENODEV;

if (!tty->ops->write)
return -EOPNOTSUPP;

mutex_lock(&speakup_tty_mutex);
if (speakup_tty) {
mutex_unlock(&speakup_tty_mutex);
return -EBUSY;
}
speakup_tty = tty;

ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
if (!ldisc_data) {
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);
if (!ldisc_data)
return -ENOMEM;
}

init_completion(&ldisc_data->completion);
ldisc_data->buf_free = true;
speakup_tty->disc_data = ldisc_data;
mutex_unlock(&speakup_tty_mutex);
tty->disc_data = ldisc_data;

return 0;
}
Expand Down Expand Up @@ -191,9 +184,25 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)

tty_unlock(tty);

mutex_lock(&speakup_tty_mutex);
speakup_tty = tty;
ret = tty_set_ldisc(tty, N_SPEAKUP);
if (ret)
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);

if (!ret)
/* Success */
return 0;

pr_err("speakup: Failed to set N_SPEAKUP on tty\n");

tty_lock(tty);
if (tty->ops->close)
tty->ops->close(tty, NULL);
tty_unlock(tty);

tty_kclose(tty);

return ret;
}
Expand Down

0 comments on commit f099209

Please sign in to comment.