Bug 69477

Summary: LTC1053-problem with send/recv through sockets
Product: [Retired] Red Hat Linux Reporter: IBM Bug Proxy <bugproxy>
Component: kernelAssignee: Arjan van de Ven <arjanv>
Status: CLOSED NOTABUG QA Contact: Brian Brock <bbrock>
Severity: high Docs Contact:
Priority: high    
Version: 7.2   
Target Milestone: ---   
Target Release: ---   
Hardware: ia64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2002-07-22 19:30:18 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description IBM Bug Proxy 2002-07-22 19:28:31 UTC
ia64, RedHat 7.2, Kernel: 2.4.9-18custom

We are passing filedescriptors through sockets, but the length of the messages
seem to be rounded up to 8-byte boundaries on the receive end, despite the fact
that this is not what we want.  The attached testcase, socktest.C, seems to
demonstrate is that the msg_controllen parameter used in recvmsg() is adjusted
in increments of 8-bytes, but since the file-descriptors are represented by
4-byte values, we cannot extract the necessary information from the controllen:

The test does the following:

(1) Create a domain socket pair
(2) Fork
(3) One process will send three messages to the other through the socketpair
(4) Each message contains 4 bytes of information, and 1, then 2, then 3
file-descriptors

The testcase outputs some information, including the controllen on the sending
side, and the receiving side. The controllen before the sendmsg(), and after the
recvmsg() should match, but the testcase shows that we seem to be incorrectly
rounding the value up to the nearest 8-byte boundary.

Please copy David Kalmuk (dckalmuk.com) on all correspondence.  He does
not have a bugzilla account.

--------cut here socktest.C----------
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socketvar.h>

#define CMSG_SPACE(_x) (sizeof(struct cmsghdr)+(_x))
#define CMSG_LEN(_x) CMSG_SPACE(_x)

#define domainSocketPair(_a) socketpair(AF_UNIX,     \
                                        SOCK_STREAM, \
                                        0,           \
                                        (_a))
#define SOCK_MAX_FD 3

typedef struct
{
    int   fd[SOCK_MAX_FD];
    int   num_fd;
    void* buff;
    int   buff_lng;
}SOCK_MSG;


int sockSendMsg(SOCK_MSG* pParmData,
                int       sock)
{
  int rc = 0;
  int count;
  int num_fd = pParmData->num_fd;
  struct msghdr msg;
  struct iovec iov[1];
  int* pData;

  union
  {
    struct cmsghdr cm;
    char control[CMSG_SPACE((sizeof(int)*SOCK_MAX_FD))];
  }control_un;

  struct cmsghdr *cmptr;

  msg.msg_control = &control_un.cm;
  msg.msg_flags  = 0;
  msg.msg_controllen = sizeof(cmsghdr) + (sizeof(int)*num_fd);

  cmptr             = CMSG_FIRSTHDR(&msg);
  cmptr->cmsg_len   = CMSG_LEN(sizeof(int) * num_fd);
  cmptr->cmsg_level = SOL_SOCKET;
  cmptr->cmsg_type  = SCM_RIGHTS;
  pData = (int*)CMSG_DATA(cmptr);

  for (count = 0; count < num_fd; count++)
  {
    *pData = pParmData->fd[count];
    pData++;
  }

  msg.msg_name   = (caddr_t) 0;
  msg.msg_namelen = 0;

  iov[0].iov_base = (char*)pParmData->buff;
  iov[0].iov_len  = pParmData->buff_lng;

  msg.msg_iov    = iov;
  msg.msg_iovlen = 1;

  printf("Sending %d descriptors\n", pParmData->num_fd);
  printf("Sending Controllen: %d\n", msg.msg_controllen);

  rc = sendmsg(sock, &msg, 0);

  printf("Send rc: %d\n", rc);

  return rc;
}

int sockRecvMsg(SOCK_MSG* pParmData,
                int       sock)
{
  int rc = 0;
  struct msghdr msg;
  struct iovec iov[1];
  int count;
  int* pData;

  union
  {
    struct cmsghdr cm;
    char control[CMSG_SPACE((sizeof(int)*SOCK_MAX_FD))];
  }control_un;

  struct cmsghdr *cmptr;

  msg.msg_control = &control_un.cm;
  msg.msg_controllen = sizeof(control_un);
  msg.msg_flags = 0;

  cmptr = CMSG_FIRSTHDR(&msg);

  msg.msg_name = NULL;
  msg.msg_namelen = 0;

  iov[0].iov_base = (char*)pParmData->buff;
  iov[0].iov_len = pParmData->buff_lng;

  msg.msg_iov = iov;
  msg.msg_iovlen = 1;

  printf("Receive Controllen: %d\n", msg.msg_controllen);

  rc = recvmsg(sock, &msg, 0);

  printf("Recv rc: %d\n", rc);
  printf("Received Controllen: %d\n", msg.msg_controllen);

  if (rc > 0)
  {
     pData = (int*)CMSG_DATA(cmptr);

     count = 0;
     while(msg.msg_controllen > sizeof(cmsghdr))
     {
        pParmData->fd[count] = *pData;
        pData++;
        msg.msg_controllen -= sizeof(int);
        count++;
     }
  }

  return rc;
}

int main()
{
   int pair[2];
   int rc;
   int testData = 3;

   SOCK_MSG msgData;

   domainSocketPair(pair);

   msgData.fd[0]  = pair[0];
   msgData.fd[1]  = pair[1];
   msgData.fd[2]  = pair[0];
   msgData.num_fd = 1;

   msgData.buff = &testData;
   msgData.buff_lng = sizeof(testData);

   if (fork() == 0)
   {
      sockSendMsg(&msgData,
                  pair[0]);

      msgData.num_fd = 2;
      sleep(5);
      sockSendMsg(&msgData,
                  pair[0]);

      msgData.num_fd = 3;
      sleep(5);
      sockSendMsg(&msgData,
                  pair[0]);
   }
   else
   {
      sockRecvMsg(&msgData,
                  pair[1]);

      printf("Received: %d %d\n", msgData.fd[0], *((int*)msgData.buff));

      sockRecvMsg(&msgData,
                  pair[1]);
      printf("Received: %d %d %d\n", msgData.fd[0], msgData.fd[1],
*((int*)msgData.buff));

      sockRecvMsg(&msgData,
                  pair[1]);
      printf("Received: %d %d %d\n", msgData.fd[0], msgData.fd[1],
*((int*)msgData.buff));
   }

   return 0;
}

--------cut here----------------

Comment 1 Arjan van de Ven 2002-07-22 19:30:13 UTC
Kernel: 2.4.9-18custom

1) we don't support custom compiled kernels
2) Please try the 2.4.9-34 erratum kernel since it has quite a few ia64 fixes