diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2020-07-14 14:33:07 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2020-07-14 14:33:07 +0000 |
commit | 3af178079cbe2efbfa4a5c1c6b27dd6296e47c08 (patch) | |
tree | a471eda4be20da858a8cd336b1041071980e4aee /sys/kern | |
parent | 40c32dad49745b2ea3e9f37862e029f6c228782a (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.c | 55 | ||||
-rw-r--r-- | sys/kern/tty_pty.c | 6 |
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: |