Bug 19557

Summary: recvmsg fails retrieving SCM_CREDENTIALS with error EOPNOTSUPP
Product: glibc Reporter: Alan Griffiths <alan.griffiths>
Component: libcAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED MOVED    
Severity: normal CC: drepper.fsp, fweimer
Priority: P2 Flags: fweimer: security-
Version: 2.21   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Alan Griffiths 2016-02-02 13:00:33 UTC
Following update on Ubuntu Xenial, the following test case fails:

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <sys/socket.h>
#include <sys/stat.h>

TEST(IsItBroken, recvmsg)
{
    using namespace testing;

    enum { server, client, size };
    int socket_fd[size];
    int const opt = 1;

    ASSERT_THAT(socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd), Eq(0));

    auto const msg = "A random message";
    send(socket_fd[client], msg, sizeof msg, MSG_DONTWAIT | MSG_NOSIGNAL);

    ASSERT_THAT(setsockopt(socket_fd[server], SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)), Ne(-1));

    union {
        struct cmsghdr cmh;
        char   control[CMSG_SPACE(sizeof(ucred))];
    } control_un;

    control_un.cmh.cmsg_len = CMSG_LEN(sizeof(ucred));
    control_un.cmh.cmsg_level = SOL_SOCKET;
    control_un.cmh.cmsg_type = SCM_CREDENTIALS;

    msghdr msgh;
    msgh.msg_name = nullptr;
    msgh.msg_namelen = 0;
    msgh.msg_iov = nullptr;
    msgh.msg_iovlen = 0;
    msgh.msg_control = control_un.control;
    msgh.msg_controllen = sizeof(control_un.control);

    errno = 0;

    EXPECT_THAT(recvmsg(socket_fd[server], &msgh, MSG_PEEK), Ne(-1))
        << "Error: " << strerror(errno);

    for (auto socket : socket_fd) close(socket);
}
Comment 1 Florian Weimer 2016-02-03 09:52:58 UTC
Can you post a test case which does not need an external test framework, the output you get, and the output you expect?
Comment 2 Alan Griffiths 2016-02-03 10:08:17 UTC
Additional information: this happens with the latest Xenial 4.4.0-2-generic kernel, but not with the previous 4.3.0-7-generic kernel.

Revised test case:

#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <string.h>

int main()
{
    enum { server, client, size };
    int socket_fd[size];
    int const opt = 1;

    assert(socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd) == 0);

    char const msg[] = "A random message";
    send(socket_fd[client], msg, sizeof msg, MSG_DONTWAIT | MSG_NOSIGNAL);

    assert(setsockopt(socket_fd[server], SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)) != -1);

    union {
        struct cmsghdr cmh;
        char control[CMSG_SPACE(sizeof(ucred))];
    } control_un;

    control_un.cmh.cmsg_len = CMSG_LEN(sizeof(ucred));
    control_un.cmh.cmsg_level = SOL_SOCKET;
    control_un.cmh.cmsg_type = SCM_CREDENTIALS;

    msghdr msgh;
    msgh.msg_name = NULL;
    msgh.msg_namelen = 0;
    msgh.msg_iov = NULL;
    msgh.msg_iovlen = 0;
    msgh.msg_control = control_un.control;
    msgh.msg_controllen = sizeof(control_un.control);

    errno = 0;

    if (recvmsg(socket_fd[server], &msgh, MSG_PEEK) == -1)
    {
        printf("Error: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("Success!\n");
        exit(EXIT_FAILURE);
    }
}

Expected:
$ g++ test.c -o test && ./test 
Success!

Actual:
$ g++ test.c -o test && ./test 
Error: Operation not supported
Comment 3 Florian Weimer 2016-02-03 12:16:59 UTC
Thanks.  This happens with kernel-4.5.0-0.rc1.git2.1.fc24.x86_64 as well.

strace shows:

socketpair(PF_LOCAL, SOCK_STREAM, 0, [3, 4]) = 0
sendto(4, "A random message\0", 17, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 17
setsockopt(3, SOL_SOCKET, SO_PASSCRED, [1], 4) = 0
recvmsg(3, 0x7ffdd7e17400, MSG_PEEK)    = -1 EOPNOTSUPP (Operation not supported)

This looks like a kernel regression.  Please report it to the kernel developers.