Comment 17 for bug 1940635

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

So what is going on is this:

In icmp6_receive systemd passes a buffer for control messages to recvmsg that is only big enough for the messages it expects to receive. glibc now attempts to append an extra control message to the buffer (translating SO_TIMESTAMP / COMPAT_SO_TIMESTAMP_OLD to SO_TIMESTAMP_NEW) and sets MSG_CTRUNC in flags if it can't fit this in. So this is where that EXFULL comes from.

So the fix for this is simple, right? Just pass a bigger buffer to recvmsg? No, if you do this networkd segfaults. I think __convert_scm_timestamps fails to handle a subtlety of the control message buffer, which is that the control messages don't always (it seems) occupy all of the buffer up to msg_controllen (!). If you look at the definition of CMSG_NXTHDR, the test for the end of the buffer has two clauses (https://sourceware.org/git/?p=glibc.git;a=blob;f=bits/socket.h;h=05ac0249c7da7218cbd11be99a67529161cfa7f7;hb=HEAD#l265):

  if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
     + __mhdr->msg_controllen)
      || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
   > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
    /* No more entries. */
    return (struct cmsghdr *) 0;

I think after glibc's alterations, calling this on the last message ends up with garbage in __cmsg->cmsg_len, so __cmsg+__cmsg->cmsg_len is overflowing and the program then goes off to read uninitialized memory and hilarity ensues.

I'm attaching a glibc patch which *may* help (it's building in a ppa now, will test it in a bit). But it's all a bit uncertain. Haven't filed an upstream glibc bug report yet.