Received: by 2002:ac0:e34a:0:0:0:0:0 with SMTP id g10csp483316imn; Wed, 27 Jul 2022 11:27:51 -0700 (PDT) X-Google-Smtp-Source: AGRyM1v80It4bx4J9NRd28HmHdny+XaW9nZMdEzdKO7Ds8KELwD2JPC5G7SesUyqCmVcmkgau8pV X-Received: by 2002:a05:6402:b72:b0:43c:81c2:dd3f with SMTP id cb18-20020a0564020b7200b0043c81c2dd3fmr8190456edb.19.1658946471580; Wed, 27 Jul 2022 11:27:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658946471; cv=none; d=google.com; s=arc-20160816; b=KsuNRndbVo+9DHxfPRjE/yK3efbecE1an3dj5hQ988OYHI86c+ik/YVQXNGochq1cd LDmPgxynvXxQWfhch8bd64CayipvfBU0Z1iIvMcftF0wJVnDRVvELO055aNxRfEwxkES XdljnijTSKuMoGwFA2D08lgz9OKkwfCetN3zgh3s2nViBRAfnBOSe3KPiksElZCKUq8D Ql3RJY6DYkRo3xbVgzMKxxZP0oBIPhWIACKAnkGz6fK5iFvKvJgTnrxDG7eLvPxtReD9 Xx6felIDO4M24bcv4u8rtyzfnBJh2rhWMHvK6VteTryAoqccZW9p8kFyUBsVJcsxCFMO ZD8A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=UWFMDthJAJlhQsmwgtTDcLobUuooPhkHLoV56bLrcv8=; b=eJXdY5S9Qh/ovR/BE59A0s/EGMvl0Rjuz5EWXWw/xmx61dwKowcT1UOOoqE+JYKp7Z LXgP6zZl3KQTR2S16iakBRLy/IfXo0CxezWISsqU5GB268PXDyJcamsq6aeomvS/a6CD vxKRuhx5EfcCYFOuA110sBJZKorf09+dDuvRtKD6pbKcvb5kUN4diCT4xad6Z1jcgDZB bnUsbDn3WatVxuqFB0/sAEyLQLDd6MAefsNuFU+23bwWu6HZkcI3tVRQce0XEtVEovRL FXDJjODrK/tk+6aJVTwlnA52woK8kByg1itssv7+ki8hXN5nDv5jV9sz4xDVj36OO2ZO 135g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=OPogxZDL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ho9-20020a1709070e8900b0072b14352ab5si23827111ejc.537.2022.07.27.11.27.25; Wed, 27 Jul 2022 11:27:51 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=OPogxZDL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236979AbiG0Q2t (ORCPT + 99 others); Wed, 27 Jul 2022 12:28:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33722 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236858AbiG0Q2Q (ORCPT ); Wed, 27 Jul 2022 12:28:16 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE24E4E60B; Wed, 27 Jul 2022 09:24:32 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 173C3B821C3; Wed, 27 Jul 2022 16:24:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 648AEC433D7; Wed, 27 Jul 2022 16:24:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1658939048; bh=vRx21NnLPZl7+o4uI9ZwbPi7+raC388cP0/RK0DNuNo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OPogxZDLavEGSrIs0kGpDxKHTtG1mZaDeWDmV8Gz+RblFmSqKUSvDzmPAKTTchYbl /AyZE35EFssoe2cn9fmUIyXRBPyYZc+v45m0LLQRh4bKw4lF4K2uu0cKFxJq+ntVSl 5bMg9ekvdR9o2KHjZ8o8lImqrLqBfv60pJzHN8UI= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, =?UTF-8?q?=E4=B8=80=E5=8F=AA=E7=8B=97?= , Dan Carpenter , Hillf Danton , Jiri Slaby Subject: [PATCH 4.14 32/37] tty: use new tty_insert_flip_string_and_push_buffer() in pty_write() Date: Wed, 27 Jul 2022 18:10:58 +0200 Message-Id: <20220727161002.154912200@linuxfoundation.org> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220727161000.822869853@linuxfoundation.org> References: <20220727161000.822869853@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jiri Slaby commit a501ab75e7624d133a5a3c7ec010687c8b961d23 upstream. There is a race in pty_write(). pty_write() can be called in parallel with e.g. ioctl(TIOCSTI) or ioctl(TCXONC) which also inserts chars to the buffer. Provided, tty_flip_buffer_push() in pty_write() is called outside the lock, it can commit inconsistent tail. This can lead to out of bounds writes and other issues. See the Link below. To fix this, we have to introduce a new helper called tty_insert_flip_string_and_push_buffer(). It does both tty_insert_flip_string() and tty_flip_buffer_commit() under the port lock. It also calls queue_work(), but outside the lock. See 71a174b39f10 (pty: do tty_flip_buffer_push without port->lock in pty_write) for the reasons. Keep the helper internal-only (in drivers' tty.h). It is not intended to be used widely. Link: https://seclists.org/oss-sec/2022/q2/155 Fixes: 71a174b39f10 (pty: do tty_flip_buffer_push without port->lock in pty_write) Cc: 一只狗 Cc: Dan Carpenter Suggested-by: Hillf Danton Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20220707082558.9250-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 14 ++------------ drivers/tty/tty_buffer.c | 31 +++++++++++++++++++++++++++++++ include/linux/tty_flip.h | 3 +++ 3 files changed, 36 insertions(+), 12 deletions(-) --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_st static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; - unsigned long flags; - if (tty->stopped) + if (tty->stopped || !c) return 0; - if (c > 0) { - spin_lock_irqsave(&to->port->lock, flags); - /* Stuff the data into the input queue of the other end */ - c = tty_insert_flip_string(to->port, buf, c); - spin_unlock_irqrestore(&to->port->lock, flags); - /* And shovel */ - if (c) - tty_flip_buffer_push(to->port); - } - return c; + return tty_insert_flip_string_and_push_buffer(to->port, buf, c); } /** --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -547,6 +547,37 @@ void tty_flip_buffer_push(struct tty_por EXPORT_SYMBOL(tty_flip_buffer_push); /** + * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and + * push + * @port: tty port + * @chars: characters + * @size: size + * + * The function combines tty_insert_flip_string() and tty_flip_buffer_push() + * with the exception of properly holding the @port->lock. + * + * To be used only internally (by pty currently). + * + * Returns: the number added. + */ +int tty_insert_flip_string_and_push_buffer(struct tty_port *port, + const unsigned char *chars, size_t size) +{ + struct tty_bufhead *buf = &port->buf; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + size = tty_insert_flip_string(port, chars, size); + if (size) + tty_flip_buffer_commit(buf->tail); + spin_unlock_irqrestore(&port->lock, flags); + + queue_work(system_unbound_wq, &buf->work); + + return size; +} + +/** * tty_buffer_init - prepare a tty buffer structure * @tty: tty to initialise * --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -39,4 +39,7 @@ static inline int tty_insert_flip_string extern void tty_buffer_lock_exclusive(struct tty_port *port); extern void tty_buffer_unlock_exclusive(struct tty_port *port); +int tty_insert_flip_string_and_push_buffer(struct tty_port *port, + const unsigned char *chars, size_t cnt); + #endif /* _LINUX_TTY_FLIP_H */