FreeBSD Bugzilla – Attachment 178701 Details for
Bug 215933
SCM_RIGHTS messages being lost, socket data being lost as well (with example code)
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
Minimal example code to demonstrate the bug
scm_rights_thrash.c (text/plain), 4.27 KB, created by
ian
on 2017-01-10 11:48:01 UTC
(
hide
)
Description:
Minimal example code to demonstrate the bug
Filename:
MIME Type:
Creator:
ian
Created:
2017-01-10 11:48:01 UTC
Size:
4.27 KB
patch
obsolete
>// Code to test thrash the fdesc over unix socket transfer processs.. >// Spawn a slave copy of our own process to run as the client, send it random >// messages, see what/when/if it breaks. > >#include <stdio.h> >#include <stdlib.h> >#include <unistd.h> >#include <fcntl.h> >#include <sysexits.h> >#include <string.h> >#include <assert.h> >#include <errno.h> >#include <sys/types.h> >#include <sys/socket.h> > >// Slave process simply consumes messages and closes incoming file descriptors.. >void >run_consumer(int fd){ > union { // force structure alignment and allocate some extra space for it.. > struct cmsghdr cmh; > char control[CMSG_SPACE(sizeof(int))+64]; > } control_union; > struct cmsghdr *cmsgptr=&control_union.cmh; > struct msghdr msg; > struct iovec iov; > size_t total=0,dropped=0; > int result,rxindex=0; > size_t expected_sequence=0; > char rxbuf[131072]; > printf("Slave %d ready..\n",getpid()); > do { > memset(&control_union,0,sizeof(control_union)); > memset(&msg,0,sizeof(struct msghdr)); > iov.iov_len=sizeof(rxbuf)-rxindex; > iov.iov_base=&rxbuf[rxindex]; > msg.msg_iov=&iov; > msg.msg_iovlen=1; > msg.msg_control=&control_union; > msg.msg_controllen=sizeof(control_union); > result=recvmsg(fd,&msg,0); > if(result>0){ > int numfds=0; > total+=result; > rxindex+=result; > if(msg.msg_controllen>=CMSG_LEN(sizeof(int)) && cmsgptr->cmsg_level==SOL_SOCKET && cmsgptr->cmsg_type==SCM_RIGHTS){ > int *fdptr=(int *)CMSG_DATA(cmsgptr); > numfds=(cmsgptr->cmsg_len-CMSG_LEN(0))/sizeof(int); > for(int i=0;i<numfds;i++){ close(fdptr[i]); } > } > printf("\033[1;32mSlave received data %d bytes (rxindex %d) ctrl=%d nfds=%d flags=%x\033[0m\n",result,rxindex,msg.msg_controllen,numfds,msg.msg_flags); > while(rxindex>(sizeof(int)*2) && rxindex>=((size_t *)rxbuf)[0]){ // Enough data to make a 'message' > size_t size=((size_t *)rxbuf)[0]; > size_t sequence=((size_t *)rxbuf)[1]; > if(sequence==expected_sequence){ > printf("\033[1;32m Got message sequence=%zd size=%zd\033[0m\n",sequence,size); > } else { > dropped+=sequence-expected_sequence; > printf("\033[1;31m Got BAD message sequence=%zd expected=%zd size=%zd\033[0m\n",sequence,expected_sequence,size); > } > expected_sequence=sequence+1; > if(rxindex>size){ > memmove(rxbuf,&rxbuf[size],rxindex-size); > rxindex-=size; > } else { > rxindex=0; > } > } > } > } while (result>0); > printf("Slave done received a total of %zd bytes, dropped %zd frames (Guessed original based on fdesc frame only frame drops %zd)..\n",total,dropped,total+(dropped*(sizeof(size_t)*2))); > exit(0); >} > >// Master forks slave then sends variable size messages with a second message containing a fdesc closly following it >int >send_test_message(int peerfd, size_t sequence, size_t size, int sendfd){ > int result; > union { > struct cmsghdr cmh; > char control[CMSG_SPACE(sizeof(int))+64]; > } control_union; > struct msghdr msg; > struct iovec iov; > struct cmsghdr *cmsgptr=&control_union.cmh; > char sendbuf[65536]; > size_t *sendinfo=(size_t *)sendbuf; > assert((size+sizeof(size_t)*2)<=sizeof(sendbuf)); > memset(&control_union,0,sizeof(control_union)); > memset(&msg,0,sizeof(struct msghdr)); > iov.iov_len=size+(sizeof(size_t)*2); > iov.iov_base=sendbuf; > msg.msg_iov=&iov; > msg.msg_iovlen=1; > // Stuff size and sequence info into the 'data' chunk we are sending. > sendinfo[0]=size+(sizeof(size_t)*2); > sendinfo[1]=sequence; > if(sendfd>=0){ > // If we have a sendfd to ship, add it and set the control message pointer > int *fdptr=(int *)CMSG_DATA(cmsgptr); > cmsgptr->cmsg_len=CMSG_LEN(sizeof(int)); > cmsgptr->cmsg_level=SOL_SOCKET; > cmsgptr->cmsg_type=SCM_RIGHTS; > fdptr[0]=sendfd; > msg.msg_control=cmsgptr; > msg.msg_controllen=cmsgptr->cmsg_len; > } > result=sendmsg(peerfd,&msg,0); > assert(result==iov.iov_len); > return iov.iov_len; >} > >int >main(int argc, char *argv[]){ > int fds[2]; > size_t total=0; > if(socketpair(AF_UNIX,SOCK_STREAM,0,fds)==0){ > size_t sequence=0; > int newpid=fork(); > if(newpid<0) exit(EX_OSERR); > if(newpid==0){ close(fds[1]); run_consumer(fds[0]); } > close(fds[0]); > printf("Master ready..\n"); > for(size_t i=6000;i<8500;i++){ > int tfd=open("/dev/null",O_WRONLY); > total+=send_test_message(fds[1],sequence++,i,-1); > total+=send_test_message(fds[1],sequence++,0,tfd); > close(tfd); > } > } > printf("Master sent a total of %zd bytes\n",total); > usleep(50000); > exit(0); >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 215933
: 178701