Skip to content

Commit f099209

Browse files
sthibaulgregkh
authored andcommitted
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: [email protected] Reported-by: Shisong Qin <[email protected]> Signed-off-by: Samuel Thibault <[email protected]> Tested-by: Shisong Qin <[email protected]> Link: https://lore.kernel.org/r/20201129193523.hm3f6n5xrn6fiyyc@function Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b650545 commit f099209

File tree

1 file changed

+23
-14
lines changed

1 file changed

+23
-14
lines changed

drivers/accessibility/speakup/spk_ttyio.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,20 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty)
4747
{
4848
struct spk_ldisc_data *ldisc_data;
4949

50+
if (tty != speakup_tty)
51+
/* Somebody tried to use this line discipline outside speakup */
52+
return -ENODEV;
53+
5054
if (!tty->ops->write)
5155
return -EOPNOTSUPP;
5256

53-
mutex_lock(&speakup_tty_mutex);
54-
if (speakup_tty) {
55-
mutex_unlock(&speakup_tty_mutex);
56-
return -EBUSY;
57-
}
58-
speakup_tty = tty;
59-
6057
ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
61-
if (!ldisc_data) {
62-
speakup_tty = NULL;
63-
mutex_unlock(&speakup_tty_mutex);
58+
if (!ldisc_data)
6459
return -ENOMEM;
65-
}
6660

6761
init_completion(&ldisc_data->completion);
6862
ldisc_data->buf_free = true;
69-
speakup_tty->disc_data = ldisc_data;
70-
mutex_unlock(&speakup_tty_mutex);
63+
tty->disc_data = ldisc_data;
7164

7265
return 0;
7366
}
@@ -191,9 +184,25 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
191184

192185
tty_unlock(tty);
193186

187+
mutex_lock(&speakup_tty_mutex);
188+
speakup_tty = tty;
194189
ret = tty_set_ldisc(tty, N_SPEAKUP);
195190
if (ret)
196-
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
191+
speakup_tty = NULL;
192+
mutex_unlock(&speakup_tty_mutex);
193+
194+
if (!ret)
195+
/* Success */
196+
return 0;
197+
198+
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
199+
200+
tty_lock(tty);
201+
if (tty->ops->close)
202+
tty->ops->close(tty, NULL);
203+
tty_unlock(tty);
204+
205+
tty_kclose(tty);
197206

198207
return ret;
199208
}

0 commit comments

Comments
 (0)