Commit f0992098 authored by Samuel Thibault's avatar Samuel Thibault Committed by Greg Kroah-Hartman

speakup: Reject setting the speakup line discipline outside of speakup

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: default avatarShisong Qin <qinshisong1205@gmail.com>
Signed-off-by: default avatarSamuel Thibault <samuel.thibault@ens-lyon.org>
Tested-by: default avatarShisong Qin <qinshisong1205@gmail.com>
Link: https://lore.kernel.org/r/20201129193523.hm3f6n5xrn6fiyyc@functionSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b6505459
......@@ -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;
}
......@@ -191,10 +184,26 @@ 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)
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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment