The branch stable/13 has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=54ccbc9bb6c5a5077e8cda21902a6e9dc188c6cf

commit 54ccbc9bb6c5a5077e8cda21902a6e9dc188c6cf
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2021-06-04 03:48:26 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2021-06-26 22:50:16 +0000

    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)
---
 sys/fs/nfsserver/nfs_nfsdsocket.c | 109 ++++++++++++++++++++++++++++++++++----
 1 file 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) {
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to