On Thu, Feb 03, 2022 at 11:39:50PM +0100, Alexander Bluhm wrote:
> On Thu, Feb 03, 2022 at 10:22:46PM +1000, David Gwynne wrote:
> > bpf should know better than this. it has all the information it needs to
> > align the payload properly, it just doesnt make enough of an effort. can
> > you try the diff below?
> 
> Diff seems to work.  regress/sbin/slaacd passes.
> I have started a full regress run on armv7 and sparc64.

cool.

> 
> > +   if (len < hlen)
> > +           return (EPERM);
> 
> This is not a permission problem.  Maybe EINVAL.

this is preveserving the existing semantics of this chunk:

@@ -232,10 +247,6 @@ bpf_movein(struct uio *uio, struct bpf_d
                goto bad;
        }
 
-       if (m->m_len < hlen) {
-               error = EPERM;
-               goto bad;
-       }
        /*
         * Make room for link header, and copy it to sockaddr
         */

i was going to follow this diff up with another one to tweak it.
tun(4) uses EMSGSIZE for this, but errno(2) says EMSGSIZE means
"Message too long". EINVAL sounds good.

want me to do it now?

> 
> > +   /*
> > +         * Get the length of the payload so we can align it properly.
> > +    */
> 
> Whitespace misaligned.

yep.

> > +   if (mlen > MAXMCLBYTES)
> > +           return (EIO);
> 
> Should we use EMSGSIZE like in bpfwrite() if the data does not fit.

yes. want me to do that now too?

> 
> > +   mlen = max(max_linkhdr, hlen) + roundup(alen, sizeof(long));
> ...
> > +   m_align(m, alen); /* Align the payload. */
> 
> sizeof(long) seems the correct alignment for mbuf.  In rev 1.237
> of m_pullup() you introduced ALIGNBYTES.  This is architecture
> dependent and the only place in the network stack where it is used.
> Should it also be sizeof(long) there?

i probably did that when i was adding ALIGNED_POINTER checks to ethernet
tunnel drivers.

my initial thought is it doesnt save m_pullup any work, so it's
probably better to use sizeof(long) so there's a better chance that
accesses to words in a pulled up payload are aligned. even if an
arch doesnt fault on unaligned access it still goes faster with
aligned accesses. if m_pullup is going to move data around it may as
well move it to the best place possible.

i'll spit a diff out for that next.

Index: bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.210
diff -u -p -r1.210 bpf.c
--- bpf.c       16 Jan 2022 06:27:14 -0000      1.210
+++ bpf.c       4 Feb 2022 09:25:40 -0000
@@ -144,7 +144,7 @@ bpf_movein(struct uio *uio, struct bpf_d
        struct mbuf *m;
        struct m_tag *mtag;
        int error;
-       u_int hlen;
+       u_int hlen, alen, mlen;
        u_int len;
        u_int linktype;
        u_int slen;
@@ -198,23 +198,38 @@ bpf_movein(struct uio *uio, struct bpf_d
                return (EIO);
        }
 
-       if (uio->uio_resid > MAXMCLBYTES)
-               return (EIO);
        len = uio->uio_resid;
+       if (len < hlen)
+               return (EPERM);
 
-       MGETHDR(m, M_WAIT, MT_DATA);
-       m->m_pkthdr.ph_ifidx = 0;
-       m->m_pkthdr.len = len - hlen;
+       /*
+        * Get the length of the payload so we can align it properly.
+        */
+       alen = len - hlen;
+
+       /*
+        * Allocate enough space for headers and the aligned payload.
+        */
+       mlen = max(max_linkhdr, hlen) + roundup(alen, sizeof(long));
+
+       if (mlen > MAXMCLBYTES)
+               return (EIO);
 
-       if (len > MHLEN) {
-               MCLGETL(m, M_WAIT, len);
+       MGETHDR(m, M_WAIT, MT_DATA);
+       if (mlen > MHLEN) {
+               MCLGETL(m, M_WAIT, mlen);
                if ((m->m_flags & M_EXT) == 0) {
                        error = ENOBUFS;
                        goto bad;
                }
        }
+
+       m_align(m, alen); /* Align the payload. */
+       m->m_data -= hlen;
+
+       m->m_pkthdr.ph_ifidx = 0;
+       m->m_pkthdr.len = len;
        m->m_len = len;
-       *mp = m;
 
        error = uiomove(mtod(m, caddr_t), len, uio);
        if (error)
@@ -232,10 +247,6 @@ bpf_movein(struct uio *uio, struct bpf_d
                goto bad;
        }
 
-       if (m->m_len < hlen) {
-               error = EPERM;
-               goto bad;
-       }
        /*
         * Make room for link header, and copy it to sockaddr
         */
@@ -249,8 +260,10 @@ bpf_movein(struct uio *uio, struct bpf_d
                        sockp->sa_family = ntohl(af);
                } else
                        memcpy(sockp->sa_data, m->m_data, hlen);
+
+               m->m_pkthdr.len -= hlen;
                m->m_len -= hlen;
-               m->m_data += hlen; /* XXX */
+               m->m_data += hlen;
        }
 
        /*
@@ -260,6 +273,7 @@ bpf_movein(struct uio *uio, struct bpf_d
        *(u_int *)(mtag + 1) = linktype;
        m_tag_prepend(m, mtag);
 
+       *mp = m;
        return (0);
  bad:
        m_freem(m);

Reply via email to