From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (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 E979715FA81 for ; Mon, 7 Sep 2026 08:54:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788771299; cv=none; b=bIeysEw6gdIhZIfPjcNyFuK3Yk/V+Aq3dbEkqKOYtneHa2Upy5zP8D9tejmQKPyqNMrEiz99dpm0Zpkc0KXJmjip8Lm1IqKqOIzOa2BwgRHaUMotxbf0llYvDzApdNq6ObyDwGFp/Ni9UGDoR01efU2lPVzBSr7dEx7cEKk0U4A= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788771299; c=relaxed/simple; bh=FTDlNw6r0LF5YxoznXLvvaS2gAHptHznaJPZ4Vd/OqI=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=Ros7q86q7Bi9pwOuKpvtWF6cRuJ34V7w7NieVDVwvy4OD85d2JO8QeBmxZR9z50o3wXr25SQIWrshSwDIhYCqNw9wKQ0Y0Pz8D6EMMh5h5sHlGp8xjfdwgp8GCPms2XuhJwH5ME7UEBnePqABHRJGtfI2X0PzAElK6RKcpYdDBA= 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=iFWq0p4n; arc=none smtp.client-ip=74.125.225.140 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="iFWq0p4n" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-499db1740e4so1421875e9.0 for ; Mon, 07 Sep 2026 01:54:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788771289; x=1789376089; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=EOH39uXHtiG5QXo0tn6kMtNcNI/rtNOE7+q7zDPj52w=; b=iFWq0p4nzwPgnFc7bGhyAtKi7K4wICKdofbQTNhwitqxwBI5Jf/OjMvxVFnrJVV3OI EUx3/8uJ/dTqtB8jgzc3AaYNFWyS+8uKgoH7U+p6YZUixf9wBTjEJV1BUJPRw4O/SLCP M/1RB7Vj/V8KRyNhb0HdIdBVE3c1+6ADlThk6khvfp/jF2nJ3pfR9TK50BEbkfaorx9V AzRJ5Tt4PUVqmWZ7UoD/B4xjSwwcZ+DKb2yX053j+45TF+kUghA+Ek+BZcRP0oCuU7NP HBspKApbC+37iPoZy76cVFtiQlP7rC2y8HqFWY0uExa5Fb3eFTFMVkugxupf0xBKpQ8L AUYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788771289; x=1789376089; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=EOH39uXHtiG5QXo0tn6kMtNcNI/rtNOE7+q7zDPj52w=; b=Z1VwTMuSjWQeqDiGSJj08aQZGZB1aN5wxO4NCYbEXwgI3MQONMz17mWSQBkvByWGtG ut8dh2ipoC6A4ASg/4N8WtydanxfHuno0prRP/y0uhQkIsA8+sYSVMcfuoK8X0aUb6RI RU0AI2nnc9lhed1qBkTrHoXPwTJsTEq4OeU1TvuppvCXxYN6NwvsmIxNcFVWxIWDl6nL ZWoC5i/EPyCKtjzB15PFqF0jKUD7tTA1DmAMiYAeisBqX4Zp3Y0/2bq783nJpNCFTjaI M4MF5zeCi8ikjtj31jJ72Pp5UV3Qzkx6unrAclNBOHoGeA7WzC/1UHe7McfSuUNXvxrG /RzQ== X-Forwarded-Encrypted: i=1; AKwUvBwGW3MG0//8qyOWAN8ZJvM2rz5xQ1n47fzxXfZdR25Xe/McZqeCA3kdJiLuoXHWmZx9M0X1tFIxjqTizw8=@vger.kernel.org X-Gm-Message-State: AFuF++kA8tgn1Mo4Ggxrkm8AoGZ+aPbZmSsvXJB8JY9HcSYCx0wzxnO5 U68AdLbNTcKbpWdWn58ZleY34zUNjgr1Hp+giHCiIKpB3odNdp9UTz9Z X-Gm-Gg: AYBFou2e1HovKlW9/8doIGT4PK2Epi23SuDMqPNGVkWb1oeAYKCYkW5qxlgUjNqoJYS vtfKDlu/eSQYLsWpbCsXb+Qsf+xHC0ryMHu2dyFzhyLwiBLXes1oz/r7yzW9et39WXoovJ6N812 g+dOxIbP+YyiwT1vPGlpA/+MiGMI30u8QgbB3/TONNVdDDUmDpr3z1GYA5ok24wiuua3q8/PeQ1 RKvOtLLP//1wNrgOAI2npU/6MQfoopuVByehvTzOoS2iZ68A+YKKv5fGWYr6kZbhGI+uxB9F/VR IckeEKC7G0EW4RPG8EITlHK0NVprBOhJFgmNC4vLzWLTm4emT/TVn4U6HyXxQcJhQx4DhfnrP0w CR/SsWvLKYyvLRVCztYd2G0RadvGBkaaAWT0evqSL1uGxfRAFOWzfXiYLrDZNHl3veydUfkjBC6 2V14B3YGnjx9m3E7BJODiyPMURMEx9VvsNcwrOpMWuXmHMYCPDKBTystN33uRG5XMrUV7JuzHLl W+4sVNnawpXUnaajutfAFXkekPdOJZp3dQ+21IMCvgN/LfCMuUEbChxmYh8MPNYxIC9flgqF7p+ X-Received: by 2002:a05:600c:34c5:b0:499:cef6:104c with SMTP id 5b1f17b1804b1-49cf823c012mr175956085e9.1.1788771288817; Mon, 07 Sep 2026 01:54:48 -0700 (PDT) Received: from ast-epyc5.inf.ethz.ch (ast-epyc4.inf.ethz.ch. [129.132.161.179]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49ce5952560sm353482585e9.3.2026.09.07.01.54.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 01:54:48 -0700 (PDT) From: Zijing Yin To: Chuck Lever , Jeff Layton , NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey Cc: Zijing Yin , linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] SUNRPC: fix netns use-after-free in write_gssp() Date: Mon, 7 Sep 2026 01:54:35 -0700 Message-ID: <20260907085435.644076-1-yzjaurora@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit While fuzzing with a customized syzkaller, I hit a refcount warning in xprt_alloc(), reached from a write to /proc/net/rpc/use-gss-proxy: refcount_t: addition on 0; use-after-free. WARNING: lib/refcount.c:25 at refcount_warn_saturate+0xf8/0x120 CPU: 0 PID: 10404 Comm: syz.0.17 Not tainted 7.3.0-rc1-00096-gcfebfd3db73d Call Trace: xprt_alloc+0x83f/0x9d0 xs_setup_xprt+0xaf/0x3c0 xs_setup_local+0x47/0x7f0 xprt_create_transport+0x16c/0x730 rpc_create+0x38e/0x7f0 gssp_rpc_create+0xe2/0x180 set_gssp_clnt+0xba/0x1b0 write_gssp+0x200/0x310 proc_reg_write+0x240/0x330 vfs_write+0x2aa/0x1050 ksys_write+0x12a/0x250 do_syscall_64+0x117/0x750 entry_SYSCALL_64_after_hwframe+0x77/0x7f create_use_gss_proxy_proc_entry() stores the struct net pointer as the proc entry's private data without taking a reference on it, and an open file descriptor does not pin the namespace either, as procfs only pins the proc_dir_entry. write_gssp() reads that pointer back with pde_data() and hands it to set_gssp_clnt(), which reaches xprt_init(): xprt->xprt_net = get_net_track(net, &xprt->ns_tracker, GFP_KERNEL); get_net_track() -> get_net() -> refcount_inc() is unconditional, so rpc_create() assumes its caller holds a reference on args.net. write_gssp() does not. Dropping the last ns.count reference does not make the file go away. __put_net() only queues cleanup_net() on a workqueue, and the remove_proc_entry() that fences off further writes runs from the rpcsec_gss pernet .exit method, that is, from inside cleanup_net(). A write landing between those two points increments a refcount that is already zero. cleanup_net() does not re-read ns.count, so the namespace is freed anyway and the rpc_xprt -- along with the AF_LOCAL socket opened for it -- is left pointing at freed memory. The resurrected count is visible to the rest of that teardown too: with CONFIG_IPV6_MROUTE the same cleanup_net() worker then trips !mr_can_free_table() in ip6mr_free_table(), which tests check_net() on the namespace it is freeing. It reduces to opening /proc/net/rpc/use-gss-proxy inside a new network namespace, calling setns() back to the original one to drop the last reference, and then writing "1" to the still-open descriptor. Take the reference in write_gssp() itself and refuse the write when the namespace is already gone. This is what procfs does for every other /proc/net file: get_proc_net() is maybe_get_net(PDE_NET(PDE(inode))) and seq_open_net() returns -ENXIO when it fails. PDE_NET() cannot be reused here because the parent directory /proc/net/rpc carries no namespace pointer. Adding a .pre_exit to rpcsec_gss_net_ops so the entry is removed earlier would only narrow the window, since pre_exit also runs from cleanup_net(). Live namespaces are unaffected: a write still returns the error from set_gssp_clnt(), a write of "2" still returns -EINVAL, and reads are untouched. Fixes: 030d794bf498 ("SUNRPC: Use gssproxy upcall for server RPCGSS authentication.") Signed-off-by: Zijing Yin --- Applies to nfsd-testing (8ba9d2d76000), v7.3-rc1, nfsd-next and nfsd-fixes; svcauth_gss.c is identical in all of them. Tested with KASAN and CONFIG_NET_NS_REFCNT_TRACKER: unpatched, the reproducer below warns on every boot; patched, it returns -ENXIO over 12704 iterations with no splat and no ref_tracker report. Reproducer (cc -static; needs CONFIG_SUNRPC_GSS=y, run as root): #define _GNU_SOURCE #include #include #include #include #include #include int main(void) { int host = open("/proc/self/ns/net", O_RDONLY); int fd; if (host < 0 || unshare(CLONE_NEWNET)) return 1; fd = open("/proc/self/net/rpc/use-gss-proxy", O_WRONLY); if (fd < 0 || setns(host, CLONE_NEWNET)) return 1; if (write(fd, "1", 1) < 0) printf("write: %s\n", strerror(errno)); return 0; } net/sunrpc/auth_gss/svcauth_gss.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 967e9d53080d..8e0b6b17c81d 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1420,10 +1420,19 @@ static ssize_t write_gssp(struct file *file, const char __user *buf, return res; if (i != 1) return -EINVAL; + + /* + * The proc entry does not hold a reference on @net, and neither + * does an open file descriptor, so @net can already be dying. + * rpc_create() below takes a reference unconditionally. + */ + if (!maybe_get_net(net)) + return -ENXIO; + res = set_gssp_clnt(net); - if (res) - return res; - res = set_gss_proxy(net, 1); + if (!res) + res = set_gss_proxy(net, 1); + put_net(net); if (res) return res; return count; base-commit: 8ba9d2d760007b15f8b4e8a812c9c0dfd66a2763 -- 2.43.0