Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp4147896pxb; Mon, 27 Sep 2021 10:21:45 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwnqZ6MmtLIiJhuGnArhmUZagq0bOxzpNyaOYY9TDwsGNdAy2YRjsMqDNhExL9c96li//Df X-Received: by 2002:a17:902:7590:b0:13d:c5d4:1b29 with SMTP id j16-20020a170902759000b0013dc5d41b29mr922665pll.36.1632763304972; Mon, 27 Sep 2021 10:21:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632763304; cv=none; d=google.com; s=arc-20160816; b=JLTOKFFQ+Vjivui3Hofg9/IW4WTxU5kwIKqMPVp1pWHOEmAsg5aCIoJ/UoTKkIRAYT UGz5NilDHl3/pTbe8sQuNvnKUoTA4Itgs5w5oGD0J0IdqdGL16z/tcavn/WefsIq3KbR ULsIVe8D59Q51hjoB7OAqwYOas0wo6gH4Tzzy0oY6LkUZGjfAqTHG00YZixU7bQnL7zR udC84/EI2Q/ehQj/jARJtpYNKcBVTHxhX5OkLVm+0wa1vzlBk2+ziLcd6HoaURhYl1IG KxvNBxrgzkoBEKe3ssvWl5dIVcA95icwz/9hrXbi6oINw2KyNfCCpANb4kND1z2l3F5L /iNA== 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=HJmbvqaaiYR3oq/+nbpVysmwX7V0S9uu3yH05cLtuiM=; b=tATQvPzx4aIB0qmedWpGiTBx2ZXeRckyzNaZkz1wB25Hp3S1GveoWygjLxCOYx3llY lqfvashOw/DT8fg9G3Ax45yNdKsqalcnt1hB21ZGuPGqcJ+uddcxNi14NSdw/JRIYjJI wzEki860rZVL8YMeVjxp8fAHV9e+k0r65mPVihoo700C/hUeHLBzGXPne60b2G1QZOyf a9geSrCyWquYHqGSlWi9uysNBZeq9mXSj2Axu6nWVPTg9E1cz7MW1+dHBepBl1+menwI 34XysJwcost3HEAM01eVJe4FaftYd0ygho+sym38sw6Ja37uBUKb9OfLYY/R9KQM76yS hkrg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=rTXMDFVU; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id b23si23829535plz.353.2021.09.27.10.21.31; Mon, 27 Sep 2021 10:21:44 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=rTXMDFVU; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 S236258AbhI0RWY (ORCPT + 99 others); Mon, 27 Sep 2021 13:22:24 -0400 Received: from mail.kernel.org ([198.145.29.99]:35378 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237416AbhI0RS2 (ORCPT ); Mon, 27 Sep 2021 13:18:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 4E24A6109F; Mon, 27 Sep 2021 17:12:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1632762749; bh=HepcGExfzO9xHUUHU3nFG+8wOL1hfP8WA54LsRsilhk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rTXMDFVUfvDqRdy6zQfU6gzHE0I4MrkBKC6233EJbrl3pCp2tJS2wxMf74JC5xohj CajXIvvSRoGOtoDNjK5yafneBEPLOSofCgUX1I8MUMmZYgMtZ28erOvwzGQ82Vp19w kRBC7UDvF8fJCvYl/wh/WAu2ILNYOF+yDVEwgWm8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Alex Elder , Johan Hovold Subject: [PATCH 5.14 020/162] staging: greybus: uart: fix tty use after free Date: Mon, 27 Sep 2021 19:01:06 +0200 Message-Id: <20210927170234.152508085@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210927170233.453060397@linuxfoundation.org> References: <20210927170233.453060397@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Johan Hovold commit 92dc0b1f46e12cfabd28d709bb34f7a39431b44f upstream. User space can hold a tty open indefinitely and tty drivers must not release the underlying structures until the last user is gone. Switch to using the tty-port reference counter to manage the life time of the greybus tty state to avoid use after free after a disconnect. Fixes: a18e15175708 ("greybus: more uart work") Cc: stable@vger.kernel.org # 4.9 Reviewed-by: Alex Elder Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20210906124538.22358-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/uart.c | 62 +++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -761,6 +761,17 @@ out: gbphy_runtime_put_autosuspend(gb_tty->gbphy_dev); } +static void gb_tty_port_destruct(struct tty_port *port) +{ + struct gb_tty *gb_tty = container_of(port, struct gb_tty, port); + + if (gb_tty->minor != GB_NUM_MINORS) + release_minor(gb_tty); + kfifo_free(&gb_tty->write_fifo); + kfree(gb_tty->buffer); + kfree(gb_tty); +} + static const struct tty_operations gb_ops = { .install = gb_tty_install, .open = gb_tty_open, @@ -786,6 +797,7 @@ static const struct tty_port_operations .dtr_rts = gb_tty_dtr_rts, .activate = gb_tty_port_activate, .shutdown = gb_tty_port_shutdown, + .destruct = gb_tty_port_destruct, }; static int gb_uart_probe(struct gbphy_device *gbphy_dev, @@ -798,17 +810,11 @@ static int gb_uart_probe(struct gbphy_de int retval; int minor; - gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL); - if (!gb_tty) - return -ENOMEM; - connection = gb_connection_create(gbphy_dev->bundle, le16_to_cpu(gbphy_dev->cport_desc->id), gb_uart_request_handler); - if (IS_ERR(connection)) { - retval = PTR_ERR(connection); - goto exit_tty_free; - } + if (IS_ERR(connection)) + return PTR_ERR(connection); max_payload = gb_operation_get_payload_size_max(connection); if (max_payload < sizeof(struct gb_uart_send_data_request)) { @@ -816,13 +822,23 @@ static int gb_uart_probe(struct gbphy_de goto exit_connection_destroy; } + gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL); + if (!gb_tty) { + retval = -ENOMEM; + goto exit_connection_destroy; + } + + tty_port_init(&gb_tty->port); + gb_tty->port.ops = &gb_port_ops; + gb_tty->minor = GB_NUM_MINORS; + gb_tty->buffer_payload_max = max_payload - sizeof(struct gb_uart_send_data_request); gb_tty->buffer = kzalloc(gb_tty->buffer_payload_max, GFP_KERNEL); if (!gb_tty->buffer) { retval = -ENOMEM; - goto exit_connection_destroy; + goto exit_put_port; } INIT_WORK(&gb_tty->tx_work, gb_uart_tx_write_work); @@ -830,7 +846,7 @@ static int gb_uart_probe(struct gbphy_de retval = kfifo_alloc(&gb_tty->write_fifo, GB_UART_WRITE_FIFO_SIZE, GFP_KERNEL); if (retval) - goto exit_buf_free; + goto exit_put_port; gb_tty->credits = GB_UART_FIRMWARE_CREDITS; init_completion(&gb_tty->credits_complete); @@ -844,7 +860,7 @@ static int gb_uart_probe(struct gbphy_de } else { retval = minor; } - goto exit_kfifo_free; + goto exit_put_port; } gb_tty->minor = minor; @@ -853,9 +869,6 @@ static int gb_uart_probe(struct gbphy_de init_waitqueue_head(&gb_tty->wioctl); mutex_init(&gb_tty->mutex); - tty_port_init(&gb_tty->port); - gb_tty->port.ops = &gb_port_ops; - gb_tty->connection = connection; gb_tty->gbphy_dev = gbphy_dev; gb_connection_set_data(connection, gb_tty); @@ -863,7 +876,7 @@ static int gb_uart_probe(struct gbphy_de retval = gb_connection_enable_tx(connection); if (retval) - goto exit_release_minor; + goto exit_put_port; send_control(gb_tty, gb_tty->ctrlout); @@ -890,16 +903,10 @@ static int gb_uart_probe(struct gbphy_de exit_connection_disable: gb_connection_disable(connection); -exit_release_minor: - release_minor(gb_tty); -exit_kfifo_free: - kfifo_free(&gb_tty->write_fifo); -exit_buf_free: - kfree(gb_tty->buffer); +exit_put_port: + tty_port_put(&gb_tty->port); exit_connection_destroy: gb_connection_destroy(connection); -exit_tty_free: - kfree(gb_tty); return retval; } @@ -930,15 +937,10 @@ static void gb_uart_remove(struct gbphy_ gb_connection_disable_rx(connection); tty_unregister_device(gb_tty_driver, gb_tty->minor); - /* FIXME - free transmit / receive buffers */ - gb_connection_disable(connection); - tty_port_destroy(&gb_tty->port); gb_connection_destroy(connection); - release_minor(gb_tty); - kfifo_free(&gb_tty->write_fifo); - kfree(gb_tty->buffer); - kfree(gb_tty); + + tty_port_put(&gb_tty->port); } static int gb_tty_init(void)