Subject: bin/28474: usr.bin/write (& wall) can't handle ptyfs system
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <gcw@primenet.com.au>
List: netbsd-bugs
Date: 11/30/2004 04:00:00
>Number:         28474
>Category:       bin
>Synopsis:       write does some weird checking and can't handle ptyfs
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Nov 30 04:00:00 +0000 2004
>Originator:     Geoff C. Wing
>Release:        NetBSD 2.99.10 (2004-11-30)
>Organization:
>Environment:
System: NetBSD g.primenet.com.au 2.99.10 NetBSD 2.99.10 (G) #0: Tue Nov 30 14:06:40 EST 2004 gcw@g.primenet.com.au:/usr/netbsd/src/sys/arch/i386/compile/G i386
Architecture: i386
Machine: i386
>Description:
	write does a security check to make sure people can't escape the /dev
	directory by checking for dot & slash before using the tty string.
	However, the tty string is appended to _PATH_DEV (which starts with
	a slash) so checking for dot is sufficient to prevent "../" bypassing
	and if you need to stop people from using subdirectories in /dev
	because they can write or mount there then security's out the window
	anyway.

	write also strips out all parts of a tty up to the last slash to find
	the tty name.  Then gives error messages as though it had "/dev/"
	prepended.  If we think we have "/dev/" there and not "/foo/" then
	we should act as if we do.  Thus when we see "/dev/pty/2" we parse
	it as "pty/2" instead of saying "2" and printing out "/dev/2".
	
	This also affects wall
>How-To-Repeat:
	use with ptyfs
>Fix:
--- usr.bin/write/term_chk.c.org	2004-10-28 14:25:02.000000000 +1000
+++ usr.bin/write/term_chk.c	2004-11-30 14:39:29.000000000 +1100
@@ -63,7 +63,7 @@
 	struct stat s;
 	int i, fd, serrno;
 
-	if (strcspn(tty, "./") != strlen(tty)) {
+	if (strchr(tty, '.') != NULL) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -111,7 +111,6 @@
 	int myttyfd;
 	int msgsok;
 	char *mytty;
-	char *cp;
 
 	/* check that sender has write enabled */
 	if (isatty(fileno(stdin)))
@@ -126,8 +125,8 @@
 		errx(1, "Cannot find your tty");
 	if ((mytty = ttyname(myttyfd)) == NULL)
 		err(1, "Cannot find the name of your tty");
-	if ((cp = strrchr(mytty, '/')) != NULL)
-		mytty = cp + 1;
+	if (strncmp(mytty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+		mytty += sizeof(_PATH_DEV) - 1;
 	if (term_chk(myuid, mytty, &msgsok, atime, 1, saved_egid) == -1)
 		err(1, "%s%s", _PATH_DEV, mytty);
 	if (!msgsok) {