nfsclient: Propagate copyin() errors from nfsm_uiombuf()

Approved by:	so
Security:	SA-23:18.nfsclient
Reviewed by:	rmacklem
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Mark Johnston 2023-12-11 20:04:56 -05:00
parent 70547544ce
commit 6fa843f6e6
4 changed files with 39 additions and 13 deletions

View file

@ -370,7 +370,7 @@ int nfsrpc_destroysession(struct nfsmount *, struct nfsclsession *,
struct ucred *, NFSPROC_T *); struct ucred *, NFSPROC_T *);
/* nfs_clcomsubs.c */ /* 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); struct mbuf *nfsm_uiombuflist(struct uio *, int, u_int);
u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *); u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *);
int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **); int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **);

View file

@ -51,12 +51,12 @@ NFSCLSTATEMUTEX;
* copies a uio scatter/gather list to an mbuf chain. * copies a uio scatter/gather list to an mbuf chain.
* NOTE: can only handle iovcnt == 1 * NOTE: can only handle iovcnt == 1
*/ */
void int
nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz) nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
{ {
char *uiocp; char *uiocp;
struct mbuf *mp, *mp2; struct mbuf *mp, *mp2;
int xfer, left, mlen; int error, xfer, left, mlen;
int uiosiz, clflg, rem; int uiosiz, clflg, rem;
char *mcp, *tcp; char *mcp, *tcp;
@ -104,8 +104,11 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
xfer = (left > mlen) ? mlen : left; xfer = (left > mlen) ? mlen : left;
if (uiop->uio_segflg == UIO_SYSSPACE) if (uiop->uio_segflg == UIO_SYSSPACE)
NFSBCOPY(uiocp, mcp, xfer); NFSBCOPY(uiocp, mcp, xfer);
else else {
copyin(uiocp, mcp, xfer); error = copyin(uiocp, mcp, xfer);
if (error != 0)
return (error);
}
mp->m_len += xfer; mp->m_len += xfer;
left -= xfer; left -= xfer;
uiocp += xfer; uiocp += xfer;
@ -148,6 +151,7 @@ nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
} }
nd->nd_bpos = mcp; nd->nd_bpos = mcp;
nd->nd_mb = mp; nd->nd_mb = mp;
return (0);
} }
/* /*
@ -160,7 +164,7 @@ nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext)
{ {
char *uiocp; char *uiocp;
struct mbuf *mp, *mp2, *firstmp; 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; int uiosiz, clflg;
char *mcp, *tcp; char *mcp, *tcp;
@ -218,8 +222,13 @@ nfsm_uiombuflist(struct uio *uiop, int siz, u_int maxext)
xfer = (left > mlen) ? mlen : left; xfer = (left > mlen) ? mlen : left;
if (uiop->uio_segflg == UIO_SYSSPACE) if (uiop->uio_segflg == UIO_SYSSPACE)
NFSBCOPY(uiocp, mcp, xfer); NFSBCOPY(uiocp, mcp, xfer);
else else {
copyin(uiocp, mcp, xfer); error = copyin(uiocp, mcp, xfer);
if (error != 0) {
m_freem(firstmp);
return (NULL);
}
}
mp->m_len += xfer; mp->m_len += xfer;
mcp += xfer; mcp += xfer;
if (maxext > 0) { if (maxext > 0) {

View file

@ -2104,7 +2104,12 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
*tl++ = x; /* total to this offset */ *tl++ = x; /* total to this offset */
*tl = x; /* size of this write */ *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 * Although it is tempting to do a normal Getattr Op in the
* NFSv4 compound, the result can be a nearly hung client * 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; iovlen = uiop->uio_iov->iov_len;
m = nfsm_uiombuflist(uiop, len, m = nfsm_uiombuflist(uiop, len,
0); 0);
if (m == NULL) {
error = EFAULT;
break;
}
} }
tdrpc = drpc = malloc(sizeof(*drpc) * tdrpc = drpc = malloc(sizeof(*drpc) *
(mirrorcnt - 1), M_TEMP, M_WAITOK | (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(len);
*tl++ = txdr_unsigned(*iomode); *tl++ = txdr_unsigned(*iomode);
*tl = txdr_unsigned(len); *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; nrp = dsp->nfsclds_sockp;
if (nrp == NULL) if (nrp == NULL)
/* If NULL, use the MDS socket. */ /* 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_strtom(nd, name, strlen(name));
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(uiop->uio_resid); *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); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR); *tl = txdr_unsigned(NFSV4OP_GETATTR);
NFSGETATTR_ATTRBIT(&attrbits); NFSGETATTR_ATTRBIT(&attrbits);

View file

@ -1587,7 +1587,7 @@ ncl_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
error = nfscl_doiods(vp, uiop, NULL, NULL, error = nfscl_doiods(vp, uiop, NULL, NULL,
NFSV4OPEN_ACCESSREAD, 0, cred, uiop->uio_td); NFSV4OPEN_ACCESSREAD, 0, cred, uiop->uio_td);
NFSCL_DEBUG(4, "readrpc: aft doiods=%d\n", error); 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, error = nfsrpc_read(vp, uiop, cred, uiop->uio_td, &nfsva,
&attrflag); &attrflag);
if (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, error = nfscl_doiods(vp, uiop, iomode, must_commit,
NFSV4OPEN_ACCESSWRITE, 0, cred, uiop->uio_td); NFSV4OPEN_ACCESSWRITE, 0, cred, uiop->uio_td);
NFSCL_DEBUG(4, "writerpc: aft doiods=%d\n", error); 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, error = nfsrpc_write(vp, uiop, iomode, must_commit, cred,
uiop->uio_td, &nfsva, &attrflag, called_from_strategy, uiop->uio_td, &nfsva, &attrflag, called_from_strategy,
ioflag); ioflag);