diff options
Diffstat (limited to 'drivers/tty/tty_io.c')
| -rw-r--r-- | drivers/tty/tty_io.c | 65 | 
1 files changed, 61 insertions, 4 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index de06c3c2ff70..3149114bf130 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2255,6 +2255,7 @@ static int tty_fasync(int fd, struct file *filp, int on)  	return retval;  } +static bool tty_legacy_tiocsti __read_mostly = IS_ENABLED(CONFIG_LEGACY_TIOCSTI);  /**   * tiocsti		-	fake input character   * @tty: tty to fake input into @@ -2273,6 +2274,9 @@ static int tiocsti(struct tty_struct *tty, char __user *p)  	char ch, mbz = 0;  	struct tty_ldisc *ld; +	if (!tty_legacy_tiocsti) +		return -EIO; +  	if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))  		return -EPERM;  	if (get_user(ch, p)) @@ -3494,7 +3498,7 @@ void tty_default_fops(struct file_operations *fops)  	*fops = tty_fops;  } -static char *tty_devnode(struct device *dev, umode_t *mode) +static char *tty_devnode(const struct device *dev, umode_t *mode)  {  	if (!mode)  		return NULL; @@ -3526,7 +3530,14 @@ static ssize_t show_cons_active(struct device *dev,  	struct console *c;  	ssize_t count = 0; -	console_lock(); +	/* +	 * Hold the console_list_lock to guarantee that no consoles are +	 * unregistered until all console processing is complete. +	 * This also allows safe traversal of the console list and +	 * race-free reading of @flags. +	 */ +	console_list_lock(); +  	for_each_console(c) {  		if (!c->device)  			continue; @@ -3538,6 +3549,13 @@ static ssize_t show_cons_active(struct device *dev,  		if (i >= ARRAY_SIZE(cs))  			break;  	} + +	/* +	 * Take console_lock to serialize device() callback with +	 * other console operations. For example, fg_console is +	 * modified under console_lock when switching vt. +	 */ +	console_lock();  	while (i--) {  		int index = cs[i]->index;  		struct tty_driver *drv = cs[i]->device(cs[i], &index); @@ -3553,6 +3571,8 @@ static ssize_t show_cons_active(struct device *dev,  	}  	console_unlock(); +	console_list_unlock(); +  	return count;  }  static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL); @@ -3572,13 +3592,51 @@ void console_sysfs_notify(void)  		sysfs_notify(&consdev->kobj, NULL, "active");  } +static struct ctl_table tty_table[] = { +	{ +		.procname	= "legacy_tiocsti", +		.data		= &tty_legacy_tiocsti, +		.maxlen		= sizeof(tty_legacy_tiocsti), +		.mode		= 0644, +		.proc_handler	= proc_dobool, +	}, +	{ +		.procname	= "ldisc_autoload", +		.data		= &tty_ldisc_autoload, +		.maxlen		= sizeof(tty_ldisc_autoload), +		.mode		= 0644, +		.proc_handler	= proc_dointvec, +		.extra1		= SYSCTL_ZERO, +		.extra2		= SYSCTL_ONE, +	}, +	{ } +}; + +static struct ctl_table tty_dir_table[] = { +	{ +		.procname	= "tty", +		.mode		= 0555, +		.child		= tty_table, +	}, +	{ } +}; + +static struct ctl_table tty_root_table[] = { +	{ +		.procname	= "dev", +		.mode		= 0555, +		.child		= tty_dir_table, +	}, +	{ } +}; +  /*   * Ok, now we can initialize the rest of the tty devices and can count   * on memory allocations, interrupts etc..   */  int __init tty_init(void)  { -	tty_sysctl_init(); +	register_sysctl_table(tty_root_table);  	cdev_init(&tty_cdev, &tty_fops);  	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||  	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) @@ -3600,4 +3658,3 @@ int __init tty_init(void)  #endif  	return 0;  } -  |