Bug 9067

Summary: netbsd too-short cmsg struct
Product: dbus Reporter: Havoc Pennington <hp>
Component: coreAssignee: Havoc Pennington <hp>
Status: RESOLVED DUPLICATE QA Contact: John (J5) Palmieri <johnp>
Severity: normal    
Priority: high CC: Glenn.Schmottlach, walters
Version: 1.2.x   
Hardware: x86 (IA32)   
OS: Windows (All)   
Whiteboard:
i915 platform: i915 features:

Description Havoc Pennington 2006-11-17 13:57:48 UTC
from the moderator queue on the mailing list, 

Subject:
NetBSD LOCAL_CREDS fails when no supplementary groups
From:
Todd Allan <todd_allan@picovex.com>
Date:
Fri, 17 Nov 2006 13:30:00 -0800
To:
dbus@lists.freedesktop.org

Hello, I've run into a snag sending D-Bus messages on a recent NetBSD-current 
in single-user mode.  The check that fails is:

dbus-sysdeps-unix.c: _dbus_read_credentials_unix_socket():

  if (cmsg.hdr.cmsg_len < sizeof (cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Message from recvmsg() was not SCM_CREDS");

In NetBSD's case, at least, struct sockcred contains a variable-length array 
of "supplemental groups", that may contain zero entries:

    int     sc_ngroups;     /* number of supplemental groups */
    gid_t   sc_groups[1];   /* variable length */

The struct sockcred transmitted with the control message will contain as many 
sc_groups entries as specified by sc_ngroups.  If sc_ngroups == 0, 
cmsg.hdr.cmsg_len will include zero sc_groups entries, and will be 4 bytes 
smaller than the sizeof(cmsg), which includes a single entry.

Processes spawned from the init process context, which has zero supplemental 
groups in its kauth_cred_t, and which do not have an ancestor that performs a 
setgroups(2), as does login(1), hit this case.

I'm new to this area and am not sure if NetBSD's behavior is unconventional 
and should perhaps be changed (say, pad out a dummy sc_groups entry), or 
whether it is reasonable to modify D-Bus to handle this case.  NetBSD provides 
a SOCKCREDSIZE() macro that could help check the received size against the 
sc_ngroups field, but I haven't looked into the portability across all 
platforms with LOCAL_CREDS or CMSGCRED.

Any advice on how to proceed appreciated, thanks,

TAllan
Comment 1 Glenn Schmottlach 2008-11-13 05:04:26 UTC
I stumbled across this same bug in dbus/dbus-sysdeps-unix.c while porting DBus 1.2.4 to QNX where only LOCAL_CREDS are supported for domain sockets. In particular, in the function dbus_read_credentials_socket() (@ line ~1218) the code tries to verify that the size of the received credentials structure is the expected size. Unfortunately, for LOCAL_CREDS, this is computed incorrectly:

BEFORE:
=======

#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
  if ( cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS )


For LOCAL_CREDS, this should actually be computed as follows:

AFTER:
======

#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
#if defined(HAVE_CMSGCRED)
  if ( cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS )
#else
  if ( (cmsg.hdr.cmsg_len < (sizeof(cmsg.hdr) + SOCKCREDSIZE(0))) || (cmsg.hdr.cmsg_type != SCM_CREDS) )
#endif

Running the dbus-daemon as root that has no (zero) supplemental groups, a simple sizeof(cmsg) is not correct since the sc_groups[1] field of struct sockcred will NOT be transmitted. Thankfully, the SOCKCREDSIZE macro in sockets.h computes the correct size (assuming that at a minimum, no supplemental groups are encoded in the stream).
Comment 2 Colin Walters 2009-07-13 11:27:52 UTC
Should be fixed from patch in 19432.

*** This bug has been marked as a duplicate of bug 19432 ***

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.