[3296] in linux-net channel archive

home help back first fref pref prev next nref lref last post

bug in tcp.c. How to fix?

daemon@ATHENA.MIT.EDU (A.N.Kuznetsov)
Tue Jun 18 14:37:46 1996

From: "A.N.Kuznetsov" <kuznet@ms2.inr.ac.ru>
To: alan@cymru.net (Alan Cox)
Date: 	Tue, 18 Jun 1996 17:30:25 +0400 (MSD)
Cc: linux-net@vger.rutgers.edu
In-Reply-To: <199606171434.PAA17126@snowcrash.cymru.net> from "Alan Cox" at Jun 17, 96 03:34:44 pm

Hello!

recv urgent data does not advance "copied" pointer,
so that when 2 or more urgent data chunks follow in row,
all they except for the last are duplicated(!) as usual data.

Test program follows.

Expected:
OOB1 A
OOB2 B
OOB3 C

Got:
OOB1 A
OOB2 B
OOB3 C
INLINE: [AB]

Please, NOTE that this bug has nothing to do with the well-known
BSD interface bug: "when two chunks of urgent data arrive
before user read the first one it goes to ordinary data stream"

I see no good fix for this problem now. Apparently, we must
advance copied pointer and cleanup_rbuf somewhere after tcp_recv_urg.

Bug is pretty serious, it affects rlogin sometimes.
(And fatally, if rlogin is encrypted).

Alexey Kuznetsov.




Test program.

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>

main()
{
	int sender, receiver;
	struct sockaddr_in addr;
	int res;
	int addrsize = sizeof(addr);

	receiver = socket(AF_INET, SOCK_STREAM, 0);
	if (receiver < 0) {
		perror("socket");
		exit(1);
	}
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port   = htons(12345);
	res = bind(receiver, &addr, sizeof(addr));
	if (res < 0) {
		perror("bind");
		exit(1);
	}

	if (fork()) {
		int fd;
		unsigned char c;
		char buf[3];

		for (;;) {
			if (listen(receiver, 1) < 0)
				continue;
			fd = accept(receiver, &addr, &addrsize);
			if (fd < 0) {
				perror("accept");
				exit(1);
			}
			close(receiver);
			break;
		}
		do {
			res = recv(fd, &c, 1, MSG_OOB);
		} while (res != 1);
		printf("OOB1 %c\n", c);
		do {
			res = recv(fd, &c, 1, MSG_OOB);
		} while (res != 1);
		printf("OOB2 %c\n", c);
		do {
			res = recv(fd, &c, 1, MSG_OOB);
		} while (res != 1);
		printf("OOB3 %c\n", c);
		res = read(fd, buf, 3);
		if (res > 0) {
			printf("INLINE: [%.*s]\n", res, buf);
		}
		exit(0);
	}
	      
	close(receiver);
	sleep(5);

	sender = socket(AF_INET, SOCK_STREAM, 0);
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr  = htonl(0x7F000001);
	addr.sin_port   = htons(12345);
	connect(sender, &addr, addrsize);

	send(sender, "A", 1, MSG_OOB);
	sleep(5);
	send(sender, "B", 1, MSG_OOB);
	sleep(5);
	send(sender, "C", 1, MSG_OOB);
	sleep(5);
	exit(0);
}


home help back first fref pref prev next nref lref last post