aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2023-12-12 01:04:56 +0000
committerMark Johnston <markj@FreeBSD.org>2023-12-12 19:12:06 +0000
commitf1d1d50e1d089f0bfcd38e5f08b1e8bf5a1d64c3 (patch)
tree7a0127432a5c168dedd1d993d834acd099248d10
parent7a241fa3182ba3e72a4e72011c6441a98cd63b0b (diff)
nfsclient: Propagate copyin() errors from nfsm_uiombuf()
Approved by: so Security: SA-23:18.nfsclient Reviewed by: rmacklem Sponsored by: The FreeBSD Foundation (cherry picked from commit 6fa843f6e647a1a1e0e42af1e7abc9e903699f31)
-rw-r--r--sys/fs/nfs/nfs_var.h2
-rw-r--r--sys/fs/nfsclient/nfs_clcomsubs.c23
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c23
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c4
4 files changed, 39 insertions, 13 deletions
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 61badf781a0a..8cdc08fba433 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -367,7 +367,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 f52de5d601ee..f2031220b80e 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 569132aee43c..63b9f7755fd3 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -1929,7 +1929,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
@@ -6043,6 +6048,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 |
@@ -6615,7 +6624,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. */
@@ -8701,7 +8714,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 02449e64e508..642963694a0a 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1581,7 +1581,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, NULL);
if (attrflag) {
@@ -1612,7 +1612,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);