Fix some long standing bugs in writing to the BPF device attached to

a DLT_NULL interface. In particular:

        1) Consistently use type u_int32_t for the header of a
           DLT_NULL device - it continues to represent the address
           family as always.
        2) In the DLT_NULL case get bpf_movein to store the u_int32_t
           in a sockaddr rather than in the mbuf, to be consistent
           with all the DLT types.
        3) Consequently fix a bug in bpf_movein/bpfwrite which
           only permitted packets up to 4 bytes less than the MTU
           to be written.
        4) Fix all DLT_NULL devices to have the code required to
           allow writing to their bpf devices.
        5) Move the code to allow writing to if_lo from if_simloop
           to looutput, because it only applies to DLT_NULL devices
           but was being applied to other devices that use if_simloop
           possibly incorrectly.

PR:		82157
Submitted by:	Matthew Luckie <mjl@luckie.org.nz>
Approved by:	re (scottl)
This commit is contained in:
David Malone 2005-06-26 18:11:11 +00:00
parent 7db9a6fcd1
commit 01399f34a5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=147611
13 changed files with 106 additions and 59 deletions

View File

@ -374,7 +374,13 @@ icoutput(struct ifnet *ifp, struct mbuf *m,
int s, len, sent;
struct mbuf *mm;
u_char *cp;
u_int32_t hdr = dst->sa_family;
u_int32_t hdr;
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &hdr, sizeof(hdr));
else
hdr = dst->sa_family;
ifp->if_flags |= IFF_RUNNING;

View File

@ -272,7 +272,7 @@ i4biprattach(void *dummy)
if_attach(sc->sc_ifp);
bpfattach(sc->sc_ifp, DLT_NULL, sizeof(u_int));
bpfattach(sc->sc_ifp, DLT_NULL, sizeof(u_int32_t));
}
}
@ -288,12 +288,20 @@ i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
int s;
struct ifqueue *ifq;
struct ip *ip;
u_int32_t af;
s = SPLI4B();
sc = ifp->if_softc;
unit = ifp->if_dunit;
/* BPF writes need to be handled specially. */
if(dst->sa_family == AF_UNSPEC)
{
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
/* check for IP */
if(dst->sa_family != AF_INET)

View File

@ -106,8 +106,8 @@ static void bpf_attachd(struct bpf_d *d, struct bpf_if *bp);
static void bpf_detachd(struct bpf_d *d);
static void bpf_freed(struct bpf_d *);
static void bpf_mcopy(const void *, void *, size_t);
static int bpf_movein(struct uio *, int,
struct mbuf **, struct sockaddr *, int *);
static int bpf_movein(struct uio *, int, int,
struct mbuf **, struct sockaddr *);
static int bpf_setif(struct bpf_d *, struct ifreq *);
static void bpf_timed_out(void *);
static __inline void
@ -148,9 +148,10 @@ static struct filterops bpfread_filtops =
{ 1, NULL, filt_bpfdetach, filt_bpfread };
static int
bpf_movein(uio, linktype, mp, sockp, datlen)
bpf_movein(uio, linktype, mtu, mp, sockp)
struct uio *uio;
int linktype, *datlen;
int linktype;
int mtu;
struct mbuf **mp;
struct sockaddr *sockp;
{
@ -187,11 +188,19 @@ bpf_movein(uio, linktype, mp, sockp, datlen)
break;
case DLT_RAW:
case DLT_NULL:
sockp->sa_family = AF_UNSPEC;
hlen = 0;
break;
case DLT_NULL:
/*
* null interface types require a 4 byte pseudo header which
* corresponds to the address family of the packet.
*/
sockp->sa_family = AF_UNSPEC;
hlen = 4;
break;
case DLT_ATM_RFC1483:
/*
* en atm driver requires 4-byte atm pseudo header.
@ -212,7 +221,10 @@ bpf_movein(uio, linktype, mp, sockp, datlen)
}
len = uio->uio_resid;
*datlen = len - hlen;
if (len - hlen > mtu)
return (EMSGSIZE);
if ((unsigned)len > MCLBYTES)
return (EIO);
@ -569,7 +581,6 @@ bpfwrite(dev, uio, ioflag)
struct mbuf *m;
int error;
struct sockaddr dst;
int datlen;
if (d->bd_bif == NULL)
return (ENXIO);
@ -583,15 +594,10 @@ bpfwrite(dev, uio, ioflag)
return (0);
bzero(&dst, sizeof(dst));
error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen);
error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp->if_mtu, &m, &dst);
if (error)
return (error);
if (datlen > ifp->if_mtu) {
m_freem(m);
return (EMSGSIZE);
}
if (d->bd_hdrcmplt)
dst.sa_family = pseudo_AF_HDRCMPLT;

View File

@ -102,7 +102,7 @@ disc_clone_create(struct if_clone *ifc, int unit)
ifp->if_addrlen = 0;
ifp->if_snd.ifq_maxlen = 20;
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
mtx_lock(&disc_mtx);
LIST_INSERT_HEAD(&disc_softc_list, sc, sc_list);
mtx_unlock(&disc_mtx);
@ -176,15 +176,14 @@ static int
discoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct rtentry *rt)
{
u_int32_t af;
M_ASSERTPKTHDR(m);
/* BPF write needs to be handled specially */
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
dst->sa_family = *(mtod(m, int *));
m->m_len -= sizeof(int);
m->m_pkthdr.len -= sizeof(int);
m->m_data += sizeof(int);
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
if (ifp->if_bpf) {

View File

@ -187,7 +187,7 @@ faith_clone_create(ifc, unit)
ifp->if_addrlen = 0;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
mtx_lock(&faith_mtx);
LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list);
mtx_unlock(&faith_mtx);
@ -225,19 +225,18 @@ faithoutput(ifp, m, dst, rt)
struct rtentry *rt;
{
int isr;
u_int32_t af;
M_ASSERTPKTHDR(m);
/* BPF write needs to be handled specially */
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
dst->sa_family = *(mtod(m, int *));
m->m_len -= sizeof(int);
m->m_pkthdr.len -= sizeof(int);
m->m_data += sizeof(int);
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
if (ifp->if_bpf) {
u_int32_t af = dst->sa_family;
af = dst->sa_family;
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
}

View File

@ -179,7 +179,7 @@ gifattach0(sc)
GIF2IFP(sc)->if_output = gif_output;
GIF2IFP(sc)->if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(GIF2IFP(sc));
bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int));
bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
if (ng_gif_attach_p != NULL)
(*ng_gif_attach_p)(GIF2IFP(sc));
}
@ -348,6 +348,7 @@ gif_output(ifp, m, dst, rt)
struct m_tag *mtag;
int error = 0;
int gif_called;
u_int32_t af;
#ifdef MAC
error = mac_check_ifnet_transmit(ifp, m);
@ -404,8 +405,14 @@ gif_output(ifp, m, dst, rt)
goto end;
}
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
if (ifp->if_bpf) {
u_int32_t af = dst->sa_family;
af = dst->sa_family;
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
}
ifp->if_opackets++;

View File

@ -233,6 +233,7 @@ gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct ip *ip;
u_int16_t etype = 0;
struct mobile_h mob_h;
u_int32_t af;
/*
* gre may cause infinite recursion calls when misconfigured.
@ -256,8 +257,14 @@ gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
gh = NULL;
ip = NULL;
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
if (ifp->if_bpf) {
u_int32_t af = dst->sa_family;
af = dst->sa_family;
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
}

View File

@ -156,7 +156,7 @@ lo_clone_create(ifc, unit)
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_softc = sc;
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
mtx_lock(&lo_mtx);
LIST_INSERT_HEAD(&lo_list, sc, sc_next);
mtx_unlock(&lo_mtx);
@ -199,6 +199,8 @@ looutput(ifp, m, dst, rt)
struct sockaddr *dst;
register struct rtentry *rt;
{
u_int32_t af;
M_ASSERTPKTHDR(m); /* check if we have the packet header */
if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
@ -209,6 +211,13 @@ looutput(ifp, m, dst, rt)
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
#if 1 /* XXX */
switch (dst->sa_family) {
case AF_INET:
@ -249,15 +258,6 @@ if_simloop(ifp, m, af, hlen)
m_tag_delete_nonpersistent(m);
m->m_pkthdr.rcvif = ifp;
/* BPF write needs to be handled specially */
if (af == AF_UNSPEC) {
KASSERT(m->m_len >= sizeof(int), ("if_simloop: m_len"));
af = *(mtod(m, int *));
m->m_len -= sizeof(int);
m->m_pkthdr.len -= sizeof(int);
m->m_data += sizeof(int);
}
/* Let BPF see incoming packet */
if (ifp->if_bpf) {
if (ifp->if_bpf->bif_dlt == DLT_NULL) {

View File

@ -245,7 +245,7 @@ stf_clone_create(struct if_clone *ifc, char *name, size_t len)
ifp->if_output = stf_output;
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
mtx_lock(&stf_mtx);
LIST_INSERT_HEAD(&stf_softc_list, sc, sc_list);
mtx_unlock(&stf_mtx);
@ -438,6 +438,7 @@ stf_output(ifp, m, dst, rt)
struct ip *ip;
struct ip6_hdr *ip6;
struct in6_ifaddr *ia6;
u_int32_t af;
#ifdef MAC
int error;
@ -480,6 +481,15 @@ stf_output(ifp, m, dst, rt)
ip6 = mtod(m, struct ip6_hdr *);
tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
/*
* BPF writes need to be handled specially.
* This is a null operation, nothing here checks dst->sa_family.
*/
if (dst->sa_family == AF_UNSPEC) {
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
/*
* Pickup the right outer dst addr from the list of candidates.
* ip6_dst has priority as it may be able to give us shorter IPv4 hops.
@ -504,7 +514,7 @@ stf_output(ifp, m, dst, rt)
* will only read from the mbuf (i.e., it won't
* try to free it or keep a pointer a to it).
*/
u_int32_t af = AF_INET6;
af = AF_INET6;
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
}

View File

@ -285,7 +285,7 @@ tuncreate(struct cdev *dev)
IFQ_SET_READY(&ifp->if_snd);
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
dev->si_drv1 = sc;
}
@ -473,6 +473,7 @@ tunoutput(
struct tun_softc *tp = ifp->if_softc;
u_short cached_tun_flags;
int error;
u_int32_t af;
TUNDEBUG (ifp, "tunoutput\n");
@ -499,16 +500,14 @@ tunoutput(
return (EHOSTDOWN);
}
/* BPF write needs to be handled specially */
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
dst->sa_family = *(mtod(m0, int *));
m0->m_len -= sizeof(int);
m0->m_pkthdr.len -= sizeof(int);
m0->m_data += sizeof(int);
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
if (ifp->if_bpf) {
uint32_t af = dst->sa_family;
af = dst->sa_family;
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m0);
}

View File

@ -352,6 +352,7 @@ ng_iface_output(struct ifnet *ifp, struct mbuf *m,
const priv_p priv = (priv_p) ifp->if_softc;
const iffam_p iffam = get_iffam_from_af(dst->sa_family);
int len, error = 0;
u_int32_t af;
/* Check interface flags */
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
@ -359,14 +360,10 @@ ng_iface_output(struct ifnet *ifp, struct mbuf *m,
return (ENETDOWN);
}
/* BPF writes need to be handled specially */
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
return (ENOBUFS);
dst->sa_family = (sa_family_t)*mtod(m, int32_t *);
m->m_data += 4;
m->m_len -= 4;
m->m_pkthdr.len -= 4;
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
/* Berkeley packet filter */
@ -508,7 +505,7 @@ ng_iface_constructor(node_p node)
/* Attach the interface */
if_attach(ifp);
bpfattach(ifp, DLT_NULL, sizeof(u_int));
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
/* Done */
return (0);

View File

@ -289,7 +289,7 @@ ng_sppp_constructor (node_p node)
/* Attach the interface */
sppp_attach (ifp);
if_attach (ifp);
bpfattach (ifp, DLT_NULL, sizeof(u_int));
bpfattach (ifp, DLT_NULL, sizeof(u_int32_t));
/* Done */
return (0);

View File

@ -1920,6 +1920,8 @@ static int
carp_looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct rtentry *rt)
{
u_int32_t af;
M_ASSERTPKTHDR(m); /* check if we have the packet header */
if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
@ -1930,6 +1932,13 @@ carp_looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
ifp->if_opackets++;
ifp->if_obytes += m->m_pkthdr.len;
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
#if 1 /* XXX */
switch (dst->sa_family) {
case AF_INET: