[net.bugs.4bsd] fcntl

damonp@daemon.UUCP (Damon Permezel) (08/22/84)

Index:	/sys/sys/kern_descrip.c 4.2BSD

Description:
	The man page for 'fcntl' states that, for the F_GETOWN and F_GETOWN
	options, process groups are indicated with negative values, and
	process ids are indicated with positive values.
	If a fcntl is performed on a socket, the value is placed unmodified
	in the so_pgrp field of the socket structure.

	The routine sohasoutofband() assumes that if so_pgrp is positive,
	it is a process group, and if negative, a process ID.
	If one does an ioctl(SIOCSPGRP) on a socket, the soo_ioctl() routine
	treats so_pgrp similar the sohasoutofband().

	This problem was noticed when trying to send out-of-band data in the
	UNIX domain on a stream socket.  sohasoutofband() delivered the signal
	to the wrong process(es).

	There will be a companion bug report soon describing how you can
	get OOB data to work in the UNIX domain!

Repeat-By:
	#include <sys/types.h>
	#include <sys/socket.h>
	#include <fcntl.h>
	#include <sys/ioctl.h>

	main() {
		static struct sockaddr sock;
		static struct sockaddr sock2;
		int s;
		int socklen, stuff, pgrp, res;

		if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
			perror("socket");
			exit(1);
		}

		strcpy(sock.sa_data, "testsock");
		socklen = sizeof(sock);

		unlink("testsock");

		if (bind(s, &sock, socklen) < 0) {
			perror("bind");
			exit(1);
		}

		pgrp = getpgrp();	/* get our process group	*/
		res = fcntl(s, F_SETOWN, -pgrp);	/* set to process group	*/
		if (res < 0) {
			perror("fcntl");
			exit(3);
		}

		res = ioctl(s, SIOCGPGRP, &stuff);
		if (res < 0) {
			perror("ioctl");
			exit(4);
		}

		printf("process group set to %d, but comes back %d\n", pgrp, stuff);
}

Fix:
	I changed the routines fsetown() and fgetown() to negate the
	negated process group ID, thus rendering it positive, prior to stuffing
	it in so_pgrp. Diffs follow. Line numbers will be off.

4a5,21
>  * Revision 1.4  84/08/21  03:15:37  damonp
>  * Since the fcntl man page asserts that process groups for the
>  * F_SETOWN and F_GETOWN options are <0, and soo_ioctl(SIOCSPGRP)
>  * and sohasoutofband() both agree that so_pgrp is >0, it was necessary
>  * to negate it in fsetown() and fgetown().
>  * -dap@tek
>  * 
202c219
< 		*valuep = ((struct socket *)fp->f_data)->so_pgrp;
---
> 		*valuep = -((struct socket *)fp->f_data)->so_pgrp;
218c235
< 		((struct socket *)fp->f_data)->so_pgrp = value;
---
> 		((struct socket *)fp->f_data)->so_pgrp = -value;