The branch main has been updated by markj:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=6fa843f6e647a1a1e0e42af1e7abc9e903699f31

commit 6fa843f6e647a1a1e0e42af1e7abc9e903699f31
Author:     Mark Johnston <[email protected]>
AuthorDate: 2023-12-12 01:04:56 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2023-12-12 19:05:24 +0000

    nfsclient: Propagate copyin() errors from nfsm_uiombuf()
    
    Approved by:    so
    Security:       SA-23:18.nfsclient
    Reviewed by:    rmacklem
    Sponsored by:   The FreeBSD Foundation
---
 sys/fs/nfs/nfs_var.h             |  2 +-
 sys/fs/nfsclient/nfs_clcomsubs.c | 23 ++++++++++++++++-------
 sys/fs/nfsclient/nfs_clrpcops.c  | 23 ++++++++++++++++++++---
 sys/fs/nfsclient/nfs_clvnops.c   |  4 ++--
 4 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 133850dcde0e..578fb3ce1340 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -370,7 +370,7 @@ int nfsrpc_destroysession(struct nfsmount *, struct 
nfsclsession *,
     struct ucred *, NFSPROC_T *);
 
 /* nfs_clcomsubs.c */
-void nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
+int nfsm_uiombuf(struct nfsrv_descript *, struct uio *, int);
 struct mbuf *nfsm_uiombuflist(struct uio *, int, u_int);
 u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *);
 int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **);
diff --git a/sys/fs/nfsclient/nfs_clcomsubs.c b/sys/fs/nfsclient/nfs_clcomsubs.c
index 7912ab56140f..270f39d03c90 100644
--- a/sys/fs/nfsclient/nfs_clcomsubs.c
+++ b/sys/fs/nfsclient/nfs_clcomsubs.c
@@ -51,12 +51,12 @@ NFSCLSTATEMUTEX;
  * copies a uio scatter/gather list to an mbuf chain.
  * NOTE: can only handle iovcnt == 1
  */
-void
+int
 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
 {
        char *uiocp;
        struct mbuf *mp, *mp2;
-       int xfer, left, mlen;
+       int error, xfer, left, mlen;
        int uiosiz, clflg, rem;
        char *mcp, *tcp;
 
@@ -104,8 +104,11 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, 
int siz)
                        xfer = (left > mlen) ? mlen : left;
                        if (uiop->uio_segflg == UIO_SYSSPACE)
                                NFSBCOPY(uiocp, mcp, xfer);
-                       else
-                               copyin(uiocp, mcp, xfer);
+                       else {
+                               error = copyin(uiocp, mcp, xfer);
+                               if (error != 0)
+                                       return (error);
+                       }
                        mp->m_len += xfer;
                        left -= xfer;
                        uiocp += xfer;
@@ -148,6 +151,7 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, 
int siz)
        }
        nd->nd_bpos = mcp;
        nd->nd_mb = mp;
+       return (0);
 }
 
 /*
@@ -160,7 +164,7 @@ nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext)
 {
        char *uiocp;
        struct mbuf *mp, *mp2, *firstmp;
-       int extpg, extpgsiz = 0, i, left, mlen, rem, xfer;
+       int error, extpg, extpgsiz = 0, i, left, mlen, rem, xfer;
        int uiosiz, clflg;
        char *mcp, *tcp;
 
@@ -218,8 +222,13 @@ nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext)
                        xfer = (left > mlen) ? mlen : left;
                        if (uiop->uio_segflg == UIO_SYSSPACE)
                                NFSBCOPY(uiocp, mcp, xfer);
-                       else
-                               copyin(uiocp, mcp, xfer);
+                       else {
+                               error = copyin(uiocp, mcp, xfer);
+                               if (error != 0) {
+                                       m_freem(firstmp);
+                                       return (NULL);
+                               }
+                       }
                        mp->m_len += xfer;
                        mcp += xfer;
                        if (maxext > 0) {
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 86c2959b1209..e9acedfb6473 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -2104,7 +2104,12 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int 
*iomode,
                        *tl++ = x;      /* total to this offset */
                        *tl = x;        /* size of this write */
                }
-               nfsm_uiombuf(nd, uiop, len);
+               error = nfsm_uiombuf(nd, uiop, len);
+               if (error != 0) {
+                       m_freem(nd->nd_mreq);
+                       free(nd, M_TEMP);
+                       return (error);
+               }
                /*
                 * Although it is tempting to do a normal Getattr Op in the
                 * NFSv4 compound, the result can be a nearly hung client
@@ -6361,6 +6366,10 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, 
int *must_commit,
                                                iovlen = uiop->uio_iov->iov_len;
                                                m = nfsm_uiombuflist(uiop, len,
                                                    0);
+                                               if (m == NULL) {
+                                                       error = EFAULT;
+                                                       break;
+                                               }
                                        }
                                        tdrpc = drpc = malloc(sizeof(*drpc) *
                                            (mirrorcnt - 1), M_TEMP, M_WAITOK |
@@ -6933,7 +6942,11 @@ nfsrpc_writeds(vnode_t vp, struct uio *uiop, int 
*iomode, int *must_commit,
                *tl++ = txdr_unsigned(len);
        *tl++ = txdr_unsigned(*iomode);
        *tl = txdr_unsigned(len);
-       nfsm_uiombuf(nd, uiop, len);
+       error = nfsm_uiombuf(nd, uiop, len);
+       if (error != 0) {
+               m_freem(nd->nd_mreq);
+               return (error);
+       }
        nrp = dsp->nfsclds_sockp;
        if (nrp == NULL)
                /* If NULL, use the MDS socket. */
@@ -9057,7 +9070,11 @@ nfsrpc_setextattr(vnode_t vp, const char *name, struct 
uio *uiop,
        nfsm_strtom(nd, name, strlen(name));
        NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(uiop->uio_resid);
-       nfsm_uiombuf(nd, uiop, uiop->uio_resid);
+       error = nfsm_uiombuf(nd, uiop, uiop->uio_resid);
+       if (error != 0) {
+               m_freem(nd->nd_mreq);
+               return (error);
+       }
        NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_GETATTR);
        NFSGETATTR_ATTRBIT(&attrbits);
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 5c9ca69b5d51..a690e988b4b3 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1587,7 +1587,7 @@ ncl_readrpc(struct vnode *vp, struct uio *uiop, struct 
ucred *cred)
                error = nfscl_doiods(vp, uiop, NULL, NULL,
                    NFSV4OPEN_ACCESSREAD, 0, cred, uiop->uio_td);
        NFSCL_DEBUG(4, "readrpc: aft doiods=%d\n", error);
-       if (error != 0)
+       if (error != 0 && error != EFAULT)
                error = nfsrpc_read(vp, uiop, cred, uiop->uio_td, &nfsva,
                    &attrflag);
        if (attrflag) {
@@ -1618,7 +1618,7 @@ ncl_writerpc(struct vnode *vp, struct uio *uiop, struct 
ucred *cred,
                error = nfscl_doiods(vp, uiop, iomode, must_commit,
                    NFSV4OPEN_ACCESSWRITE, 0, cred, uiop->uio_td);
        NFSCL_DEBUG(4, "writerpc: aft doiods=%d\n", error);
-       if (error != 0)
+       if (error != 0 && error != EFAULT)
                error = nfsrpc_write(vp, uiop, iomode, must_commit, cred,
                    uiop->uio_td, &nfsva, &attrflag, called_from_strategy,
                    ioflag);

Reply via email to