From nobody Tue Jan 30 17:11:27 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4TPWsq6Jg7z59CPB; Tue, 30 Jan 2024 17:11:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4TPWsq3xCmz4DxP; Tue, 30 Jan 2024 17:11:27 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1706634687; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vRmso0ni+aXoI1Vt1ZYLVuq3GlLHpiFZPwDaP+Rdk5k=; b=ywneib5i+mE3Pvd2IndIHTetq8o3ZG8xmBQihuDu3FZlLFJDlP60kBlp1Uh75Ss93UMIaB q1CmAMPBg/xDCXcG90jKzCm6vrrKei08ZjtEySbRV8QJlCis6YqZqOM9R6u2RdD3SHKovs kdYPruB0KlimB6lhoJjDmck9KH/UcxVsingiVZiFQfbRn1EMDXZ/gHbjRI4EiZeWRgEY2/ IMcY303rio0jl8GBYnEI1GnxcuFSTjXuzskV9ZZ9Wd6NXxm/OoVP35x31+2kIIQSXrb8Mz LXu+Tzlh3dCfMDNyf9RWA+v+kQAmN+uZ/8/Nhdpb7idIKAqwNnNPVj1gPzo87Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1706634687; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=vRmso0ni+aXoI1Vt1ZYLVuq3GlLHpiFZPwDaP+Rdk5k=; b=YbX5mUqb9NzwNSjAi+VXd/gZBkQa+jkc/GAMDN3FXkmb4p2So5LnznOYIhiPNzdDSp/Iex hfa/jQ8hYT5UjV9tF8Ja99k+zd46oso3AShkXJbbv2f9qU1VX+1HQPA22AM/pKtDJljA3c oXfVqMgIUz/oK6Y+vmrOlXSbmCLUKAXvbtgSknQUVrcFn7jBQKW3pYh0yqSLiYvlkDcfFq Q9f5s1XteryRZnyaFjfPhjWDYDMJxou31cX1pv+sqB13fRtNUQM1dT9DNSijHCqffS+mT4 ZUqPoeEH8O3ARsuLQ2HZM2XOQ06uyOfVfKy/bcz8KRt8gwXK53lFQOj+4/B7sA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1706634687; a=rsa-sha256; cv=none; b=tN5fd/iNXafyv+kpdk7tvkp0Q496+z9jGQeiEJO6b41yrw/0CCtM0SaBJ7PkWUF0MsNbH/ oHGZsYJF7tQPlbuSKunMllNASGXJOukBd0UIkT0IqX42ZldiR/nRcgFA4fjqKJ3+GSUBAu am8G4jMxAieKs2nhMpwYNaiRundUQGjyPrfQCoZpPgX9ebvuHBJ5rkT8A5hwqvI6xRZMza aZ3NbszS+hRE7Zhr64+FjVgauPkov2/a/w5pCptPkKAK4loRebYjU3ECubJ9hnbjPKll16 4X+9L+OKO71CHuXjVc9KUk6f9TiWpG2yl4OQBQmFOEYC5M7mjm+afHNI7F1tcA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4TPWsq32DdzkZF; Tue, 30 Jan 2024 17:11:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 40UHBRuD093662; Tue, 30 Jan 2024 17:11:27 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 40UHBReA093659; Tue, 30 Jan 2024 17:11:27 GMT (envelope-from git) Date: Tue, 30 Jan 2024 17:11:27 GMT Message-Id: <202401301711.40UHBReA093659@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kyle Evans Subject: git: 050b4db5a8c1 - stable/13 - kern: tty: recanonicalize the buffer on ICANON/VEOF/VEOL changes List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 050b4db5a8c1a32a0c77391b7dc81ef5a2ef93f7 Auto-Submitted: auto-generated The branch stable/13 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=050b4db5a8c1a32a0c77391b7dc81ef5a2ef93f7 commit 050b4db5a8c1a32a0c77391b7dc81ef5a2ef93f7 Author: Kyle Evans AuthorDate: 2024-01-16 02:55:59 +0000 Commit: Kyle Evans CommitDate: 2024-01-30 17:11:10 +0000 kern: tty: recanonicalize the buffer on ICANON/VEOF/VEOL changes Before this change, we would canonicalize any partial input if the new local mode is not ICANON, but that's about it. If we were switching from -ICANON -> ICANON, or if VEOF/VEOL changes, then our internal canon accounting would be wrong. The main consequence of this is that in ICANON mode, we would potentially hang a read(2) longer if the new VEOF/VEOL appears later in the buffer, and FIONREAD would be similarly wrong as a result. Reviewed by: kib (cherry picked from commit 522083ffbd1ab9b485861750e889d606dc75ed0a) (cherry picked from commit 5738d741fb796c1f0a6b5c2157af7de58104ac97) --- sys/kern/tty.c | 22 +++++++++++++++++++--- sys/kern/tty_inq.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ sys/kern/tty_ttydisc.c | 22 ++++++++++++++++++++++ sys/sys/ttydisc.h | 1 + sys/sys/ttyqueue.h | 1 + 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/sys/kern/tty.c b/sys/kern/tty.c index d46462842038..d7f9a914166a 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -1703,6 +1703,7 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, case TIOCSETAW: case TIOCSETAF: { struct termios *t = data; + bool canonicalize = false; /* * Who makes up these funny rules? According to POSIX, @@ -1752,6 +1753,19 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, return (error); } + /* + * We'll canonicalize any partial input if we're transitioning + * ICANON one way or the other. If we're going from -ICANON -> + * ICANON, then in the worst case scenario we're in the middle + * of a line but both ttydisc_read() and FIONREAD will search + * for one of our line terminals. + */ + if ((t->c_lflag & ICANON) != (tp->t_termios.c_lflag & ICANON)) + canonicalize = true; + else if (tp->t_termios.c_cc[VEOF] != t->c_cc[VEOF] || + tp->t_termios.c_cc[VEOL] != t->c_cc[VEOL]) + canonicalize = true; + /* Copy new non-device driver parameters. */ tp->t_termios.c_iflag = t->c_iflag; tp->t_termios.c_oflag = t->c_oflag; @@ -1760,13 +1774,15 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, ttydisc_optimize(tp); + if (canonicalize) + ttydisc_canonicalize(tp); if ((t->c_lflag & ICANON) == 0) { /* * When in non-canonical mode, wake up all - * readers. Canonicalize any partial input. VMIN - * and VTIME could also be adjusted. + * readers. Any partial input has already been + * canonicalized above if we were in canonical mode. + * VMIN and VTIME could also be adjusted. */ - ttyinq_canonicalize(&tp->t_inq); tty_wakeup(tp, FREAD); } diff --git a/sys/kern/tty_inq.c b/sys/kern/tty_inq.c index 291a815fa2db..daf3bde77712 100644 --- a/sys/kern/tty_inq.c +++ b/sys/kern/tty_inq.c @@ -346,6 +346,55 @@ ttyinq_canonicalize(struct ttyinq *ti) ti->ti_startblock = ti->ti_reprintblock = ti->ti_lastblock; } +/* + * Canonicalize at one of the break characters; we'll work backwards from the + * lastblock to firstblock to try and find the latest one. + */ +void +ttyinq_canonicalize_break(struct ttyinq *ti, const char *breakc) +{ + struct ttyinq_block *tib = ti->ti_lastblock; + unsigned int canon, off; + unsigned int boff; + + /* No block, no change needed. */ + if (tib == NULL || ti->ti_end == 0) + return; + + /* Start just past the end... */ + off = ti->ti_end; + canon = ti->ti_begin; + + while (off > ti->ti_begin) { + off--; + boff = off % TTYINQ_DATASIZE; + + if (strchr(breakc, tib->tib_data[boff]) && !GETBIT(tib, boff)) { + canon = off + 1; + break; + } + + if (off != ti->ti_begin && boff == 0) + tib = tib->tib_prev; + } + + MPASS(canon > ti->ti_begin || off == ti->ti_begin); + + /* + * We should only be able to hit canon == ti_begin if we walked + * everything we have and didn't find any of the break characters, so + * if canon == ti_begin then tib is already the correct block and we + * should avoid touching it. + * + * For all other scenarios, if canon lies on a block boundary then tib + * has already advanced to the previous block. + */ + if (canon != ti->ti_begin && (canon % TTYINQ_DATASIZE) == 0) + tib = tib->tib_next; + ti->ti_linestart = ti->ti_reprint = canon; + ti->ti_startblock = ti->ti_reprintblock = tib; +} + size_t ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen, char *lastc) diff --git a/sys/kern/tty_ttydisc.c b/sys/kern/tty_ttydisc.c index 04d99c336438..92f75d672269 100644 --- a/sys/kern/tty_ttydisc.c +++ b/sys/kern/tty_ttydisc.c @@ -167,6 +167,28 @@ ttydisc_bytesavail(struct tty *tp) return (clen); } +void +ttydisc_canonicalize(struct tty *tp) +{ + char breakc[4]; + + /* + * If we're in non-canonical mode, it's as easy as just canonicalizing + * the current partial line. + */ + if (!CMP_FLAG(l, ICANON)) { + ttyinq_canonicalize(&tp->t_inq); + return; + } + + /* + * For canonical mode, we need to rescan the buffer for the last EOL + * indicator. + */ + ttydisc_read_break(tp, &breakc[0], sizeof(breakc)); + ttyinq_canonicalize_break(&tp->t_inq, breakc); +} + static int ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag) { diff --git a/sys/sys/ttydisc.h b/sys/sys/ttydisc.h index 81d436139555..cdd3576afedf 100644 --- a/sys/sys/ttydisc.h +++ b/sys/sys/ttydisc.h @@ -47,6 +47,7 @@ void ttydisc_close(struct tty *tp); size_t ttydisc_bytesavail(struct tty *tp); int ttydisc_read(struct tty *tp, struct uio *uio, int ioflag); int ttydisc_write(struct tty *tp, struct uio *uio, int ioflag); +void ttydisc_canonicalize(struct tty *tp); void ttydisc_optimize(struct tty *tp); /* Bottom half routines. */ diff --git a/sys/sys/ttyqueue.h b/sys/sys/ttyqueue.h index fd5a6bf7719e..89c07b7faa10 100644 --- a/sys/sys/ttyqueue.h +++ b/sys/sys/ttyqueue.h @@ -78,6 +78,7 @@ size_t ttyinq_write(struct ttyinq *ti, const void *buf, size_t len, int ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t len, int quote); void ttyinq_canonicalize(struct ttyinq *ti); +void ttyinq_canonicalize_break(struct ttyinq *ti, const char *breakc); size_t ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen, char *lastc); void ttyinq_flush(struct ttyinq *ti);