Received: by 2002:ac0:e34a:0:0:0:0:0 with SMTP id g10csp480709imn; Wed, 27 Jul 2022 11:23:22 -0700 (PDT) X-Google-Smtp-Source: AGRyM1ttyj2o2+44ucJLhqem3LdcjGu6bywSsnDuiix8WxaNDihYSpwbj3tyXUhtE6Qnzrqw58iv X-Received: by 2002:a05:6402:12ce:b0:43c:b51e:b73e with SMTP id k14-20020a05640212ce00b0043cb51eb73emr4227987edx.312.1658946202063; Wed, 27 Jul 2022 11:23:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658946202; cv=none; d=google.com; s=arc-20160816; b=TpEwKiQbHD+TI2RSgFViEux6HlM38RrOXC6PsEV8H7HTepZ/atVHKBBz6OTrO7zLTJ d94Hwy27lz+r1wLh8dm9bWrYfcGdI4r+fd8ghxDxJGPoeqcsjZHf5KwjaZ+kz2oZJY5r d1C5Jy3wB3d9vRiBYssgJ/cRIfnGhdnbGisc74zqHMHz4D6ENBR7IqlEDb54oKQgJuyS lT9Byum4w9QeWOCID1gl43N8yv5ZMSLFqs4V3rg9Pq3wtYAjkZEJFo+8diXDbm9hkPnC zAyAmMLUEGSFGIHS9v6f/AZp5szvDsnuWPTolfqxeXwXrKpRjvAzLtS6fYF/5BVx3GwM UINA== 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=iXIOWEvLMq9DTqCy76IqWxGW1S86koSkGkycAgnZgsc=; b=Ie5KRcQGzWNgbhMyvZgvWLm7pOwytYC2fae7SittzF+6HmvhW1xHIeViwsiJ3awXQl B8i1IHOSiC0rlSp2gcnW1/x1juBUD7VJCCxtwxI0ewEAdqfPPo9wrnZAlcnuYPOq3vb4 SO6PRX0Lusi6IU4z6HyNyRIGZbxamLqcfKa7gmOlSaj7T8fgu7yCgTesRGzwv4h4ou1M TRZ9qNgJlnZqAyRsPxw3b9orY7AL67Ra1c+TsOxdFqdbxD1fmSLvCzwoUbJxJTj6n1zW Nl0ALK6OVH2mkpEYikPJ9AFxF1xdMFyyCFcYLyHNI4MRXZMuktJSfvNMiP5K/uEIWOxE tYFw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="XMYem/mL"; 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 n12-20020a05640205cc00b0043a50fda151si23261308edx.434.2022.07.27.11.22.56; Wed, 27 Jul 2022 11:23:22 -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="XMYem/mL"; 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 S238857AbiG0Qgx (ORCPT + 99 others); Wed, 27 Jul 2022 12:36:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47664 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237965AbiG0QfI (ORCPT ); Wed, 27 Jul 2022 12:35:08 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFA8F56B93; Wed, 27 Jul 2022 09:27:43 -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 228A9B821CB; Wed, 27 Jul 2022 16:27:42 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5DF34C433D6; Wed, 27 Jul 2022 16:27:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1658939260; bh=lybdaq6uKudUqfYXxUSkTfKxk/xAIs80HzWNT+hwtq0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XMYem/mLFbTz+dWaKIfrFjH2hjzJRgATqTbML/5yR9FLvDON5fpbBAVKjePrbnDzj wJYtRCYQfu3y/ww32yviEl7PuvSfhHwihoLgvQPJH/8eMgCqst2j59HaHMHilW6HK/ hNPV+JpfLlewCMrWa3+u37sf779aygzAxbEbPGWQ= 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.19 57/62] tty: use new tty_insert_flip_string_and_push_buffer() in pty_write() Date: Wed, 27 Jul 2022 18:11:06 +0200 Message-Id: <20220727161006.374175944@linuxfoundation.org> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220727161004.175638564@linuxfoundation.org> References: <20220727161004.175638564@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 @@ -548,6 +548,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 */