aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2021-06-04 03:48:26 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2021-06-26 22:50:16 +0000
commit54ccbc9bb6c5a5077e8cda21902a6e9dc188c6cf (patch)
tree98c4ae08a87af3fb61055993fbe3b468611bf16f
parent92500ec0c45cbef90634fb9987287ac2768ab475 (diff)
downloadsrc-54ccbc9bb6c5a5077e8cda21902a6e9dc188c6cf.tar.gz
src-54ccbc9bb6c5a5077e8cda21902a6e9dc188c6cf.zip
nfsd: Pre-parse the next NFSv4 operation number for put FH operations
RFC5661 Sec. 2.6 specifies when a NFSERR_WRONGSEC error reply can be done. For the four operations PutFH, PutrootFH, PutpublicFH and RestoreFH, NFSERR_WRONGSEC can or cannot be replied, depending upon what operation follows one of these operations in the compound. This patch modifies nfsrvd_compound() so that it parses the next operation number before executing any of the above four operations, storing it in "nextop". A future commit will implement use of "nextop" to decide if NFSERR_WRONGSEC can be replied for the above four operations. This commit should not change the semantics of performing the compound RPC. (cherry picked from commit d224f05fcfc13725c43ea0a02d511b3bf6a8ad14)
-rw-r--r--sys/fs/nfsserver/nfs_nfsdsocket.c109
1 files changed, 100 insertions, 9 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c
index a8e1757835ac..f40569da0097 100644
--- a/sys/fs/nfsserver/nfs_nfsdsocket.c
+++ b/sys/fs/nfsserver/nfs_nfsdsocket.c
@@ -705,7 +705,7 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
int i, lktype, op, op0 = 0, statsinprog = 0;
u_int32_t *tl;
struct nfsclient *clp, *nclp;
- int numops, error = 0, igotlock;
+ int error = 0, igotlock, nextop, numops, savefhcnt;
u_int32_t retops = 0, *retopsp = NULL, *repp;
vnode_t vp, nvp, savevp;
struct nfsrvfh fh;
@@ -822,6 +822,8 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
savevp = vp = NULL;
save_fsid.val[0] = save_fsid.val[1] = 0;
cur_fsid.val[0] = cur_fsid.val[1] = 0;
+ nextop = -1;
+ savefhcnt = 0;
/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
if (taglen < 0) {
@@ -850,10 +852,20 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
* savevpnes and vpnes - are the export flags for the above.
*/
for (i = 0; i < numops; i++) {
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
- *repp = *tl;
- op = fxdr_unsigned(int, *tl);
+ if (savefhcnt > 0) {
+ op = NFSV4OP_SAVEFH;
+ *repp = txdr_unsigned(op);
+ savefhcnt--;
+ } else if (nextop == -1) {
+ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
+ *repp = *tl;
+ op = fxdr_unsigned(int, *tl);
+ } else {
+ op = nextop;
+ *repp = txdr_unsigned(op);
+ nextop = -1;
+ }
NFSD_DEBUG(4, "op=%d\n", op);
if (op < NFSV4OP_ACCESS || op >= NFSV42_NOPS ||
(op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
@@ -950,6 +962,25 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
error = nfsrv_mtofh(nd, &fh);
if (error)
goto nfsmout;
+ if ((nd->nd_flag & ND_LASTOP) == 0) {
+ /*
+ * Pre-parse the next op#. If it is
+ * SaveFH, count it and skip to the
+ * next op#, if not the last op#.
+ * nextop is used to determine if
+ * NFSERR_WRONGSEC can be returned,
+ * per RFC5661 Sec. 2.6.
+ */
+ do {
+ NFSM_DISSECT(tl, uint32_t *,
+ NFSX_UNSIGNED);
+ nextop = fxdr_unsigned(int, *tl);
+ if (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1)
+ savefhcnt++;
+ } while (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1);
+ }
if (!nd->nd_repstat)
nfsd_fhtovp(nd, &fh, LK_SHARED, &nvp, &nes,
NULL, 0);
@@ -964,11 +995,31 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
}
break;
case NFSV4OP_PUTPUBFH:
- if (nfs_pubfhset)
- nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
- &nes, NULL, 0);
- else
- nd->nd_repstat = NFSERR_NOFILEHANDLE;
+ if (nfs_pubfhset) {
+ if ((nd->nd_flag & ND_LASTOP) == 0) {
+ /*
+ * Pre-parse the next op#. If it is
+ * SaveFH, count it and skip to the
+ * next op#, if not the last op#.
+ * nextop is used to determine if
+ * NFSERR_WRONGSEC can be returned,
+ * per RFC5661 Sec. 2.6.
+ */
+ do {
+ NFSM_DISSECT(tl, uint32_t *,
+ NFSX_UNSIGNED);
+ nextop = fxdr_unsigned(int,
+ *tl);
+ if (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1)
+ savefhcnt++;
+ } while (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1);
+ }
+ nfsd_fhtovp(nd, &nfs_pubfh, LK_SHARED, &nvp,
+ &nes, NULL, 0);
+ } else
+ nd->nd_repstat = NFSERR_NOFILEHANDLE;
if (!nd->nd_repstat) {
if (vp)
vrele(vp);
@@ -980,6 +1031,26 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
break;
case NFSV4OP_PUTROOTFH:
if (nfs_rootfhset) {
+ if ((nd->nd_flag & ND_LASTOP) == 0) {
+ /*
+ * Pre-parse the next op#. If it is
+ * SaveFH, count it and skip to the
+ * next op#, if not the last op#.
+ * nextop is used to determine if
+ * NFSERR_WRONGSEC can be returned,
+ * per RFC5661 Sec. 2.6.
+ */
+ do {
+ NFSM_DISSECT(tl, uint32_t *,
+ NFSX_UNSIGNED);
+ nextop = fxdr_unsigned(int,
+ *tl);
+ if (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1)
+ savefhcnt++;
+ } while (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1);
+ }
nfsd_fhtovp(nd, &nfs_rootfh, LK_SHARED, &nvp,
&nes, NULL, 0);
if (!nd->nd_repstat) {
@@ -1016,6 +1087,26 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
break;
case NFSV4OP_RESTOREFH:
if (savevp) {
+ if ((nd->nd_flag & ND_LASTOP) == 0) {
+ /*
+ * Pre-parse the next op#. If it is
+ * SaveFH, count it and skip to the
+ * next op#, if not the last op#.
+ * nextop is used to determine if
+ * NFSERR_WRONGSEC can be returned,
+ * per RFC5661 Sec. 2.6.
+ */
+ do {
+ NFSM_DISSECT(tl, uint32_t *,
+ NFSX_UNSIGNED);
+ nextop = fxdr_unsigned(int,
+ *tl);
+ if (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1)
+ savefhcnt++;
+ } while (nextop == NFSV4OP_SAVEFH &&
+ i < numops - 1);
+ }
nd->nd_repstat = 0;
/* If vp == savevp, a no-op */
if (vp != savevp) {