https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=206626
--- Comment #2 from CTurt <ct...@hardenedbsd.org> --- It is possible to get panic from this bug by reducing the `nid_namelen` value to `0xfffffffe`. In this case, the system will panic due to a general protection fault in `vmem_alloc`. I've updated the PoC code to cause panic by this method (https://gist.github.com/CTurt/957360482a4dc453f6a4). The patch for this bug is to add appropriate bound checks to `nfssvc_idname` in `sys/fs/nfs/nfs_commonsubs.c`: APPLESTATIC int nfssvc_idname(struct nfsd_idargs *nidp) { struct nfsusrgrp *nusrp, *usrp, *newusrp; struct nfsuserhashhead *hp; int i; int error = 0; u_char *cp; + if (nidp->nid_namelen < 0 || nidp->nid_namelen > 128) { + error = EINVAL; + goto exit; + } + ... Additionally, to better explain this bug, I've decided to go through the full code path to trigger it: When supplying the `NFSSVC_IDNAME` flag to the `nfssvc` system call, after passing the privilege check, the `nfsd_call_nfscommon` function pointer will be called, which points to `nfssvc_nfscommon`: https://github.com/freebsd/freebsd/blob/release/10.2.0/sys/nfs/nfs_nfssvc.c#L75 int sys_nfssvc(struct thread *td, struct nfssvc_args *uap) { int error; KASSERT(!mtx_owned(&Giant), ("nfssvc(): called with Giant")); AUDIT_ARG_CMD(uap->flag); /* Allow anyone to get the stats. */ if ((uap->flag & ~NFSSVC_GETSTATS) != 0) { error = priv_check(td, PRIV_NFS_DAEMON); if (error != 0) return (error); } error = EINVAL; if ((uap->flag & (NFSSVC_ADDSOCK | NFSSVC_OLDNFSD | NFSSVC_NFSD)) && ... else if ((uap->flag & (NFSSVC_IDNAME | NFSSVC_GETSTATS | NFSSVC_GSSDADDPORT | NFSSVC_GSSDADDFIRST | NFSSVC_GSSDDELETEALL | NFSSVC_NFSUSERDPORT | NFSSVC_NFSUSERDDELPORT)) && nfsd_call_nfscommon != NULL) error = (*nfsd_call_nfscommon)(td, uap); ... return (error); } `nfssvc_nfscommon` then calls `nfssvc_call`: https://github.com/freebsd/freebsd/blob/release/10.2.0/sys/fs/nfs/nfs_commonport.c#L433 static int nfssvc_nfscommon(struct thread *td, struct nfssvc_args *uap) { int error; error = nfssvc_call(td, uap, td->td_ucred); NFSEXITCODE(error); return (error); } The `nfsd_idargs` struct will then be copied in from userland, and passed to `nfssvc_idname`: static int nfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) { int error = EINVAL; struct nfsd_idargs nid; if (uap->flag & NFSSVC_IDNAME) { error = copyin(uap->argp, (caddr_t)&nid, sizeof (nid)); if (error) goto out; error = nfssvc_idname(&nid); goto out; ... In `nfssvc_idname` we have an allocation with `nidp->nid_namelen + 1`, and then `copyin` with `nidp->nid_namelen`. There were no bound checks on `nidp->nid_namelen`, so we have `malloc` with completely user controlled size: https://github.com/freebsd/freebsd/blob/release/10.2.0/sys/fs/nfs/nfs_commonsubs.c#L3093 APPLESTATIC int nfssvc_idname(struct nfsd_idargs *nidp) { struct nfsusrgrp *nusrp, *usrp, *newusrp; struct nfsuserhashhead *hp; int i; int error = 0; u_char *cp; if (nidp->nid_flag & NFSID_INITIALIZE) { cp = (u_char *)malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, nidp->nid_namelen); ... -- You are receiving this mail because: You are the assignee for the bug. _______________________________________________ freebsd-bugs@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-bugs To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"