Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Nov 2005 18:59:08 -0800 (PST)
From:      Nate Eldredge <nge@cs.hmc.edu>
To:        bug-followup@FreeBSD.org, marcolz@stack.nl
Cc:        freebsd-current@freebsd.org, rwatson@freebsd.org, Philippe.Pegon@crc.u-strasbg.fr
Subject:   Re: kern/83375: Fatal trap 12 cloning a pty (was: show stopper for FreeBSD 6)
Message-ID:  <Pine.GSO.4.63.0511011820500.1991@turing>

next in thread | raw e-mail | index | archive | help
Okay, well I have made some progress here.  The problem, at least on 
7.0-CURRENT, occurs when you revoke() somebody's controlling tty, and then 
they try to clone it by opening /dev/tty.  revoke() will set the vnode's 
type to VBAD and ->v_rdev to NULL.  However ctty_clone() assumes that if 
the P_CONTROLT flag is set and p_session->s_ttyvp is non-null then 
s_ttyvp->v_rdev is non-null as well, and it passes it to dev_ref which 
dereferences the pointer.

One way to fix this is to have ctty_clone check for v_type == VBAD and/or 
v_rdev == NULL, and treat it like the case of s_ttyvp == NULL (give them 
the dummy /dev/ctty instead).  Does that seem reasonable?  I am not very 
familiar with the kernel, just trying to learn through fixing bugs.  When 
I do that, the screen testcase works until the machine runs out of memory 
:)

The dumps posted from 5.x look very different and this may be a separate 
bug.  Unfortunately I don't have a 5.x test box.

Here is a simpler test case.  I use /dev/ttyv9 as the terminal device, so 
you have to be root to run it, but it should also work with a pty.  So a 
regular user could exploit this.

------------------------snip---------------------
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <string.h>

#define TTY "/dev/ttyv9" /* should be totally unused */
#define CTTY "/dev/tty"

int main(void) {
   int ttyfd;
   pid_t pid;
   /* Get rid of my ctty. */
   printf("Parent starting: pid %d\n", getpid());
   pid = fork();
   if (pid < 0) {
     perror("fork");
     exit(1);
   } else if (pid > 0) {
     int status;
     /* parent */
     waitpid(pid, &status, 0);
     exit(0);
   }
   /* child */
   printf("Child: pid %d\n", getpid());

   if (setsid() < 0) {
     perror("setsid");
     exit(1);
   }

   ttyfd = open(TTY, O_RDWR);
   if (ttyfd < 0) {
     perror(TTY);
     exit(1);
   }
   if (ioctl(ttyfd, TIOCSCTTY) < 0) {
     perror("ioctl(TIOCSCTTY)");
     exit(1);
   }

   if (revoke(TTY) < 0) {
     perror("revoke");
     exit(1);
   }

   if (open(CTTY, O_RDWR) < 0) {
     perror(CTTY);
     exit(1);
   }
   return 0;
}
-----------------------------snip-------------------

-- 
Nate Eldredge
nge@cs.hmc.edu



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.GSO.4.63.0511011820500.1991>