kern/83375: Fatal trap 12 cloning a pty (was: show stopper for
FreeBSD 6)
Nate Eldredge
nge at cs.hmc.edu
Tue Nov 1 18:59:10 PST 2005
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 at cs.hmc.edu
More information about the freebsd-current
mailing list