From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qv1-f42.google.com (mail-qv1-f42.google.com [209.85.219.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0A57121A459 for ; Fri, 26 Jun 2026 01:41:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.42 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782438065; cv=none; b=DbkkMtrxitBv9AamIcuejAF3CcPc3KoIIyLEJ6jMnWZXBAFI9lPuEFOApy5b4ezAe5Mb/Y//epP0HwG1ho11btOuWdEBYn2LXpEy1W1JRgqpmFEUfuOEc5pTyofD05JnOmG3evmHqHdrnbGZNvOrUWkq0dwmkfv3OG1rxoC6Hhc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782438065; c=relaxed/simple; bh=wjVyx+M+umE0ClrKNc/uYpDyveiTp16e7BZhS7fGxVk=; h=Content-Type:Mime-Version:Subject:From:In-Reply-To:Date:Cc: Message-Id:References:To; b=ubPpj6w8SerdDmR7TZCk8P/LkGPerFRy2c2Y05yN9OoqIEZpbfU9iGtYyinaV6zkoiLGa77sElPGhcA5eKQWVFwzkPNE5ddBCiCpGjgaSk7WZC/B/TBQFfLuEhiI4XMUJDNjaOcEPoESbjt/b5QgBq5VLrwa9F/yRqnPa2ikqeM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=I3UUq2m/; arc=none smtp.client-ip=209.85.219.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="I3UUq2m/" Received: by mail-qv1-f42.google.com with SMTP id 6a1803df08f44-8db9f25c5acso6110166d6.0 for ; Thu, 25 Jun 2026 18:41:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1782438063; x=1783042863; darn=vger.kernel.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=7ngqRe4pHm929VH+H9v0EOaTZy1/xI9u5JJe/w/V394=; b=I3UUq2m/ctO6adUl0mag8N4Krb+AMkuCEwacvdvRvz2rIy8u8lUIUDxh7c747byiYM B/eINX2xOMRtX1rUGuhkCLajU6FTEwDEItluEIWKl0XO+b9xouKI3VYZvrLIPMQ/jO/f t7GU0s/zsc+kWMfXB8YVVHUkaUK64M+nHrvWAFkioX7AJOog9ItW4Hp+p/Hidd+Xkzlv eviwstUvjBf1rHJvdngTX1SrmgXIMvHoGfvLoMrjPfDKU9VYZNziWrstM5lcGDooemgq QEmrfxhfLn4lW5cy6fP1DOZ6QwVcHlQjEXclaoHVOQmCAuXnnY9iz0AB7LsgX5mVscUO xQMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782438063; x=1783042863; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-gg:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=7ngqRe4pHm929VH+H9v0EOaTZy1/xI9u5JJe/w/V394=; b=AJ7dA3GOtG/VSRR/U6NJm4Z/v5Df7lyzc2eszFHNwZjddQZxLgL3dJa7dChzEc3KkU 7Su/Y8SxE5PQwd/wHKtI2PkBuLPhswAWPOvN8FRQcXKQ9GNYJ9TvqYpJtNLSE1El4PaZ r/k/baFBmx46C9H89aa2O8kz7pOCNWqvbIQbj1UdTdWrGR4NFYXxIC7WN1CvBITokaJ8 tAZnE3jyRU4xYKfEImCU4nv0jWdBc/2F+snNvs2ubBnWbtKEitoKppR5qIqtUfWK+TO9 S0gOrQLNP9d8N3O/SnjN7JehpSsEshys2wITLEOYr07jayp+aLVvF2IPX+FChwNUOiM8 4vcg== X-Gm-Message-State: AOJu0YzOR3Vwk05Xr3UrSB4ccEfsjUgsInClkCBuT8Fv4hEK22THTCpK 2oJcgFB3iEXb8AAPjhFJVd6XeVzKyEp5vwM528y8ADSjylFfbysu1FoTucBQpt6yRHM= X-Gm-Gg: AfdE7ckH8G0OBG6m76oly18wjexvbqg/h3GhYujtC3nfrvqylj8moEZGYy+xEvECAMj AyIYt0KAGWCUH9EsZZQYjql1wl0e+DKH2+qi+kk0XwMQbHgK5L9yPGMCJ/k8e7EUx/jLAGXy5/E qLGHaLqzIbM0Fri8mCh3RBOfyEmIDwsKHsF34SX/93JWDHR2bNFFE2j3bIBncc/7SehhkH5gBjm q15jQGcsx2mJe77Lrye8bWtj4At6BlBNV8Vgd7N2DAdp0OSbisnO+NIkBMj0DNWAD0WbYwkeRBm LCSI+v9xOeJ2lwQIrulfFk36bMwM+pBm8Qcy8DhtfSFYETNby7Nzo1jWLfDDSwdlwPtnHLpzQWU Qew2dFO9AWUPWXDKdJhVdRBKdh4lHOCVgcZEwHHcvWkK2BHvfGIjr1soDLpjKy6p9DyXN7Lx1Xv b6KK9K+JAOlo40cIoE08eovHD4ymnyNuZOGXhcv1ucl0SsaMfqAZM4DQ== X-Received: by 2002:a05:6214:2f10:b0:8cc:d6d9:702 with SMTP id 6a1803df08f44-8e6cf496743mr82564276d6.0.1782438062897; Thu, 25 Jun 2026 18:41:02 -0700 (PDT) Received: from smtpclient.apple ([2601:985:4601:5df0:bd2f:1819:13b7:2731]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8e683cbd054sm42127556d6.28.2026.06.25.18.41.01 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Jun 2026 18:41:02 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: [PATCH] ipack: ipoctal: fix use-after-free and null-ptr-deref on remove From: Shuangpeng In-Reply-To: <145da0571617ef4649721b82bb8759722e2859b3.1782357839.git.xiaopei01@kylinos.cn> Date: Thu, 25 Jun 2026 21:40:30 -0400 Cc: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Message-Id: <28C40F77-46D3-4ABC-BAD2-38EB9A606E71@gmail.com> References: <145da0571617ef4649721b82bb8759722e2859b3.1782357839.git.xiaopei01@kylinos.cn> To: Pei Xiao X-Mailer: Apple Mail (2.3864.600.51.1.1) Hi Pei, I applied the new patch and reran the same reproducer [1]. It triggers another KASAN report: [ 63.599954][ T1151] BUG: KASAN: slab-use-after-free in ipoctal_cleanup = (include/linux/ipack.h:292 drivers/ipack/devices/ipoctal.c:697) [ 63.600513][ T1151] Read of size 8 at addr ffff8881136e5008 by task = kworker/1:2/1151 [ 63.601248][ T1151] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + = PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 63.601249][ T1151] Workqueue: events release_one_tty [ 63.601254][ T1151] Call Trace: [ 63.601257][ T1151] [ 63.601258][ T1151] dump_stack_lvl (lib/dump_stack.c:94 = lib/dump_stack.c:120) [ 63.601261][ T1151] print_report (mm/kasan/report.c:378 = mm/kasan/report.c:482) [ 63.601272][ T1151] kasan_report (mm/kasan/report.c:595) [ 63.601286][ T1151] ipoctal_cleanup (include/linux/ipack.h:292 = drivers/ipack/devices/ipoctal.c:697) [ 63.601289][ T1151] release_one_tty (drivers/tty/tty_io.c:1522) [ 63.601292][ T1151] process_scheduled_works (kernel/workqueue.c:3322 = kernel/workqueue.c:3405) [ 63.601297][ T1151] worker_thread (kernel/workqueue.c:3486) [ 63.601303][ T1151] kthread (kernel/kthread.c:436) [ 63.601310][ T1151] ret_from_fork (kernel/process.c:158) [ 63.601320][ T1151] ret_from_fork_asm (arch/x86/entry/entry_64.S:245) [ 63.601324][ T1151] [ 63.610982][ T1151] The buggy address belongs to the object at = ffff8881136e5000 [ 63.610982][ T1151] which belongs to the cache kmalloc-1k of size 1024 [ 63.611938][ T1151] The buggy address is located 8 bytes inside of [ 63.611938][ T1151] freed 1024-byte region [ffff8881136e5000, = ffff8881136e5400) I am also happy to test the next version if needed. Best, Shuangpeng [1] = https://gist.github.com/shuangpengbai/bc71ccd7ce1454abae45897fdde6813b > On Jun 24, 2026, at 23:24, Pei Xiao wrote: >=20 > A use-after-free occurs when the device is removed while a tty > session is still active. The remove callback frees the ipoctal > structure via kfree() while tty ops may still access it. >=20 > Fix this by introducing kref-based lifetime management. The kref is > initialized in probe(), taken in ipoctal_install() when a tty is > opened, and released in ipoctal_cleanup() when the tty is finally > destroyed. The remove callback replaces direct kfree() with > kref_put(), ensuring the memory is freed only after all references > are released. >=20 > However, the kref keeps only the ipoctal struct alive =E2=80=94 the = MMIO > mappings (devm_ioremap) and xmit_buf are released during remove() > regardless. If a tty fd is still open: >=20 > - tty_port_free_xmit_buf() NULLs xmit_buf, leading to a NULL > dereference in ipoctal_write_tty(). > - devm iounmap() removes page table mappings, leading to a page > fault in ipoctal_set_termios() and other tty ops that access > channel->regs via iowrite8(). >=20 > Fix both by: >=20 > (1) checking for NULL xmit_buf in ipoctal_write_tty(), and > (2) introducing a "removed" flag in struct ipoctal, set at the > start of __ipoctal_remove(), and checked in every tty op that > touches hardware registers (write_tty, set_termios, > port_activate, hangup, shutdown). >=20 > Reported-by: Shuangpeng Bai > Closes: = https://lore.kernel.org/lkml/178144969601.60470.1257088106279546587@gmail.= com/ > Fixes: 05e5027efc9c ("Staging: ipack: move out of staging") > Signed-off-by: Pei Xiao > --- > drivers/ipack/devices/ipoctal.c | 45 +++++++++++++++++++++++++++++++-- > 1 file changed, 43 insertions(+), 2 deletions(-) >=20 > diff --git a/drivers/ipack/devices/ipoctal.c = b/drivers/ipack/devices/ipoctal.c > index 1bbefc6de708..2b9d381cf56d 100644 > --- a/drivers/ipack/devices/ipoctal.c > +++ b/drivers/ipack/devices/ipoctal.c > @@ -10,6 +10,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -25,6 +26,8 @@ >=20 > static const struct tty_operations ipoctal_fops; >=20 > +static void ipoctal_release(struct kref *kref); > + > struct ipoctal_channel { > struct ipoctal_stats stats; > unsigned int nb_bytes; > @@ -49,6 +52,8 @@ struct ipoctal { > struct tty_driver *tty_drv; > u8 __iomem *mem8_space; > u8 __iomem *int_space; > + struct kref kref; > + bool removed; > }; >=20 > static inline struct ipoctal *chan_to_ipoctal(struct ipoctal_channel = *chan, > @@ -70,8 +75,13 @@ static void ipoctal_reset_channel(struct = ipoctal_channel *channel) > static int ipoctal_port_activate(struct tty_port *port, struct = tty_struct *tty) > { > struct ipoctal_channel *channel; > + struct ipoctal *ipoctal; >=20 > channel =3D dev_get_drvdata(tty->dev); > + ipoctal =3D chan_to_ipoctal(channel, tty->index); > + > + if (ipoctal->removed) > + return -ENODEV; >=20 > /* > * Enable RX. TX will be enabled when > @@ -95,6 +105,7 @@ static int ipoctal_install(struct tty_driver = *driver, struct tty_struct *tty) > if (res) > goto err_put_carrier; >=20 > + kref_get(&ipoctal->kref); > tty->driver_data =3D channel; >=20 > return 0; > @@ -460,8 +471,12 @@ static ssize_t ipoctal_write_tty(struct = tty_struct *tty, const u8 *buf, > size_t count) > { > struct ipoctal_channel *channel =3D tty->driver_data; > + struct ipoctal *ipoctal =3D chan_to_ipoctal(channel, tty->index); > size_t char_copied; >=20 > + if (ipoctal->removed || !channel->tty_port.xmit_buf) > + return 0; > + > char_copied =3D ipoctal_copy_write_buffer(channel, buf, count); >=20 > /* As the IP-OCTAL 485 only supports half duplex, do it manually */ > @@ -501,8 +516,12 @@ static void ipoctal_set_termios(struct tty_struct = *tty, > unsigned char mr2 =3D 0; > unsigned char csr =3D 0; > struct ipoctal_channel *channel =3D tty->driver_data; > + struct ipoctal *ipoctal =3D chan_to_ipoctal(channel, tty->index); > speed_t baud; >=20 > + if (ipoctal->removed) > + return; > + > cflag =3D tty->termios.c_cflag; >=20 > /* Disable and reset everything before change the setup */ > @@ -631,10 +650,15 @@ static void ipoctal_hangup(struct tty_struct = *tty) > { > unsigned long flags; > struct ipoctal_channel *channel =3D tty->driver_data; > + struct ipoctal *ipoctal; >=20 > if (channel =3D=3D NULL) > return; >=20 > + ipoctal =3D chan_to_ipoctal(channel, tty->index); > + if (ipoctal->removed) > + return; > + > spin_lock_irqsave(&channel->lock, flags); > channel->nb_bytes =3D 0; > channel->pointer_read =3D 0; > @@ -651,10 +675,15 @@ static void ipoctal_hangup(struct tty_struct = *tty) > static void ipoctal_shutdown(struct tty_struct *tty) > { > struct ipoctal_channel *channel =3D tty->driver_data; > + struct ipoctal *ipoctal; >=20 > if (channel =3D=3D NULL) > return; >=20 > + ipoctal =3D chan_to_ipoctal(channel, tty->index); > + if (ipoctal->removed) > + return; > + > ipoctal_reset_channel(channel); > tty_port_set_initialized(&channel->tty_port, false); > } > @@ -666,6 +695,7 @@ static void ipoctal_cleanup(struct tty_struct = *tty) >=20 > /* release the carrier driver */ > ipack_put_carrier(ipoctal->dev); > + kref_put(&ipoctal->kref, ipoctal_release); > } >=20 > static const struct tty_operations ipoctal_fops =3D { > @@ -683,6 +713,13 @@ static const struct tty_operations ipoctal_fops =3D= { > .cleanup =3D ipoctal_cleanup, > }; >=20 > +static void ipoctal_release(struct kref *kref) > +{ > + struct ipoctal *ipoctal =3D container_of(kref, struct ipoctal, = kref); > + > + kfree(ipoctal); > +} > + > static int ipoctal_probe(struct ipack_device *dev) > { > int res; > @@ -692,6 +729,8 @@ static int ipoctal_probe(struct ipack_device *dev) > if (ipoctal =3D=3D NULL) > return -ENOMEM; >=20 > + kref_init(&ipoctal->kref); > + > ipoctal->dev =3D dev; > res =3D ipoctal_inst_slot(ipoctal, dev->bus->bus_nr, dev->slot); > if (res) > @@ -701,7 +740,7 @@ static int ipoctal_probe(struct ipack_device *dev) > return 0; >=20 > out_uninst: > - kfree(ipoctal); > + kref_put(&ipoctal->kref, ipoctal_release); > return res; > } >=20 > @@ -709,6 +748,8 @@ static void __ipoctal_remove(struct ipoctal = *ipoctal) > { > int i; >=20 > + ipoctal->removed =3D true; > + > ipoctal->dev->bus->ops->free_irq(ipoctal->dev); >=20 > for (i =3D 0; i < NR_CHANNELS; i++) { > @@ -725,7 +766,7 @@ static void __ipoctal_remove(struct ipoctal = *ipoctal) > tty_unregister_driver(ipoctal->tty_drv); > kfree(ipoctal->tty_drv->name); > tty_driver_kref_put(ipoctal->tty_drv); > - kfree(ipoctal); > + kref_put(&ipoctal->kref, ipoctal_release); > } >=20 > static void ipoctal_remove(struct ipack_device *idev) > --=20 > 2.25.1 >=20