1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-18 07:13:36 +02:00

Add checks for invalid dir count and max size for readdir/readdirplus.

A zero count or max size value is now rejected early instead of
relying on VOP_GETATTR to return an error.  Also verify that the
max size after rounding up to a multiple of DIRBLKSIZ is positive.
A negative value would turn into a large allocation, causing the
malloc() to fail.

From an LLM bug report.  With help from miod@ and kirill@.
This commit is contained in:
millert
2026-05-04 17:05:59 +00:00
parent 887f67889a
commit 8cfd5285c0
+34 -23
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: nfs_serv.c,v 1.132 2025/04/30 18:38:20 miod Exp $ */
/* $OpenBSD: nfs_serv.c,v 1.133 2026/05/04 17:05:59 millert Exp $ */
/* $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $ */
/*
@@ -2427,17 +2427,24 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
}
off = toff;
cnt = fxdr_unsigned(int, *tl);
xfer = NFS_SRVMAXDATA(nfsd);
if (cnt > xfer || cnt < 0)
cnt = xfer;
siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
if (siz > xfer)
siz = xfer;
fullsiz = siz;
error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
if (!error && vp->v_type != VDIR) {
error = ENOTDIR;
vput(vp);
if (cnt == 0) {
if (info.nmi_v3)
error = NFSERR_TOOSMALL;
else
error = EBADRPC;
} else {
xfer = NFS_SRVMAXDATA(nfsd);
if (cnt > xfer || cnt < 0)
cnt = xfer;
siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
if (siz > xfer || siz <= 0)
siz = xfer;
fullsiz = siz;
error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
if (!error && vp->v_type != VDIR) {
error = ENOTDIR;
vput(vp);
}
}
if (error) {
if (nfsm_reply(&info, nfsd, slp, mrq, error,
@@ -2649,17 +2656,21 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
tl += 2;
siz = fxdr_unsigned(int, *tl++);
cnt = fxdr_unsigned(int, *tl);
xfer = NFS_SRVMAXDATA(nfsd);
if (cnt > xfer || cnt < 0)
cnt = xfer;
siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
if (siz > xfer)
siz = xfer;
fullsiz = siz;
error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
if (!error && vp->v_type != VDIR) {
error = ENOTDIR;
vput(vp);
if (siz == 0 || cnt == 0) {
error = NFSERR_TOOSMALL;
} else {
xfer = NFS_SRVMAXDATA(nfsd);
if (cnt > xfer || cnt < 0)
cnt = xfer;
siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
if (siz > xfer || siz <= 0)
siz = xfer;
fullsiz = siz;
error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
if (!error && vp->v_type != VDIR) {
error = ENOTDIR;
vput(vp);
}
}
if (error) {
if (nfsm_reply(&info, nfsd, slp, mrq, error,