summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2020-07-14 14:33:07 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2020-07-14 14:33:07 +0000
commit3af178079cbe2efbfa4a5c1c6b27dd6296e47c08 (patch)
treea471eda4be20da858a8cd336b1041071980e4aee /sys/kern
parent40c32dad49745b2ea3e9f37862e029f6c228782a (diff)
A pty write containing VDISCARD, VREPRINT, or various retyping cases of
VERASE would perform (sometimes irrelevant) compute in the kernel which can be heavy (especially with our insufficient tty subsystem locking). Use tsleep_nsec for 1 tick in such circumstances to yield cpu, and also bring interruptability to ptcwrite() https://syzkaller.appspot.com/bug?extid=462539bc18fef8fc26cc ok kettenis millert, discussions with greg and anton
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/tty.c55
-rw-r--r--sys/kern/tty_pty.c6
2 files changed, 36 insertions, 25 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 08b44aff92d..7e9f7b0982f 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.157 2020/06/15 15:29:40 mpi Exp $ */
+/* $OpenBSD: tty.c,v 1.158 2020/07/14 14:33:03 deraadt Exp $ */
/* $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $ */
/*-
@@ -227,14 +227,15 @@ ttyclose(struct tty *tp)
/*
- * Process input of a single character received on a tty.
+ * Process input of a single character received on a tty. Returns 0 for
+ * simple operations, 1 for costly ones (ptcwrite needs to know).
*/
int
ttyinput(int c, struct tty *tp)
{
int iflag, lflag;
u_char *cc;
- int i, error;
+ int i, error, ret = 0;
int s;
enqueue_randomness(tp->t_dev << 8 | c);
@@ -342,7 +343,7 @@ parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
ttyflush(tp, FWRITE);
ttyecho(c, tp);
if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
- ttyretype(tp);
+ ret = ttyretype(tp);
SET(tp->t_lflag, FLUSHO);
}
goto startoutput;
@@ -443,7 +444,7 @@ parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
*/
if (CCEQ(cc[VERASE], c)) {
if (tp->t_rawq.c_cc)
- ttyrub(unputc(&tp->t_rawq), tp);
+ ret = ttyrub(unputc(&tp->t_rawq), tp);
goto endcase;
}
/*
@@ -452,10 +453,11 @@ parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
if (CCEQ(cc[VKILL], c)) {
if (ISSET(lflag, ECHOKE) &&
tp->t_rawq.c_cc == tp->t_rocount &&
- !ISSET(lflag, ECHOPRT))
+ !ISSET(lflag, ECHOPRT)) {
while (tp->t_rawq.c_cc)
- ttyrub(unputc(&tp->t_rawq), tp);
- else {
+ if (ttyrub(unputc(&tp->t_rawq), tp))
+ ret = 1;
+ } else {
ttyecho(c, tp);
if (ISSET(lflag, ECHOK) ||
ISSET(lflag, ECHOKE))
@@ -477,14 +479,16 @@ parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
* erase whitespace
*/
while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
- ttyrub(c, tp);
+ if (ttyrub(c, tp))
+ ret = 1;
if (c == -1)
goto endcase;
/*
* erase last char of word and remember the
* next chars type (for ALTWERASE)
*/
- ttyrub(c, tp);
+ if (ttyrub(c, tp))
+ ret = 1;
c = unputc(&tp->t_rawq);
if (c == -1)
goto endcase;
@@ -497,7 +501,8 @@ parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
* erase rest of word
*/
do {
- ttyrub(c, tp);
+ if (ttyrub(c, tp))
+ ret = 1;
c = unputc(&tp->t_rawq);
if (c == -1)
goto endcase;
@@ -510,7 +515,7 @@ parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
* reprint line (^R)
*/
if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
- ttyretype(tp);
+ ret = ttyretype(tp);
goto endcase;
}
/*
@@ -577,12 +582,13 @@ endcase:
*/
if (ISSET(tp->t_state, TS_TTSTOP) &&
!ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
- return (0);
+ return (ret);
restartoutput:
CLR(tp->t_lflag, FLUSHO);
CLR(tp->t_state, TS_TTSTOP);
startoutput:
- return (ttstart(tp));
+ ttstart(tp);
+ return (ret);
}
/*
@@ -1895,7 +1901,7 @@ ovhiwat:
* Rubout one character from the rawq of tp
* as cleanly as possible.
*/
-void
+int
ttyrub(int c, struct tty *tp)
{
u_char *cp;
@@ -1903,15 +1909,14 @@ ttyrub(int c, struct tty *tp)
int tabc, s;
if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
- return;
+ return 0;
CLR(tp->t_lflag, FLUSHO);
if (ISSET(tp->t_lflag, ECHOE)) {
if (tp->t_rocount == 0) {
/*
* Screwed by ttwrite; retype
*/
- ttyretype(tp);
- return;
+ return ttyretype(tp);
}
if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
ttyrubo(tp, 2);
@@ -1930,10 +1935,8 @@ ttyrub(int c, struct tty *tp)
ttyrubo(tp, 2);
break;
case TAB:
- if (tp->t_rocount < tp->t_rawq.c_cc) {
- ttyretype(tp);
- return;
- }
+ if (tp->t_rocount < tp->t_rawq.c_cc)
+ return ttyretype(tp);
s = spltty();
savecol = tp->t_column;
SET(tp->t_state, TS_CNTTB);
@@ -1971,6 +1974,7 @@ ttyrub(int c, struct tty *tp)
} else
ttyecho(tp->t_cc[VERASE], tp);
--tp->t_rocount;
+ return 0;
}
/*
@@ -1992,7 +1996,7 @@ ttyrubo(struct tty *tp, int cnt)
* Reprint the rawq line. Note, it is assumed that c_cc has already
* been checked.
*/
-void
+int
ttyretype(struct tty *tp)
{
u_char *cp;
@@ -2014,6 +2018,11 @@ ttyretype(struct tty *tp)
tp->t_rocount = tp->t_rawq.c_cc;
tp->t_rocol = 0;
+ /*
+ * Yield because of expense, or possible ptcwrite() injection flood.
+ * Also check for interrupt, and return upwards.
+ */
+ return tsleep_nsec(tp, TTIPRI | PCATCH, "ttyretype", 1);
}
/*
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c
index 18c6a058005..11cfb3c2aad 100644
--- a/sys/kern/tty_pty.c
+++ b/sys/kern/tty_pty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty_pty.c,v 1.101 2020/06/22 13:14:32 mpi Exp $ */
+/* $OpenBSD: tty_pty.c,v 1.102 2020/07/14 14:33:03 deraadt Exp $ */
/* $NetBSD: tty_pty.c,v 1.33.4.1 1996/06/02 09:08:11 mrg Exp $ */
/*
@@ -564,7 +564,8 @@ again:
wakeup(&tp->t_rawq);
goto block;
}
- (*linesw[tp->t_line].l_rint)(*cp++, tp);
+ if ((*linesw[tp->t_line].l_rint)(*cp++, tp) == EINTR)
+ goto interrupt;
cnt++;
cc--;
}
@@ -591,6 +592,7 @@ block:
if (error == 0)
goto again;
+interrupt:
/* adjust for data copied in but not written */
uio->uio_resid += cc;
done: