Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 May 2017 12:36:18 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 219472] Out of bounds access in vlan
Message-ID:  <bug-219472-8@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=219472

            Bug ID: 219472
           Summary: Out of bounds access in vlan
           Product: Base System
           Version: CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs@FreeBSD.org
          Reporter: ecturt@gmail.com

This whole struct (`ifv_mib`) is user controllable through the
`IFDATA_LINKSPECIFIC` sysctl command:

https://github.com/freebsd/freebsd/blob/release/11.0.1/sys/net/if_mib.c#L117

        case IFDATA_LINKSPECIFIC:
                error = SYSCTL_OUT(req, ifp->if_linkmib, ifp->if_linkmiblen);
                if (error || !req->newptr)
                        goto out;

                error = SYSCTL_IN(req, ifp->if_linkmib, ifp->if_linkmiblen);
                if (error)
                        goto out;
                        break;

In the case of `struct ifvlan`, the contained `if_linkmib` is a `struct
ifv_linkmib` containing a `uint16_t` called `ifvm_vid`:

https://github.com/freebsd/freebsd/blob/release/11.0.1/sys/net/if_vlan.c#L108

struct  ifvlan {
        struct  ifvlantrunk *ifv_trunk;
        struct  ifnet *ifv_ifp;
#define TRUNK(ifv)      ((ifv)->ifv_trunk)
#define PARENT(ifv)     ((ifv)->ifv_trunk->parent)
        void    *ifv_cookie;
        int     ifv_pflags;     /* special flags we have set on parent */
        struct  ifv_linkmib {
                int     ifvm_encaplen;  /* encapsulation length */
                int     ifvm_mtufudge;  /* MTU fudged by this much */
                int     ifvm_mintu;     /* min transmission unit */
                uint16_t ifvm_proto;    /* encapsulation ethertype */
                uint16_t ifvm_tag;      /* tag to apply on packets leaving if
*/
                uint16_t ifvm_vid;      /* VLAN ID */
                uint8_t ifvm_pcp;       /* Priority Code Point (PCP). */
        }       ifv_mib;
        SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead;
#ifndef VLAN_ARRAY
        LIST_ENTRY(ifvlan) ifv_list;
#endif
};
#define ifv_proto       ifv_mib.ifvm_proto
#define ifv_tag         ifv_mib.ifvm_tag
#define ifv_vid         ifv_mib.ifvm_vid
#define ifv_pcp         ifv_mib.ifvm_pcp
#define ifv_encaplen    ifv_mib.ifvm_encaplen
#define ifv_mtufudge    ifv_mib.ifvm_mtufudge
#define ifv_mintu       ifv_mib.ifvm_mintu

Thus, it follows that `ifv->ifv_vid` is a completely user controlled
`uint16_t`, through the `IFDATA_LINKSPECIFIC` `sysctl` name.

This value is used as an index to perform reads and writes on the `vlans` array
of size `0x1000` in multiple places.

https://github.com/freebsd/freebsd/blob/release/11.0.1/sys/net/if_vlan.c#L427

static __inline int
vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
{

        if (trunk->vlans[ifv->ifv_vid] != NULL)
                return EEXIST;
        trunk->vlans[ifv->ifv_vid] = ifv;
        trunk->refcnt++;

        return (0);
}

static __inline int
vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
{

        trunk->vlans[ifv->ifv_vid] = NULL;
        trunk->refcnt--;

        return (0);
}

...

However, this is a static array of size `VLAN_ARRAY_SIZE` (`0x1000`) elements:

https://github.com/freebsd/freebsd/blob/release/11.0.1/sys/net/ethernet.h#L86

#define EVL_VLID_MASK 0x0FFF

https://github.com/freebsd/freebsd/blob/release/11.0.1/sys/net/if_vlan.c#L89

struct ifvlantrunk {
        struct  ifnet   *parent;        /* parent interface of this trunk */
        struct  rmlock  lock;
#ifdef VLAN_ARRAY
#define VLAN_ARRAY_SIZE (EVL_VLID_MASK + 1)
        struct  ifvlan  *vlans[VLAN_ARRAY_SIZE]; /* static table */
#else
        struct  ifvlanhead *hash;       /* dynamic hash-list table */
        uint16_t        hmask;
        uint16_t        hwidth;
#endif
        int             refcnt;
};

So, out of bounds access is possible if `ifv_vid` is set to a value greater
than `0xfff`.

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