Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp4652092ybl; Mon, 26 Aug 2019 13:47:49 -0700 (PDT) X-Google-Smtp-Source: APXvYqylbcPFeDw7s8xMcI58O5wYt/posQIgcncQh8oPYq2QR57DFI2paJozA9YN/cb3N5ns3TDW X-Received: by 2002:a65:6108:: with SMTP id z8mr7869198pgu.289.1566852469310; Mon, 26 Aug 2019 13:47:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566852469; cv=none; d=google.com; s=arc-20160816; b=YXGrnBo42/FaBSfDuGnMDaXyIjWxVkV7qO1Y/1s2tn8qEOvia73aVh14xkCeFzC8Ss ni5EZRhNZToEIY19aICh2yG6E/rZQQevBeB77McWqedyKwWnvCVfN93XTlLU+WF2doeU c7LffzQqCUWei6lRvokNrUsCQzFELkoGjUbnvvAw0N+J2Rc2Oc2WboUDKHOOOJM4rY45 lJ/tjb4moQ7JCdNZpGFGnDpe7Yw1ohpguQHtK2A4Uj+YEEvyb4qae9gsg/nwOEhWZAMv LyafrrbhQg/5qqm0ZSBAVbC0x9U26tPaYxZ0k6MbvL36l3HaefQWY8sXq93ys2Lb1HlE DUWw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=5NThB/NJ/xChr+SumN9ETd9hm3xzCr8nXnGoqknvnKk=; b=mZuLH62kcH64ElU1SFNLGcjXbEmgTqGjRc1TEz0kFGZ7C3pkMuISt3sfD1uTPcxcxl Tmok+AzvKz5gAFBwp1kDQKdKbjJm40Gx3Wb7SSD7Oj4kH8yS8Uj68y30ofmWNEs+6IcS FIvCfko4sejVwrAehtwZcpfMi7K5oQ672ERmoHNygRXq2U59VagH+GnJcaZFjSN0xo2v 6josGMfKVOygNPaSWOHQC92kG4fXjm24ZXnemT1uSwQichzunmY9rCxGuco6QEz5BeHN D1atay+Fr5zuxx3TATSLBubdPhM6XsPSbb9mQ2vhNeYXCryZ8dkzzrEGziSPPCkvL+4n ZdNw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-nfs-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id cd2si1532640plb.391.2019.08.26.13.47.35; Mon, 26 Aug 2019 13:47:49 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-nfs-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-nfs-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387449AbfHZUYT (ORCPT + 99 others); Mon, 26 Aug 2019 16:24:19 -0400 Received: from mx1.redhat.com ([209.132.183.28]:51098 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728711AbfHZUYT (ORCPT ); Mon, 26 Aug 2019 16:24:19 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AAA9330821AE; Mon, 26 Aug 2019 20:24:18 +0000 (UTC) Received: from bcodding.csb (ovpn-112-84.rdu2.redhat.com [10.10.112.84]) by smtp.corp.redhat.com (Postfix) with ESMTP id 69B1F6092D; Mon, 26 Aug 2019 20:24:18 +0000 (UTC) Received: by bcodding.csb (Postfix, from userid 24008) id CE657109C550; Mon, 26 Aug 2019 16:24:17 -0400 (EDT) From: Benjamin Coddington To: Trond Myklebust , Anna Schumaker Cc: Al Viro , linux-nfs@vger.kernel.org Subject: [PATCH] NFSv3: nfs_instantiate() might succeed leaving dentry negative unhashed Date: Mon, 26 Aug 2019 16:24:17 -0400 Message-Id: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Mon, 26 Aug 2019 20:24:18 +0000 (UTC) Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org After adding commit b0c6108ecf64 ("nfs_instantiate(): prevent multiple aliases for directory inode") my NFS client crashes while doing lustre race tests simultaneously on a local filesystem and the same filesystem exported via knfsd: BUG: unable to handle kernel NULL pointer dereference at 0000000000000028 Call Trace: ? iput+0x76/0x200 ? d_splice_alias+0x307/0x3c0 ? dput.part.31+0x96/0x110 ? nfs_instantiate+0x45/0x160 [nfs] nfs3_proc_setacls+0xa/0x20 [nfsv3] nfs3_proc_create+0x1cc/0x230 [nfsv3] nfs_create+0x83/0x160 [nfs] path_openat+0x11aa/0x14d0 do_filp_open+0x93/0x100 ? __check_object_size+0xa3/0x181 do_sys_open+0x184/0x220 do_syscall_64+0x5b/0x1b0 entry_SYSCALL_64_after_hwframe+0x65/0xca 158 static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, 159 struct posix_acl *dfacl) 160 { >> 161 struct nfs_server *server = NFS_SERVER(inode); The 0x28 offset is i_sb in struct inode, we passed a NULL inode to nfs3_proc_setacls(). After taking this apart, I find the dentry in R12 has a NULL inode after nfs_instantiate(), which makes sense if we move it to the alias just after nfs_fhget() (See the referenced commit above). Indeed, on the list of children is the identical positive dentry that is left behind after d_splice_alias(). Moving it would usualy be fine for callers, except for NFSv3 because we want the inode pointer to ride the dentry back up the stack so we can set ACLs on it and/or set attributes in the case of EXCLUSIVE. A similar problem existed in nfsd_create_locked(), and was fixed by commit 3819bb0d79f5 ("nfsd: vfs_mkdir() might succeed leaving dentry negative unhashed"). This patch takes the same approach to fixing the problem: in the rare case that we lost the race to the dentry, look it up and get the inode from there. Signed-off-by: Benjamin Coddington Fixes: b0c6108ecf64 ("nfs_instantiate(): prevent multiple aliases for directory inode") Cc: Al Viro --- fs/nfs/nfs3proc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index a3ad2d46fd42..292c53c082f7 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "iostat.h" #include "internal.h" @@ -305,6 +306,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, struct posix_acl *default_acl, *acl; struct nfs3_createdata *data; int status = -ENOMEM; + struct dentry *d = NULL; dprintk("NFS call create %pd\n", dentry); @@ -355,6 +357,22 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, if (status != 0) goto out_release_acls; + /* Possible that nfs_instantiate() lost a race to open-by-fhandle, + * in which case we don't have a reference to the dentry */ + if (unlikely(d_unhashed(dentry))) { + d = lookup_one_len(dentry->d_name.name, dentry->d_parent, + dentry->d_name.len); + if (IS_ERR(d)) { + status = PTR_ERR(d); + goto out_release_acls; + } + if (unlikely(d_is_negative(d))) { + status = -ENOENT; + goto out_put_d; + } + dentry = d; + } + /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) { @@ -372,11 +390,13 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, nfs_post_op_update_inode(d_inode(dentry), data->res.fattr); dprintk("NFS reply setattr (post-create): %d\n", status); if (status != 0) - goto out_release_acls; + goto out_put_d; } status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl); +out_put_d: + dput(d); out_release_acls: posix_acl_release(acl); posix_acl_release(default_acl); -- 2.20.1