From nobody Tue Jan 16 02:56: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 4TDYYl3dNyz56Sb1; Tue, 16 Jan 2024 02:56: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 4TDYYl20wVz4fCK; Tue, 16 Jan 2024 02:56:27 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1705373787; 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=nnEj9LUWNTZNm+gpJq5OnzsRmntirj+ng89sHy0YuQ0=; b=h960KVtTZsxNjxSKKBRlqeIGuMtfTgujDCLV5gosU27Gzm6kFa6y0/UxE+/LVK2K1bo+T4 n0vTMgt0a6NqFEjVm/osEv7NITRubO+/RxDBsIkbyet4BxsiuchbG0HsE7JsqVPs2fP/08 BKPt+x9DeKToUWAyloev5bQRV8KmbqRa9NJdomeIJbJL9W4AXxdtwPWb42jDaRl6v3hgnW h05q0KBTImYJ4Uol1K4+I9LNaCPzyfB6D5vI7CRz6lUuUcIxFaSSlw6/Cn+zfqORp4Dfi8 Aj2GGI48Ba0RiSCRZseUHTQWiIlC1GuwBpWqWchMUZv5dKVFYZ4YtU/9I9c7Ig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1705373787; 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=nnEj9LUWNTZNm+gpJq5OnzsRmntirj+ng89sHy0YuQ0=; b=Sb2lm/KlsaqjYx9JRmycna659KGf/b/G1IRX1RXl/3ZUz52RRGA+xzBOeJmNHMit2jR4BX XZ/2LY6Oo2EIh9UBXBP0b37wOnuAYyxPixZI2VpG1u3eRqM+q5fzIOx1JxbmjZ5ke/gdn3 B/DCiGqsN4S3R7tzWktNqzlNhIEJSbl79aVPOCBb9rowLyoWVAt6EKCt1hVAB3Tpx3RFVs jRS8BqC55dYsDRGSNQRDlWS8KC6KDdCDmE0KHd8fETzStz5RGK6xWN8ZIuPv/WuMpdXl7l ORr3Vm3w4J4akjuc4iYycOMNAFQRF1wgv4kzH24trvArOjT1d1Q+S7jxPMxCBA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1705373787; a=rsa-sha256; cv=none; b=mR6sXRh4j37AKFbqFvqM5ntU4P/FygfwbXcP7pzqtM7+EhG4PVVlk2Gd3yg3btoI6Lsuzv dYnPMoFLccU5XzbXiUJ+KP1O1CZSPvy/gv/9hW/otA1ugv2N2ui3rIstvWssoevzEHsSi9 dyPpx3el3OUzzmbnKvcD1u8qJwhlyQEnqioHXyG/us1Lq0NR/Lygp2q8Yfu161DqekOVDE ZSc0rrGRdWkvYY2ifRNGM+fNuhJNYFqMVh9jO6EMk/hKvG+ZsQAIEKA6xWnBE7AUKGmrQw 5RCrxUU56NJ5RU7Wvzq3WQNKFOs/P2ddIB7QJKMAuKeeEI4De2xo82rvBdHLUw== 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 4TDYYl13X5zMVp; Tue, 16 Jan 2024 02:56: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 40G2uR6T071553; Tue, 16 Jan 2024 02:56:27 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 40G2uRMK071550; Tue, 16 Jan 2024 02:56:27 GMT (envelope-from git) Date: Tue, 16 Jan 2024 02:56:27 GMT Message-Id: <202401160256.40G2uRMK071550@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kyle Evans Subject: git: 522083ffbd1a - main - 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/main X-Git-Reftype: branch X-Git-Commit: 522083ffbd1ab9b485861750e889d606dc75ed0a Auto-Submitted: auto-generated The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=522083ffbd1ab9b485861750e889d606dc75ed0a commit 522083ffbd1ab9b485861750e889d606dc75ed0a Author: Kyle Evans AuthorDate: 2024-01-16 02:55:59 +0000 Commit: Kyle Evans CommitDate: 2024-01-16 02:55:59 +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 Differential Revision: https://reviews.freebsd.org/D43456 --- 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 e4186a67cb31..29bb092a50b0 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -1705,6 +1705,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, @@ -1754,6 +1755,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; @@ -1762,13 +1776,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 2eed9802a7b7..533fdfd30ce9 100644 --- a/sys/kern/tty_inq.c +++ b/sys/kern/tty_inq.c @@ -354,6 +354,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 = 0; + + while (off > 0) { + if ((off % TTYINQ_DATASIZE) == 0) + tib = tib->tib_prev; + + off--; + boff = off % TTYINQ_DATASIZE; + + if (strchr(breakc, tib->tib_data[boff]) && !GETBIT(tib, boff)) { + canon = off + 1; + break; + } + } + + MPASS(canon > 0 || off == 0); + + /* + * We should only be able to hit bcanon == 0 if we walked everything we + * have and didn't find any of the break characters, so if bcanon == 0 + * 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 != 0 && (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 f6e9e9869951..2be6b560d4f4 100644 --- a/sys/kern/tty_ttydisc.c +++ b/sys/kern/tty_ttydisc.c @@ -166,6 +166,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);