summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1999-11-30 06:56:15 +0000
committerdillon <dillon@FreeBSD.org>1999-11-30 06:56:15 +0000
commit679b553dfa3bff9c4f61583330de3dcc30c5167d (patch)
treef2820dde0b12799fb5f43c84ec0c25e80a9fea50 /sys
parent3c1a09eca379aa495e106a062c015cdf1e4b0d01 (diff)
downloadFreeBSD-src-679b553dfa3bff9c4f61583330de3dcc30c5167d.zip
FreeBSD-src-679b553dfa3bff9c4f61583330de3dcc30c5167d.tar.gz
The symlink implementation could improperly return a NULL vp along with
a 0 error code. The problem occured with NFSv2 mounts and also with any NFSv3 mount returning an EEXIST error (which is translated to 0 prior to return). The reply to the rpc only contains the file handle for the no-error case under NFSv3. The error case under NFSv3 and all cases under NFSv2 do *not* return the file handle. The fix is to do a secondary lookup to obtain the file handle and thus be able to generate a return vnode for the situations where the rpc reply does not contain the required information. The bug was originally introduced when VOP_SYMLINK semantics were changed for -CURRENT. The NFS symlink implementation was not properly modified to go along with the change despite the fact that three people reviewed the code. It took four attempts to get the current fix correct with five people. Is NFS obfuscated? Ha! Reviewed by: Alfred Perlstein <bright@wintelcom.net> Testing and Discussion: "Viren R.Shah" <viren@rstcorp.com>, Eivind Eklund <eivind@FreeBSD.ORG>, Ian Dowse <iedowse@maths.tcd.ie>
Diffstat (limited to 'sys')
-rw-r--r--sys/nfs/nfs_vnops.c36
-rw-r--r--sys/nfsclient/nfs_vnops.c36
2 files changed, 66 insertions, 6 deletions
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index 6c6ae61..e53b295 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -1805,24 +1805,54 @@ nfs_symlink(ap)
txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
+
+ /*
+ * Issue the NFS request and get the rpc response.
+ *
+ * Only NFSv3 responses returning an error of 0 actually return
+ * a file handle that can be converted into newvp without having
+ * to do an extra lookup rpc.
+ */
nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
if (v3) {
- if (!error)
+ if (error == 0)
nfsm_mtofh(dvp, newvp, v3, gotvp);
nfsm_wcc_data(dvp, wccflag);
}
+
+ /*
+ * out code jumps -> here, mrep is also freed.
+ */
+
nfsm_reqdone;
+
/*
- * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+ * If we get an EEXIST error, silently convert it to no-error
+ * in case of an NFS retry.
*/
if (error == EEXIST)
error = 0;
+ /*
+ * If we do not have (or no longer have) an error, and we could
+ * not extract the newvp from the response due to the request being
+ * NFSv2 or the error being EEXIST. We have to do a lookup in order
+ * to obtain a newvp to return.
+ */
+ if (error == 0 && newvp == NULL) {
+ struct nfsnode *np = NULL;
+
+ error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
+ cnp->cn_cred, cnp->cn_proc, &np);
+ if (!error)
+ newvp = NFSTOV(np);
+ }
if (error) {
if (newvp)
vput(newvp);
- } else
+ } else {
*ap->a_vpp = newvp;
+ }
VTONFS(dvp)->n_flag |= NMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index 6c6ae61..e53b295 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -1805,24 +1805,54 @@ nfs_symlink(ap)
txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
}
+
+ /*
+ * Issue the NFS request and get the rpc response.
+ *
+ * Only NFSv3 responses returning an error of 0 actually return
+ * a file handle that can be converted into newvp without having
+ * to do an extra lookup rpc.
+ */
nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
if (v3) {
- if (!error)
+ if (error == 0)
nfsm_mtofh(dvp, newvp, v3, gotvp);
nfsm_wcc_data(dvp, wccflag);
}
+
+ /*
+ * out code jumps -> here, mrep is also freed.
+ */
+
nfsm_reqdone;
+
/*
- * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+ * If we get an EEXIST error, silently convert it to no-error
+ * in case of an NFS retry.
*/
if (error == EEXIST)
error = 0;
+ /*
+ * If we do not have (or no longer have) an error, and we could
+ * not extract the newvp from the response due to the request being
+ * NFSv2 or the error being EEXIST. We have to do a lookup in order
+ * to obtain a newvp to return.
+ */
+ if (error == 0 && newvp == NULL) {
+ struct nfsnode *np = NULL;
+
+ error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
+ cnp->cn_cred, cnp->cn_proc, &np);
+ if (!error)
+ newvp = NFSTOV(np);
+ }
if (error) {
if (newvp)
vput(newvp);
- } else
+ } else {
*ap->a_vpp = newvp;
+ }
VTONFS(dvp)->n_flag |= NMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
OpenPOWER on IntegriCloud