Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 59D234E5351; Thu, 17 Sep 2026 18:10:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789668649; cv=none; b=t1BFZIjjvDF6Gg5NHB+qbxFF4ddAQOrjUOVW9mW7bMjrBT97bkyPuF/IP35dcJf3g0oPmOaOwJ93+VBZdiFYeI3ho6bwc5LBwbIGOJizKlmS5L57irvYpl2VACgKHTCA5dqSsOT4KSwGqB90aKP/4gsJKMa+kztnA3Q6Cu7k1mw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789668649; c=relaxed/simple; bh=HkMuPCO6PxgqlEKMI39rbMmFJsZjq77c//b/i9TIM+Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LpN4xZsE1TXZ66nr0NEMiBpNpHvSkLN909TqukvaGhhOWkajzAaLCjTz5HH5+RkET6BcspD0byz0DnbYuwjs0gSfl0qQx9Qbj0+uvtaL7QuwtiMaGz09CBo86q0gNyGXc/52CP+Yn0HbDVcvHLbohQtz3WKNt7daUBACVKY33TM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=CwgNWGlI; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="CwgNWGlI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B8ACC1F000FF; Thu, 17 Sep 2026 18:10:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1789668648; bh=OzlIwhVJGutQAxwC/mtWy0FYi+Ww1A1+qG38c2jeRQ0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=CwgNWGlIo04zkZYmQLUnxonOWv89TpTR9IF1QeckWRvaziK4k77nwnjPKx5K1v2ry kM1mhzUu1einRgrsehJqtfm4kWd64XgVN3kZ62f2GQmzx//xM0kUXQTVimZuxGAwGg e5CPziVrg7YB1YknwAp2npsw/+QrQBi99Yulj/Pc= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, syzbot+d6fa74e3f19d6ee01e3a@syzkaller.appspotmail.com, James Chapman , Guillaume Nault , Eric Dumazet , Paolo Abeni , Sasha Levin Subject: [PATCH 6.12 0494/1102] l2tp: fix tunnel and session refcount leak on seq_file release Date: Thu, 17 Sep 2026 16:07:17 +0100 Message-ID: <20260917151552.122713264@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260917151539.408551884@linuxfoundation.org> References: <20260917151539.408551884@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Eric Dumazet [ Upstream commit 9006c116dd111d457bf5d074990210f70a4ad2c8 ] In pppol2tp_proc_open() and l2tp_dfs_seq_open(), iteration state (pd->tunnel and pd->session) is kept in seq_file private data to allow iteration across multiple read() system calls. However, if userspace closes /proc/net/pppol2tp or /sys/kernel/debug/l2tp/tunnels before reading to end-of-file (EOF), any tunnel or session reference stored in pd->tunnel / pd->session is left un-dropped when seq_file private data is freed. Fix this by dropping any remaining pd->tunnel and pd->session references in pppol2tp_proc_release() and l2tp_dfs_seq_release() when closing the file. Fixes: 0e0c3fee3a59 ("l2tp: hold reference on tunnels printed in pppol2tp proc file") Fixes: f726214d9b23 ("l2tp: hold reference on tunnels printed in l2tp/tunnels debugfs file") Reported-by: syzbot+d6fa74e3f19d6ee01e3a@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6a760f32.01d0871a.3a0d52.004f.GAE@google.com/T/#u Assisted-by: Jetski:Gemini-3.1-Pro Cc: James Chapman Cc: Guillaume Nault Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260811144651.2733424-1-edumazet@google.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/l2tp/l2tp_debugfs.c | 4 +++ net/l2tp/l2tp_ppp.c | 56 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index 2d0c8275a3a82..90fc0a59d50ac 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c @@ -306,6 +306,10 @@ static int l2tp_dfs_seq_release(struct inode *inode, struct file *file) seq = file->private_data; pd = seq->private; + if (pd->session) + l2tp_session_put(pd->session); + if (pd->tunnel) + l2tp_tunnel_put(pd->tunnel); if (pd->net) put_net_track(pd->net, &pd->ns_tracker); kfree(pd); diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index f388bf9abf378..c67ba1eab4769 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1608,7 +1608,53 @@ static const struct seq_operations pppol2tp_seq_ops = { .stop = pppol2tp_seq_stop, .show = pppol2tp_seq_show, }; -#endif /* CONFIG_PROC_FS */ + +static int pppol2tp_proc_open(struct inode *inode, struct file *file) +{ + struct net *net = pde_data(inode); + struct pppol2tp_seq_data *pd; + + net = maybe_get_net(net); + if (!net) + return -ENXIO; + + pd = __seq_open_private(file, &pppol2tp_seq_ops, sizeof(*pd)); + if (!pd) { + put_net(net); + return -ENOMEM; + } + +#ifdef CONFIG_NET_NS + pd->p.net = net; + netns_tracker_alloc(net, &pd->p.ns_tracker, GFP_KERNEL); +#endif + return 0; +} + +static int pppol2tp_proc_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct pppol2tp_seq_data *pd = seq->private; + + if (pd->session) + l2tp_session_put(pd->session); + if (pd->tunnel) + l2tp_tunnel_put(pd->tunnel); + +#ifdef CONFIG_NET_NS + put_net_track(pd->p.net, &pd->p.ns_tracker); +#else + put_net(&init_net); +#endif + return seq_release_private(inode, file); +} + +static const struct proc_ops pppol2tp_proc_ops = { + .proc_open = pppol2tp_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = pppol2tp_proc_release, +}; /***************************************************************************** * Network namespace @@ -1619,8 +1665,8 @@ static __net_init int pppol2tp_init_net(struct net *net) struct proc_dir_entry *pde; int err = 0; - pde = proc_create_net("pppol2tp", 0444, net->proc_net, - &pppol2tp_seq_ops, sizeof(struct pppol2tp_seq_data)); + pde = proc_create_data("pppol2tp", 0444, net->proc_net, + &pppol2tp_proc_ops, net); if (!pde) { err = -ENOMEM; goto out; @@ -1635,9 +1681,13 @@ static __net_exit void pppol2tp_exit_net(struct net *net) remove_proc_entry("pppol2tp", net->proc_net); } +#endif /* CONFIG_PROC_FS */ + static struct pernet_operations pppol2tp_net_ops = { +#ifdef CONFIG_PROC_FS .init = pppol2tp_init_net, .exit = pppol2tp_exit_net, +#endif }; /***************************************************************************** -- 2.53.0