Skip to content

Commit

Permalink
devpts_get_tty() should validate inode
Browse files Browse the repository at this point in the history
devpts_get_tty() assumes that the inode passed in is associated with a valid
pty.  But if the only reference to the pty is via a bind-mount, the inode
passed to devpts_get_tty() while valid, would refer to a pty that no longer
exists.

With a lot of debug effort, Grzegorz Nosek developed a small program (see
below) to reproduce a crash on recent kernels. This crash is a regression
introduced by the commit:

	commit 527b3e4
	Author: Sukadev Bhattiprolu <[email protected]>
	Date:   Mon Oct 13 10:43:08 2008 +0100

To fix, ensure that the dentry associated with the inode has not yet been
deleted/unhashed by devpts_pty_kill().

See also:
https://lists.linux-foundation.org/pipermail/containers/2009-July/019273.html 

tty-bug.c:

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/signal.h>
#include <unistd.h>
#include <stdio.h>

#include <linux/fs.h>

void dummy(int sig)
{
}

static int child(void *unused)
{
	int fd;

	signal(SIGINT, dummy); signal(SIGHUP, dummy);
	pause(); /* cheesy synchronisation to wait for /dev/pts/0 to appear */

	mount("/dev/pts/0", "/dev/console", NULL, MS_BIND, NULL);
	sleep(2);

	fd = open("/dev/console", O_RDWR);
	dup(0); dup(0);
	write(1, "Hello world!\n", sizeof("Hello world!\n")-1);
	return 0;
}

int main(void)
{
	pid_t pid;
	char *stack;

	stack = malloc(16384);
	pid = clone(child, stack+16384, CLONE_NEWNS|SIGCHLD, NULL);

	open("/dev/ptmx", O_RDWR|O_NOCTTY|O_NONBLOCK);

	unlockpt(fd); grantpt(fd);

	sleep(2);
	kill(pid, SIGHUP);
	sleep(1);
	return 0; /* exit before child opens /dev/console */
}

Reported-by: Grzegorz Nosek <[email protected]>
Signed-off-by: Sukadev Bhattiprolu <[email protected]>
Tested-by: Serge Hallyn <[email protected]>
Cc: stable <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Sukadev Bhattiprolu authored and gregkh committed Dec 11, 2009
1 parent 68cb4f8 commit edfacdd
Showing 1 changed file with 14 additions and 2 deletions.
16 changes: 14 additions & 2 deletions fs/devpts/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,11 +517,23 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)

struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
{
struct dentry *dentry;
struct tty_struct *tty;

BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));

/* Ensure dentry has not been deleted by devpts_pty_kill() */
dentry = d_find_alias(pts_inode);
if (!dentry)
return NULL;

tty = NULL;
if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
return (struct tty_struct *)pts_inode->i_private;
return NULL;
tty = (struct tty_struct *)pts_inode->i_private;

dput(dentry);

return tty;
}

void devpts_pty_kill(struct tty_struct *tty)
Expand Down

0 comments on commit edfacdd

Please sign in to comment.