On 04/06/2018 07:11 AM, Rusty Russell wrote: > I was really surprised that sendmsg() returned EBADF on a valid fd; > turns out I was using sendmsg with SCM_RIGHTS to send a closed fd, which > gives EBADF (see test program below). > > But this is only obliquely referenced in unix(7): > > SCM_RIGHTS > Send or receive a set of open file descriptors from another process. The data portion contains an integer > array of the file descriptors. The passed file descriptors behave as though they have been created with > dup(2). > > EBADF is not mentioned in the unix(7) ERRORS (it's mentioned in dup(2)). Thanks, Rusty. I applied the patch below. Cheers, Michael diff --git a/man7/unix.7 b/man7/unix.7 index 79f93899c..a8efc8940 100644 --- a/man7/unix.7 +++ b/man7/unix.7 @@ -467,6 +467,15 @@ see The specified local address is already in use or the filesystem socket object already exists. .TP +.B EBADF +This error can occur for +.BR sendmsg (2) +when sending a file descriptor as ancillary data over +a UNIX domain socket (see the description of +.BR SCM_RIGHTS , +above), and indicates that the file descriptor number that +is being sent is not valid (e.g., it is not an open file descripror). +.TP .B ECONNREFUSED The remote address specified by .BR connect (2) > Thanks, > Rusty. > > #include <assert.h> > #include <errno.h> > #include <stdbool.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <sys/socket.h> > #include <unistd.h> > > int fdpass_send(int sockout, int fd) > { > /* From the cmsg(3) manpage: */ > struct msghdr msg = { 0 }; > struct cmsghdr *cmsg; > struct iovec iov; > char c = 0; > union { /* Ancillary data buffer, wrapped in a union > in order to ensure it is suitably aligned */ > char buf[CMSG_SPACE(sizeof(fd))]; > struct cmsghdr align; > } u; > > msg.msg_control = u.buf; > msg.msg_controllen = sizeof(u.buf); > memset(&u, 0, sizeof(u)); > cmsg = CMSG_FIRSTHDR(&msg); > cmsg->cmsg_level = SOL_SOCKET; > cmsg->cmsg_type = SCM_RIGHTS; > cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); > memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); > > msg.msg_name = NULL; > msg.msg_namelen = 0; > msg.msg_iov = &iov; > msg.msg_iovlen = 1; > msg.msg_flags = 0; > > /* Keith Packard reports that 0-length sends don't work, so we > * always send 1 byte. */ > iov.iov_base = &c; > iov.iov_len = 1; > > return sendmsg(sockout, &msg, 0); > } > > int fdpass_recv(int sockin) > { > /* From the cmsg(3) manpage: */ > struct msghdr msg = { 0 }; > struct cmsghdr *cmsg; > struct iovec iov; > int fd; > char c; > union { /* Ancillary data buffer, wrapped in a union > in order to ensure it is suitably aligned */ > char buf[CMSG_SPACE(sizeof(fd))]; > struct cmsghdr align; > } u; > > msg.msg_control = u.buf; > msg.msg_controllen = sizeof(u.buf); > > msg.msg_name = NULL; > msg.msg_namelen = 0; > msg.msg_iov = &iov; > msg.msg_iovlen = 1; > msg.msg_flags = 0; > > iov.iov_base = &c; > iov.iov_len = 1; > > if (recvmsg(sockin, &msg, 0) < 0) > return -1; > > cmsg = CMSG_FIRSTHDR(&msg); > if (!cmsg > || cmsg->cmsg_len != CMSG_LEN(sizeof(fd)) > || cmsg->cmsg_level != SOL_SOCKET > || cmsg->cmsg_type != SCM_RIGHTS) { > errno = -EINVAL; > return -1; > } > > memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); > return fd; > } > > static void child(int sockfd) > { > int newfd = fdpass_recv(sockfd); > assert(newfd < 0); > exit(0); > } > > int main(void) > { > int sv[2]; > int pid, ret; > > assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); > > pid = fork(); > if (pid == 0) { > close(sv[1]); > child(sv[0]); > } > > close(sv[0]); > ret = fdpass_send(sv[1], sv[0]); > printf("fdpass of bad fd return %i (%s)\n", ret, strerror(errno)); > return 0; > } > -- > To unsubscribe from this list: send the line "unsubscribe linux-man" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ -- To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html