Skip site navigation (1)Skip section navigation (2)
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>