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>