title: Audit netlink response don't have the right packet length
body: <p>I have been trying to read the linux audit logs from go using <a href="https://github.com/mdlayher/netlink" rel="nofollow noreferrer">mdlayher/netlink</a>. I am able to make a connection and set the PID as well to be able to receive logs from the netlink socket over unicast and multicast.</p>
  <p>The problem is, when the library tries to parse the messages from netlink, it fails, and <strong>not because of the library</strong>. I tried to dump the messages that were sent to my connection and this is what I found.</p>
  <pre><code>([]uint8) (len=48 cap=4096) {
   00000000  1d 00 00 00 28 05 00 00  00 00 00 00 00 00 00 00  |....(...........|
   00000010  61 75 64 69 74 28 31 36  31 32 30 33 31 38 36 32  |audit(1612031862|
   00000020  2e 36 33 31 3a 32 37 31  30 34 29 3a 20 00 00 00  |.631:27104): ...|
  }
  </code></pre>
  <p>This is one of the messages from the log stream. According to the <a href="https://en.wikipedia.org/wiki/Netlink#Packet_structure" rel="nofollow noreferrer">packet structure</a>, The first 16 bytes are part of the <a href="https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/netlink.h#L44" rel="nofollow noreferrer">netlink message header</a> <code>nlmsghdr</code>.</p>
  <pre class="lang-c prettyprint-override"><code>struct nlmsghdr {
      __u32       nlmsg_len;  /* Length of message including header */
      __u16       nlmsg_type; /* Message content */
      __u16       nlmsg_flags;    /* Additional flags */
      __u32       nlmsg_seq;  /* Sequence number */
      __u32       nlmsg_pid;  /* Sending process port ID */
  };
  </code></pre>
  <p>Note, how the <code>nlmsg_len</code> is marked as <code>length of the message including header</code>. If you look at the message dump, the first <code>__u32</code> is <code>1d 00 00 00</code>, which in the network byte order is 29. Which means the whole packet should be 29 bytes. But, if you count the bytes, it's 45 + 3 bytes of padding which is how the packets are aligned. The message ends at byte 45 which is (29 + 16) or 29 + length of the message header size.</p>
  <p>But, the strange thing is, it only happens on audit log messages and not on audit control message replies. Refer to <a href="https://play.golang.com/p/mA7_MJdVSv8" rel="nofollow noreferrer">https://play.golang.com/p/mA7_MJdVSv8</a> for examples on how the packet structures are parsed.</p>
  <p>Is this expected ? Looking at the go stdlib <a href="https://golang.org/src/syscall/netlink_linux.go?s=2998:3058#L106" rel="nofollow noreferrer"><code>syscall.ParseNetlinkMessage</code></a>, it seems to obey the header + body constraint. I can't make it out in the <a href="https://github.com/linux-audit/audit-userspace/blob/master/lib/netlink.c#L102" rel="nofollow noreferrer">userspace-audit code</a> which is responsible for <code>auditd</code>, <code>auditctl</code> and it's family of tools.</p>
  <p>Another popular library, <a href="https://github.com/slackhq/go-audit/blob/6d44a76821e57968c1938217ed6cf4b2af9c8c10/client.go#L123" rel="nofollow noreferrer">slackhq/go-audit</a> seems to not rely on the header length and parse based on the size of the buffer read from the socket.</p>
  <p>This diff on the mdlayher/netlink library seems to fix the above issue and can also get the byte dumps of the payload. But this shouldn't be the case.</p>
  <pre><code>diff --git a/conn_linux.go b/conn_linux.go
  index ef18ef7..561ac69 100644
  --- a/conn_linux.go
  +++ b/conn_linux.go
  @@ -11,6 +11,8 @@ import (
          &quot;time&quot;
          &quot;unsafe&quot;
  
  +       &quot;github.com/davecgh/go-spew/spew&quot;
  +       &quot;github.com/josharian/native&quot;
          &quot;golang.org/x/net/bpf&quot;
          &quot;golang.org/x/sys/unix&quot;
   )
  @@ -194,7 +196,13 @@ func (c *conn) Receive() ([]Message, error) {
  
          raw, err := syscall.ParseNetlinkMessage(b[:n])
          if err != nil {
  -               return nil, err
  +               spew.Dump(b[:n])
  +               bl := native.Endian.Uint32(b[:4]) + syscall.NLMSG_HDRLEN
  +               native.Endian.PutUint32(b[:4], bl)
  +               raw, err = syscall.ParseNetlinkMessage(b[:n])
  +               if err != nil {
  +                       return nil, err
  +               }
          }
  
          msgs := make([]Message, 0, len(raw))
  </code></pre>
  <h3>code for reproducing the above behaviour</h3>
  <ul>
  <li>Code to read the audit log: <a href="https://play.golang.com/p/Kj4DOl0PKRQ" rel="nofollow noreferrer">https://play.golang.com/p/Kj4DOl0PKRQ</a></li>
  <li>Code to see how different packets are parsed by golang: <a href="https://play.golang.com/p/mA7_MJdVSv8" rel="nofollow noreferrer">https://play.golang.com/p/mA7_MJdVSv8</a></li>
  <li>The audit.h file: <a href="https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/audit.h" rel="nofollow noreferrer">include/audit.h</a></li>
  <li><code>uname -a</code>: <code>Linux linux-dev 4.15.0-135-generic #139-Ubuntu SMP Mon Jan 18 17:38:24 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux</code></li>
  </ul>
  <hr />
  <h3>Update 1</h3>
  <p>This above behavior seems to crop up when I try to alter the audit state via the <code>AUDIT_SET</code> message type. If I try to connect to the read-only multicast group <code>AUDIT_NLGRP_READLOG</code>, It doesn't seem to happen. Also, If I close the unicast connection and then try multicast, the issue is back again. Basically, as long as my PID is bound to the socket, this issue comes back up.
  Sample dump when only connecting via multicast group</p>
  <pre><code>([]uint8) (len=76 cap=4096) {
   00000000  49 00 00 00 1d 05 00 00  00 00 00 00 00 00 00 00  |I...............|
   00000010  61 75 64 69 74 28 31 36  31 32 31 36 35 31 33 31  |audit(1612165131|
   00000020  2e 30 31 36 3a 33 33 34  37 32 29 3a 20 61 72 67  |.016:33472): arg|
   00000030  63 3d 32 20 61 30 3d 22  61 75 64 69 74 63 74 6c  |c=2 a0=&quot;auditctl|
   00000040  22 20 61 31 3d 22 2d 73  22 00 00 00              |&quot; a1=&quot;-s&quot;...|
  }
  </code></pre>
  <p>Notice how the size if 0x49 = 73, the exact packet length.</p>