speakup: Reject setting the speakup line discipline outside of speakup
commit f0992098ca
upstream.
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>
This commit is contained in:
parent
a2a163f70b
commit
b0d4fa10bf
@ -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(struct spk_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;
|
||||
}
|
||||
@ -189,9 +182,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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user