Bug 13500 - __cmsg_nxthdr in cmsg_nxthdr.c (CMSG_NXTHDR) has undefined behavior when setting up ancillary data
Summary: __cmsg_nxthdr in cmsg_nxthdr.c (CMSG_NXTHDR) has undefined behavior when sett...
Status: RESOLVED INVALID
Alias: None
Product: glibc
Classification: Unclassified
Component: network (show other bugs)
Version: 2.14
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-12-14 20:30 UTC by Igor Lubashev
Modified: 2019-06-20 02:25 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
Test that fails, unless NEED_A_WORKAROUND_FOR_BUG_13500 is defined (604 bytes, text/x-csrc)
2012-01-03 18:10 UTC, Igor Lubashev
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Igor Lubashev 2011-12-14 20:30:08 UTC
In the current implementation, when setting up ancillary data, __cmsg_nxthdr will try to read data from the uninitialized area of the ancillary buffer and may erroneously return NULL.

  cmsg = (struct cmsghdr *) ((unsigned char *) cmsg
			     + CMSG_ALIGN (cmsg->cmsg_len));
  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 NULL;

Above is the relevant part of the current implementation.

"cmsg->cmsg_len" in the second "||" clause will read uninitialized data.  That second "||" clause is not needed at all (and the kernel version of this function does not have it).

This implementation is ok for parsing ancillary data (it provides some extra sanity checking of the data), but it is broken for setting up ancillary data.

A workaround is to memset the entire ancillary data buffer to 0 before initializing it, but there is no such requirement in neither man pages nor RFC 2292 or RFC 3542.

Glibc's implementation of CMSG_NXTHDR is not consistent with the reference implementation in RFC 2292 and RFC 3542.



P.S.
  The current implementation does not support another RFC 2292/3542 requirement requirement:

   The following behavior of this macro is new to this API: if the value
   of the cmsg pointer is NULL, a pointer to the cmsghdr structure
   describing the first ancillary data object is returned.  That is,
   CMSG_NXTHDR(mhdr, NULL) is equivalent to CMSG_FIRSTHDR(mhdr).

But you'll probably want a different bug report for this.
Comment 1 Ulrich Drepper 2011-12-18 01:49:45 UTC
Where is the self-contained test case?
Comment 2 Igor Lubashev 2012-01-03 18:10:45 UTC
Created attachment 6141 [details]
Test that fails, unless NEED_A_WORKAROUND_FOR_BUG_13500 is defined

Here is a test case.

The expected output is "Looks good!".
Currently, the output is "CMSG_NXTHDR is lying -- I have space for another int"
Comment 3 Andreas Jaeger 2012-12-01 16:46:33 UTC
Test has been provided, so removing WAITING.
Comment 4 phperl 2016-12-07 11:03:33 UTC
use NEED_A_WORKAROUND_FOR_BUG_13500 to zero buf, will make length check useless, even to introduce security bugs.
Comment 5 Florian Weimer 2016-12-07 11:11:57 UTC
(In reply to phperl from comment #4)
> use NEED_A_WORKAROUND_FOR_BUG_13500 to zero buf, will make length check
> useless, even to introduce security bugs.

Sorry, I don't understand this comment.

The length check is *always* useless for constructing ancillary data lists, but it is not useless for *reading* them.
Comment 6 phperl 2016-12-09 07:36:36 UTC
(In reply to Florian Weimer from comment #5)
> (In reply to phperl from comment #4)
> > use NEED_A_WORKAROUND_FOR_BUG_13500 to zero buf, will make length check
> > useless, even to introduce security bugs.
> 
> Sorry, I don't understand this comment.
> 
> The length check is *always* useless for constructing ancillary data lists,
> but it is not useless for *reading* them.

Sorry, I missed the *reading* process.
Comment 7 Carlos O'Donell 2019-06-20 02:25:41 UTC
I'm marking this as RESOLVED INVALID.

The length check in the current glibc CMSG_NXTHDR macro requires that the you are reading valid data, and the check will not be removed to facilitate setting up of lists. If you are setting up a list you must set it to some known values for the macro to work correctly e.g. memset to zero.

I suggest reaching out to the linux man pages project to update the man page with relevant information for developers.

Note that I don't see where RFC 2292, and RFC 3542 cover setting up a list, only reading one.

As Florian notes: "The length check is *always* useless for constructing ancillary data lists, but it is not useless for *reading* them."