Bug 261566 - Padding of DLT_PFLOG packets should be done differently
Summary: Padding of DLT_PFLOG packets should be done differently
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-01-30 05:40 UTC by Guy Harris
Modified: 2022-02-09 09:57 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Guy Harris 2022-01-30 05:40:43 UTC
Currently, sys/net/if_pflog.h does

    #define PFLOG_HDRLEN            BPF_WORDALIGN(offsetof(struct pfloghdr, pad2))

This is done only in FreeBSD; neither DragonFly BSD nor NetBSD nor OpenBSD nor Darwin use BPF_WORDALIGN() here, and, as FreeBSD's BPF_WORDALIGN() aligns to the size of a long, this means that the DLT_PFLOG packet format can differ depending on whether the machine writing the packet is 32-bit (ILP32) or 64-bit (LP64), which, given that neither the pcap file format nor the pcapng file format give any indication of the size of a long on the platform on which the file was written, means that the correct way to process a DLT_PFLOG packt in a given file cannot be determined from the file.

The commit message for the commit that added BPF_WORDALIGN() was

    There were two issues with the new pflog packet length.
    The first is that the length is expected to be a multiple of
    sizeof(long), but we'd assumed it had to be a multiple of
    sizeof(uint32_t).

but it gives not justification for the claim that "the length is expected to be a multiple of sizeof(long)".  As indicated:

1) that's not the case on only *other* BSD-flavored OS with pflog

and

2) that creates a packet format that can only be processed correctly by providing external information about the machine that wrote the file, which requires not only extra code, but extra time and energy on the part of whoever's trying to read the file, to determine the size of a long on the platform on which it was written and to supply that to the program reading the file.

The other OSes rely on the compiler to add the padding as a consequence of the structure including some 32-bit integral values; that should suffice here, although if you want to make *sure* it's padded to a 4-byte boundary, you could use roundup2() from sys/param.h to do it rather than dragging in net/bpf.h.

Note that

1) it's not clear that aligning on an 8-byte boundary will provide any performance improvement, as, even if you were to align the IP packet on an 8-byte boundary, there's no guarantee that this will put a significant number of 8-byte fields on an 8-byte boundary

and

2) that will make a difference for two of the main packet analyzers that read pcap and pcapng files (tcpdump and Wireshark) only on CPUs that 1) support unaligned access but 2) impose a penalty for those accesses.
Comment 1 Guy Harris 2022-01-30 08:51:20 UTC
Note also that, if you try to read a DLT_PFLOG capture with the OpenBSD struct pfloghdr, and round the length up to a multiple of 8, you will *NOT* correctly read it.

Here's version 1.29 of sys/net/if_pflog.h:

    https://cvsweb.openbsd.org/src/sys/net/if_pflog.h?rev=1.29&content-type=text/x-cvsweb-markup

struct pf_addr is 16 bytes (containing a union big enough to hold either an IPv4 or an IPv6 address, as per version 1.505 of sys/net/pfvar.h:

    https://cvsweb.openbsd.org/src/sys/net/pfvar.h?rev=1.505&content-type=text/x-cvsweb-markup

), IFNAMSIZ is 16, sa_family_t is 1 byte, and uid_t and pid_t are both 4 bytes, for a total of 1+1+1+1+16+16+4+4+4+4+4+4+1+1+1+1+16+16+2+2 = 100 bytes, which is *not* a multiple of 8, although it *is* a multiple of 4.

The new-style header was introduced in version 1.8:

    https://cvsweb.openbsd.org/src/sys/net/if_pflog.h?rev=1.8&content-type=text/x-cvsweb-markup

    https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/net/if_pflog.h.diff?r1=1.7&r2=1.8&f=h

and they got rid of the "PFLOG_REAL_HDRLEN doesn't include the padding to a 4-byte boundary" stuff in version 1.16:

    https://cvsweb.openbsd.org/src/sys/net/if_pflog.h?rev=1.16&content-type=text/x-cvsweb-markup

    https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/net/if_pflog.h.diff?r1=1.15&r2=1.16&f=h
Comment 2 Kristof Provost freebsd_committer freebsd_triage 2022-01-31 21:57:21 UTC
Thanks for the report.

I distinctly recall looking at the Wireshark code before implementing the BPF_WORDALIGN(), however it clearly does `padded_length = WS_ROUNDUP_4(length);`, so I don't know what happened there.

How does this look to you:

diff --git a/sys/net/if_pflog.h b/sys/net/if_pflog.h
index 0406f78474a8..443c1cc36cf6 100644
--- a/sys/net/if_pflog.h
+++ b/sys/net/if_pflog.h
@@ -33,7 +33,6 @@

 #include <sys/types.h>

-#include <net/bpf.h>
 #include <net/if.h>

 #define        PFLOGIFS_MAX    16
@@ -60,7 +59,9 @@ struct pfloghdr {
        u_int8_t        pad2[3];
 };

-#define        PFLOG_HDRLEN            BPF_WORDALIGN(offsetof(struct pfloghdr, pad2))
+#define PFLOG_ALIGNMENT                sizeof(uint32_t)
+#define PFLOG_ALIGN(x)         (((x) + PFLOG_ALIGNMENT - 1) & ~(PFLOG_ALIGNMENT - 1))
+#define        PFLOG_HDRLEN            PFLOG_ALIGN(offsetof(struct pfloghdr, pad2))
 /* minus pad, also used as a signature */
 #define        PFLOG_REAL_HDRLEN       offsetof(struct pfloghdr, pad2)
Comment 3 Guy Harris 2022-02-01 00:03:58 UTC
> I distinctly recall looking at the Wireshark code before implementing the BPF_WORDALIGN(), however it clearly does `padded_length = WS_ROUNDUP_4(length);`, so I don't know what happened there.

It got fixed from "add 3 to the length under the assumption that there's 1 byte of padding" to "round it up to a multiple of 4".

(Tcpdump now does the same thing, and libpcap now gets the pflog header length from the length field, rounding it up to a multiple of 4, rather than having a hardwired length based on whatever platform it was compiled on.)

> How does this look to you:

That should work.
Comment 4 commit-hook freebsd_committer freebsd_triage 2022-02-01 17:19:08 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=4daa31c10867b133bdc2a424e1e60d280384dc56

commit 4daa31c10867b133bdc2a424e1e60d280384dc56
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2022-02-01 07:56:49 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2022-02-01 17:17:44 +0000

    pflog: align header to 4 bytes, not 8

    6d4baa0d01 incorrectly rounded the lenght of the pflog header up to 8
    bytes, rather than 4.

    PR:             261566
    Reported by:    Guy Harris <gharris@sonic.net>
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")

 sys/net/if_pflog.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Comment 5 commit-hook freebsd_committer freebsd_triage 2022-02-09 09:44:40 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=c6745a0cc40e77ed3b783a0a8050b42bdf682e57

commit c6745a0cc40e77ed3b783a0a8050b42bdf682e57
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2022-02-01 07:56:49 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2022-02-09 09:40:58 +0000

    pflog: align header to 4 bytes, not 8

    6d4baa0d01 incorrectly rounded the lenght of the pflog header up to 8
    bytes, rather than 4.

    PR:             261566
    Reported by:    Guy Harris <gharris@sonic.net>
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")

    (cherry picked from commit 4daa31c10867b133bdc2a424e1e60d280384dc56)

 sys/net/if_pflog.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Comment 6 commit-hook freebsd_committer freebsd_triage 2022-02-09 09:57:43 UTC
A commit in branch stable/12 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=275f412b070f0d23b028f8bde85182a1f6d0fe7c

commit 275f412b070f0d23b028f8bde85182a1f6d0fe7c
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2022-02-01 07:56:49 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2022-02-09 09:56:36 +0000

    pflog: align header to 4 bytes, not 8

    6d4baa0d01 incorrectly rounded the lenght of the pflog header up to 8
    bytes, rather than 4.

    PR:             261566
    Reported by:    Guy Harris <gharris@sonic.net>
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")

    (cherry picked from commit 4daa31c10867b133bdc2a424e1e60d280384dc56)

 sys/net/if_pflog.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)