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
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).
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.