On Sat, 22 Feb 2025, Al Viro wrote:
> On Fri, Feb 21, 2025 at 10:36:34AM +1100, NeilBrown wrote:
> 
> >  nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr 
> > *sattr)
> >  {
> >     struct posix_acl *default_acl, *acl;
> > @@ -612,15 +612,18 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry 
> > *dentry, struct iattr *sattr)
> >             dentry = d_alias;
> >  
> >     status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl);
> > +   if (status && d_alias)
> > +           dput(d_alias);
> >  
> > -   dput(d_alias);
> >  out_release_acls:
> >     posix_acl_release(acl);
> >     posix_acl_release(default_acl);
> >  out:
> >     nfs3_free_createdata(data);
> >     dprintk("NFS reply mkdir: %d\n", status);
> > -   return status;
> > +   if (status)
> > +           return ERR_PTR(status);
> > +   return d_alias;
> 
> Ugh...  That's really hard to follow - you are leaving a dangling
> reference in d_alias textually upstream of using that variable.
> The only reason it's not a bug is that dput() is reachable only
> with status && d_alias and that guarantees that we'll
> actually go away on if (status) return ERR_PTR(status).
> 
> Worse, you can reach 'out:' with d_alias uninitialized.  Yes,
> all such branches happen with status either still unmodified
> since it's initialization (which is non-zero) or under
> if (status), so again, that return d_alias; is unreachable.
> 
> So the code is correct, but it's really asking for trouble down
> the road.
> 
> BTW, dput(NULL) is guaranteed to be a no-op...
> 

Thanks for that.  I've minimised the use of status and mostly
stored errors in d_alias - which I've renamed to 'ret'.
I think that answers your concerns.

Thanks,
NeilBrown

--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -578,13 +578,13 @@ nfs3_proc_symlink(struct inode *dir, struct dentry 
*dentry, struct folio *folio,
        return status;
 }
 
-static int
+static struct dentry *
 nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 {
        struct posix_acl *default_acl, *acl;
        struct nfs3_createdata *data;
-       struct dentry *d_alias;
-       int status = -ENOMEM;
+       struct dentry *ret = ERR_PTR(-ENOMEM);
+       int status;
 
        dprintk("NFS call  mkdir %pd\n", dentry);
 
@@ -592,8 +592,9 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, 
struct iattr *sattr)
        if (data == NULL)
                goto out;
 
-       status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
-       if (status)
+       ret = ERR_PTR(posix_acl_create(dir, &sattr->ia_mode,
+                                      &default_acl, &acl));
+       if (IS_ERR(ret))
                goto out;
 
        data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
@@ -602,25 +603,27 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, 
struct iattr *sattr)
        data->arg.mkdir.len = dentry->d_name.len;
        data->arg.mkdir.sattr = sattr;
 
-       d_alias = nfs3_do_create(dir, dentry, data);
-       status = PTR_ERR_OR_ZERO(d_alias);
+       ret = nfs3_do_create(dir, dentry, data);
 
-       if (status != 0)
+       if (IS_ERR(ret))
                goto out_release_acls;
 
-       if (d_alias)
-               dentry = d_alias;
+       if (ret)
+               dentry = ret;
 
        status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl);
+       if (status) {
+               dput(ret);
+               ret = ERR_PTR(status);
+       }
 
-       dput(d_alias);
 out_release_acls:
        posix_acl_release(acl);
        posix_acl_release(default_acl);
 out:
        nfs3_free_createdata(data);
-       dprintk("NFS reply mkdir: %d\n", status);
-       return status;
+       dprintk("NFS reply mkdir: %d\n", PTR_ERR_OR_ZERO(ret));
+       return ret;
 }
 
 static int

Reply via email to