Message ID | 20241021142343.3857891-3-yangerkun@huaweicloud.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | bugfix for c_show/e_show | expand |
On Mon, Oct 21, 2024 at 10:23:42PM +0800, Yang Erkun wrote: > From: Yang Erkun <yangerkun@huawei.com> > > The function `c_show` was called with protection from RCU. This only > ensures that `cp` will not be freed. Therefore, the reference count for > `cp` can drop to zero, which will trigger a refcount use-after-free > warning when `cache_get` is called. To resolve this issue, use > `cache_get_rcu` to ensure that `cp` remains active. > > ------------[ cut here ]------------ > refcount_t: addition on 0; use-after-free. > WARNING: CPU: 7 PID: 822 at lib/refcount.c:25 > refcount_warn_saturate+0xb1/0x120 > CPU: 7 UID: 0 PID: 822 Comm: cat Not tainted 6.12.0-rc3+ #1 > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS > 1.16.1-2.fc37 04/01/2014 > RIP: 0010:refcount_warn_saturate+0xb1/0x120 > > Call Trace: > <TASK> > c_show+0x2fc/0x380 [sunrpc] > seq_read_iter+0x589/0x770 > seq_read+0x1e5/0x270 > proc_reg_read+0xe1/0x140 > vfs_read+0x125/0x530 > ksys_read+0xc1/0x160 > do_syscall_64+0x5f/0x170 > entry_SYSCALL_64_after_hwframe+0x76/0x7e > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Instead, how about: Cc: stable@vger.kernel.org # v4.20+ > Signed-off-by: Yang Erkun <yangerkun@huawei.com> > --- > net/sunrpc/cache.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c > index 1bd3e531b0e0..059f6ef1ad18 100644 > --- a/net/sunrpc/cache.c > +++ b/net/sunrpc/cache.c > @@ -1427,7 +1427,9 @@ static int c_show(struct seq_file *m, void *p) > seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n", > convert_to_wallclock(cp->expiry_time), > kref_read(&cp->ref), cp->flags); > - cache_get(cp); > + if (!cache_get_rcu(cp)) > + return 0; > + > if (cache_check(cd, cp, NULL)) > /* cache_check does a cache_put on failure */ > seq_puts(m, "# "); > -- > 2.39.2 >
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 1bd3e531b0e0..059f6ef1ad18 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1427,7 +1427,9 @@ static int c_show(struct seq_file *m, void *p) seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n", convert_to_wallclock(cp->expiry_time), kref_read(&cp->ref), cp->flags); - cache_get(cp); + if (!cache_get_rcu(cp)) + return 0; + if (cache_check(cd, cp, NULL)) /* cache_check does a cache_put on failure */ seq_puts(m, "# ");