Messages in this thread Patch in this message | | | Date | Tue, 17 Nov 2009 18:35:43 -0800 | From | Sukadev Bhattiprolu <> | Subject | [PATCH] devpts_get_tty() should validate inode |
| |
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 527b3e4773628b30d03323a2cb5fb0d84441990f Author: Sukadev Bhattiprolu <sukadev@us.ibm.com> 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 <root@localdomain.pl> Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> --- Index: linux-2.6/fs/devpts/inode.c =================================================================== --- linux-2.6.orig/fs/devpts/inode.c 2009-10-20 21:11:03.000000000 -0700 +++ linux-2.6/fs/devpts/inode.c 2009-11-17 16:07:16.000000000 -0800 @@ -517,11 +517,23 @@ 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)
| |