/* * Check that fd does not get created when the ancillary data buffer * gets truncated... * Philippe Troin * This snippet is licensed under the GNU General Public License. */ #include #include #include #include #include #include #include #include #include #include #include void child_proc(int sock) { struct msghdr msg; int zero; int devnull; char ancdata[CMSG_SPACE(sizeof(devnull))]; struct iovec iov[1]; struct cmsghdr *cmsg; /**/ zero = 0; if ((devnull = open("/dev/null", O_RDWR))<0) perror("child: open /dev/null"), exit(1); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = ancdata; msg.msg_controllen = sizeof(ancdata); msg.msg_flags = 0; iov[0].iov_base = &zero; iov[0].iov_len = sizeof(zero); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(devnull)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *((int*)CMSG_DATA(cmsg)) = devnull; if (sendmsg(sock, &msg, 0)<0) perror("child: sendmsg"), exit(1); } void parent_proc(int sock) { struct msghdr msg; int data; const char padvalue[]="f00bar"; union { struct { char ancdata[2]; char padding[6]; } a; char safety[CMSG_SPACE(sizeof(int))]; } ancs; struct iovec iov[1]; /**/ if (sock != 3) fprintf(stderr, "expected parent socket at fd 3, got %d\n", sock), exit(1); if (close(4)>=0 || errno != EBADF) fprintf(stderr, "already got a descriptor at fd 4, why ?\n"), exit(1); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = ancs.a.ancdata; msg.msg_controllen = sizeof(ancs.a.ancdata); msg.msg_flags = 0; iov[0].iov_base = &data; iov[0].iov_len = sizeof(data); memset(&ancs, 0, sizeof(ancs)); memcpy(ancs.a.padding, padvalue, strlen(padvalue)); fprintf(stderr, "calling recvmsg with controllen = %d\n", msg.msg_controllen); if (recvmsg(sock, &msg, 0)<0) perror("parent: recvmsg"), exit(1); fprintf(stderr, "recvmsg returned with controllen = %d\n", msg.msg_controllen); if (memcmp(ancs.a.padding, padvalue, strlen(padvalue)) != 0) fprintf(stderr, "recvmsg smashed the stack !\n"); if (close(4)>=0 || errno != EBADF) fprintf(stderr, "fd 4 was passed, even it had no room to be put in !\n"); } int main(int argc, char *argv[]) { int fds[2]; pid_t childpid; /**/ if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fds)<0) perror("socketpair"), exit(1); if ((childpid=fork())<0) perror("fork"), exit(1); if (childpid==0) { /* Child */ if (close(fds[0])<0) perror("child: close"), exit(1); child_proc(fds[1]); } else { /* Parent */ int status; /**/ if (close(fds[1])<0) perror("parent: close"), exit(1); parent_proc(fds[0]); if (waitpid(childpid, &status, 0)<0) perror("parent: waitpid"), exit(1); if (status != 0) fprintf(stderr, "child exited with status %d\n", status), exit(1); } exit(0); }