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));