DragonFlyBSD Kernel Audit
DF-0768 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/nfs/nfs_vnops.c b/sys/vfs/nfs/nfs_vnops.c
index 0000000..1111111 100644
--- a/sys/vfs/nfs/nfs_vnops.c
+++ b/sys/vfs/nfs/nfs_vnops.c
@@ -2922,9 +2922,29 @@
 				}
 			    }
 			} else {
+			    /*
+			     * Skip over the file handle.  The handle length
+			     * `i` is server-controlled, so bound it to
+			     * NFSX_V3FHMAX (as nfsm_getfh() does) before
+			     * calling nfsm_rndup(i).  Without this bound a
+			     * malicious READDIRPLUS reply can set i >=
+			     * 0x7FFFFFFD, which overflows nfsm_rndup(a)=
+			     * ((a)+3)&~3 to INT_MIN; nfsm_adv() then treats
+			     * the negative length as "fits in cluster",
+			     * corrupting info.dpos into a wild pointer and
+			     * panicking the kernel on the next dissect.
+			     * i == 0 is the legitimate post_op_fh3
+			     * handle_follows == 0 ("no handle") case.
+			     */
 			    /* Just skip over the file handle */
 			    NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
 			    i = fxdr_unsigned(int, *tl);
+			    if (i < 0 || i > NFSX_V3FHMAX) {
+				error = EBADRPC;
+				m_freem(info.mrep);
+				info.mrep = NULL;
+				goto nfsmout;
+			    }
 			    ERROROUT(nfsm_adv(&info, nfsm_rndup(i)));
 			}
 			NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));