Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 13 Apr 2016 19:29:18 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 206626] Integer overflow in nfssvc system call
Message-ID:  <bug-206626-8-Kbst45zkNZ@https.bugs.freebsd.org/bugzilla/>
In-Reply-To: <bug-206626-8@https.bugs.freebsd.org/bugzilla/>
References:  <bug-206626-8@https.bugs.freebsd.org/bugzilla/>

next in thread | previous in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D206626

--- Comment #2 from CTurt <cturt@hardenedbsd.org> ---
It is possible to get panic from this bug by reducing the `nid_namelen` val=
ue
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 =3D 0;
        u_char *cp;

+       if (nidp->nid_namelen < 0 || nidp->nid_namelen > 128) {
+               error =3D EINVAL;
+               goto exit;
+       }
+
        ...

Additionally, to better explain this bug, I've decided to go through the fu=
ll
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 wil=
l 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) !=3D 0) {
                error =3D priv_check(td, PRIV_NFS_DAEMON);
                if (error !=3D 0)
                        return (error);
        }
        error =3D 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 !=3D NULL)
                error =3D (*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_commo=
nport.c#L433

static int
nfssvc_nfscommon(struct thread *td, struct nfssvc_args *uap)
{
        int error;

        error =3D 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 =3D EINVAL;
        struct nfsd_idargs nid;

        if (uap->flag & NFSSVC_IDNAME) {
                error =3D copyin(uap->argp, (caddr_t)&nid, sizeof (nid));
                if (error)
                        goto out;
                error =3D 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 si=
ze:

https://github.com/freebsd/freebsd/blob/release/10.2.0/sys/fs/nfs/nfs_commo=
nsubs.c#L3093

APPLESTATIC int
nfssvc_idname(struct nfsd_idargs *nidp)
{
        struct nfsusrgrp *nusrp, *usrp, *newusrp;
        struct nfsuserhashhead *hp;
        int i;
        int error =3D 0;
        u_char *cp;

        if (nidp->nid_flag & NFSID_INITIALIZE) {
            cp =3D (u_char *)malloc(nidp->nid_namelen + 1,
                M_NFSSTRING, M_WAITOK);
            error =3D copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
                nidp->nid_namelen);
                ...

--=20
You are receiving this mail because:
You are the assignee for the bug.=



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-206626-8-Kbst45zkNZ>