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>
index | next in thread | raw e-mail
>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:
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199611280634.BAA00553>
