Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2c0cea6 authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

nfsd4: check for negative dentry before use in nfsv4 readdir



After 2f9092e1 "Fix i_mutex vs.  readdir
handling in nfsd" (and 14f7dd63 "Copy XFS readdir hack into nfsd code"),
an entry may be removed between the first mutex_unlock and the second
mutex_lock. In this case, lookup_one_len() will return a negative
dentry.  Check for this case to avoid a NULL dereference.

Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Reviewed-by: default avatarJ. R. Okajima <hooanon05@yahoo.co.jp>
Cc: stable@kernel.org
parent ccecee1e
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -2214,6 +2214,15 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
	dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
	if (IS_ERR(dentry))
		return nfserrno(PTR_ERR(dentry));
	if (!dentry->d_inode) {
		/*
		 * nfsd_buffered_readdir drops the i_mutex between
		 * readdir and calling this callback, leaving a window
		 * where this directory entry could have gone away.
		 */
		dput(dentry);
		return nfserr_noent;
	}

	exp_get(exp);
	/*
@@ -2276,6 +2285,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
	struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
	int buflen;
	__be32 *p = cd->buffer;
	__be32 *cookiep;
	__be32 nfserr = nfserr_toosmall;

	/* In nfsv4, "." and ".." never make it onto the wire.. */
@@ -2292,7 +2302,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
		goto fail;

	*p++ = xdr_one;                             /* mark entry present */
	cd->offset = p;                             /* remember pointer */
	cookiep = p;
	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
	p = xdr_encode_array(p, name, namlen);      /* name length & name */

@@ -2306,6 +2316,8 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
		goto fail;
	case nfserr_dropit:
		goto fail;
	case nfserr_noent:
		goto skip_entry;
	default:
		/*
		 * If the client requested the RDATTR_ERROR attribute,
@@ -2324,6 +2336,8 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
	}
	cd->buflen -= (p - cd->buffer);
	cd->buffer = p;
	cd->offset = cookiep;
skip_entry:
	cd->common.err = nfs_ok;
	return 0;
fail: