Date: Thu, 28 Nov 1996 01:34:35 -0500 From: Bill Paul <wpaul@skynet.ctr.columbia.edu> To: FreeBSD-gnats-submit@freebsd.org Subject: kern/2114: recv() with MSG_PEEK and NULL pointer wedges system Message-ID: <199611280634.BAA00553@skynet.ctr.columbia.edu> Resent-Message-ID: <199611280640.WAA09000@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 2114 >Category: kern >Synopsis: recv() with MSG_PEEK and NULL pointer wedges system >Confidential: no >Severity: serious >Priority: high >Responsible: freebsd-bugs >State: open >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Nov 27 22:40:02 PST 1996 >Last-Modified: >Originator: Bill Paul >Organization: Columbia University, New York City >Release: FreeBSD 2.1-STABLE i386 >Environment: 2.1.0-RELEASE 486DX2/66 with 20MB RAM 400MB IDE disk ET4000 graphics 3c503 ethernet adapter syscons console driver The test program that freezes my system has also been reported to have the same effect on a machine of 2.2-RELENG vintage. >Description: Enclosed are two simple programs: s.c and r.c, which I was using for testing. The r program creates an AF_UNIX socket, binds it, listen()s it, then accept()s on it, which makes it block while waiting for callers. The s program connect()s to the AF_UNIX socket and send a small amount of data using write(2). The r program first does a recv() on the socket with the MSG_PEEK flag set, mainly to see the size of the pending message before actually read(2)ing it. If then uses read(2) to read the message into a buffer. recv(2) expects a socket descriptor, a pointer to a buffer, the size of the buffer, and a flag. On a whim, I made the buffer pointer NULL. Doing this turned out to be a bad idea: once the r program hits the recv() system call, the system freezes, and the only way to recover is to reboot. Once in this frozen state, the system still accepts some interrupts: I can switch virtual consoles (syscons driver) and I can ping the system from another machine via ethernet, however I can't log in, and the console does not respond to any keypresses other than ALT-F?. >How-To-Repeat: Here is the source for the s program: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <err.h> #include <sys/types.h> #include <sys/time.h> #include <string.h> #include <sys/uio.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/fcntl.h> #include <sys/stat.h> #include <sys/ipc.h> #include <sys/msg.h> #ifndef lint static const char rcsid[] = "$Id: s.c,v 1.2 1996/11/24 06:17:07 wpaul Exp $"; #endif #define S_MKEY 12345678 #define C_MKEY 87654321 #define PERMS 0666 #define RPC_MSGTYPE 9090 struct msgbuf { long type; int data; }; struct cmessage { struct cmsghdr cmsg; int fd; }; int main() { struct iovec iov[1]; struct msghdr msg; struct cmessage cm; struct sockaddr_un sun; int s; int len; int readfd; int key; struct msqid_ds qid; struct msgbuf message; int type; char testbuf[] = "this is a test message"; strcpy(sun.sun_path, "/tmp/testsock"); sun.sun_family = AF_UNIX; len = sun.sun_len = sizeof(sun.sun_len) + sizeof(sun.sun_family) + strlen(sun.sun_path) + 1; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket creation failed"); if (connect(s, (struct sockaddr *)&sun, len) == -1) err(1, "couldn't connect socket"); write(s, &testbuf, strlen(testbuf)); close(s); exit(0); } Here is the source for the r program: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <err.h> #include <sys/types.h> #include <sys/time.h> #include <string.h> #include <sys/uio.h> #include <sys/fcntl.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/stat.h> #include <sys/ipc.h> #include <sys/msg.h> #ifndef lint static const char rcsid[] = "$Id: r.c,v 1.3 1996/11/24 06:17:07 wpaul Exp wpaul $"; #endif struct cmessage { struct cmsghdr cmsg; int fd; }; #define S_MKEY 12345678 #define C_MKEY 87654321 #define PERMS 0666 #define RPC_MSGTYPE 9090 #define S_MSGTYPE 9999999 struct msgbuf { long type; int data; }; int main() { struct iovec iov[1]; struct msghdr msg; struct cmessage cm; struct sockaddr_un sun; int s; int sock; int len; fd_set readfds; struct stat st; int readfd; int writefd; struct msqid_ds qid; struct msgbuf message; char testbuf[512]; if (unlink("/tmp/testsock") == -1) warn("couldn't remove old socket"); strcpy(sun.sun_path, "/tmp/testsock"); sun.sun_family = AF_UNIX; len = sun.sun_len = sizeof(sun.sun_len) + sizeof(sun.sun_family) + strlen(sun.sun_path) + 1; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) err(1, "socket creation failed"); if (bind(s, (struct sockaddr *)&sun, len) == -1) err(1, "couldn't bind socket"); listen(s, 2); if ((sock = accept(s, (struct sockaddr *)&sun, &len)) == -1) err(1, "accept failed"); FD_ZERO(&readfds); FD_SET(sock, &readfds); select(FD_SETSIZE, &readfds, NULL, NULL, NULL); len = 0; len = recv(sock, NULL, sizeof(testbuf), MSG_PEEK); /* ^^^^ bug!! */ /* replace NULL with &testbuf, and everything works fine */ printf("peeked length was: %d\n", len); len = 0; len = read(sock, &testbuf, sizeof(testbuf)); printf ("read length was: %d\n", len); close(s); close(sock); exit(0); } To reproduce the problem, do the following: % cc -o s s.c % cc -o r r.c % ./r & % ./s As soon as the r program wakes up and tries to peek at the message sent to it by the s program, the system will freeze. >Fix: Unknown. Presumeably, the recv() system call needs to do better argument checking. >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199611280634.BAA00553>