2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-21 19:53:59 +08:00
linux-next/fs/proc/proc_tty.c

191 lines
4.7 KiB
C
Raw Normal View History

/*
* proc_tty.c -- handles /proc/tty
*
* Copyright 1997, Theodore Ts'o
*/
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/tty.h>
#include <linux/seq_file.h>
#include <linux/bitops.h>
tty fix oops when rmmod 8250 After rmmod 8250.ko tty_kref_put starts kwork (release_one_tty) to release proc interface oops when accessing driver->driver_name in proc_tty_unregister_driver Use jprobe, found driver->driver_name point to 8250.ko static static struct uart_driver serial8250_reg .driver_name= serial, Use name in proc_dir_entry instead of driver->driver_name to fix oops test on linux 4.1.12: BUG: unable to handle kernel paging request at ffffffffa01979de IP: [<ffffffff81310f40>] strchr+0x0/0x30 PGD 1a0d067 PUD 1a0e063 PMD 851c1f067 PTE 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ... ... [last unloaded: 8250] CPU: 7 PID: 116 Comm: kworker/7:1 Tainted: G O 4.1.12 #1 Hardware name: Insyde RiverForest/Type2 - Board Product Name1, BIOS NE5KV904 12/21/2015 Workqueue: events release_one_tty task: ffff88085b684960 ti: ffff880852884000 task.ti: ffff880852884000 RIP: 0010:[<ffffffff81310f40>] [<ffffffff81310f40>] strchr+0x0/0x30 RSP: 0018:ffff880852887c90 EFLAGS: 00010282 RAX: ffffffff81a5eca0 RBX: ffffffffa01979de RCX: 0000000000000004 RDX: ffff880852887d10 RSI: 000000000000002f RDI: ffffffffa01979de RBP: ffff880852887cd8 R08: 0000000000000000 R09: ffff88085f5d94d0 R10: 0000000000000195 R11: 0000000000000000 R12: ffffffffa01979de R13: ffff880852887d00 R14: ffffffffa01979de R15: ffff88085f02e840 FS: 0000000000000000(0000) GS:ffff88085f5c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffa01979de CR3: 0000000001a0c000 CR4: 00000000001406e0 Stack: ffffffff812349b1 ffff880852887cb8 ffff880852887d10 ffff88085f5cd6c2 ffff880852800a80 ffffffffa01979de ffff880852800a84 0000000000000010 ffff88085bb28bd8 ffff880852887d38 ffffffff812354f0 ffff880852887d08 Call Trace: [<ffffffff812349b1>] ? __xlate_proc_name+0x71/0xd0 [<ffffffff812354f0>] remove_proc_entry+0x40/0x180 [<ffffffff815f6811>] ? _raw_spin_lock_irqsave+0x41/0x60 [<ffffffff813be520>] ? destruct_tty_driver+0x60/0xe0 [<ffffffff81237c68>] proc_tty_unregister_driver+0x28/0x40 [<ffffffff813be548>] destruct_tty_driver+0x88/0xe0 [<ffffffff813be5bd>] tty_driver_kref_put+0x1d/0x20 [<ffffffff813becca>] release_one_tty+0x5a/0xd0 [<ffffffff81074159>] process_one_work+0x139/0x420 [<ffffffff810745a1>] worker_thread+0x121/0x450 [<ffffffff81074480>] ? process_scheduled_works+0x40/0x40 [<ffffffff8107a16c>] kthread+0xec/0x110 [<ffffffff81080000>] ? tg_rt_schedulable+0x210/0x220 [<ffffffff8107a080>] ? kthread_freezable_should_stop+0x80/0x80 [<ffffffff815f7292>] ret_from_fork+0x42/0x70 [<ffffffff8107a080>] ? kthread_freezable_should_stop+0x80/0x80 Signed-off-by: nixiaoming <nixiaoming@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-09-15 17:45:56 +08:00
#include "internal.h"
/*
* The /proc/tty directory inodes...
*/
static struct proc_dir_entry *proc_tty_driver;
/*
* This is the handler for /proc/tty/drivers
*/
static void show_tty_range(struct seq_file *m, struct tty_driver *p,
dev_t from, int num)
{
seq_printf(m, "%-20s ", p->driver_name ? p->driver_name : "unknown");
seq_printf(m, "/dev/%-8s ", p->name);
if (p->num > 1) {
seq_printf(m, "%3d %d-%d ", MAJOR(from), MINOR(from),
MINOR(from) + num - 1);
} else {
seq_printf(m, "%3d %7d ", MAJOR(from), MINOR(from));
}
switch (p->type) {
case TTY_DRIVER_TYPE_SYSTEM:
seq_puts(m, "system");
if (p->subtype == SYSTEM_TYPE_TTY)
seq_puts(m, ":/dev/tty");
else if (p->subtype == SYSTEM_TYPE_SYSCONS)
seq_puts(m, ":console");
else if (p->subtype == SYSTEM_TYPE_CONSOLE)
seq_puts(m, ":vtmaster");
break;
case TTY_DRIVER_TYPE_CONSOLE:
seq_puts(m, "console");
break;
case TTY_DRIVER_TYPE_SERIAL:
seq_puts(m, "serial");
break;
case TTY_DRIVER_TYPE_PTY:
if (p->subtype == PTY_TYPE_MASTER)
seq_puts(m, "pty:master");
else if (p->subtype == PTY_TYPE_SLAVE)
seq_puts(m, "pty:slave");
else
seq_puts(m, "pty");
break;
default:
seq_printf(m, "type:%d.%d", p->type, p->subtype);
}
seq_putc(m, '\n');
}
static int show_tty_driver(struct seq_file *m, void *v)
{
struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers);
dev_t from = MKDEV(p->major, p->minor_start);
dev_t to = from + p->num;
if (&p->tty_drivers == tty_drivers.next) {
/* pseudo-drivers first */
seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 0);
seq_puts(m, "system:/dev/tty\n");
seq_printf(m, "%-20s /dev/%-8s ", "/dev/console", "console");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 1);
seq_puts(m, "system:console\n");
#ifdef CONFIG_UNIX98_PTYS
seq_printf(m, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx");
seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 2);
seq_puts(m, "system\n");
#endif
#ifdef CONFIG_VT
seq_printf(m, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0");
seq_printf(m, "%3d %7d ", TTY_MAJOR, 0);
seq_puts(m, "system:vtmaster\n");
#endif
}
while (MAJOR(from) < MAJOR(to)) {
dev_t next = MKDEV(MAJOR(from)+1, 0);
show_tty_range(m, p, from, next - from);
from = next;
}
if (from != to)
show_tty_range(m, p, from, to - from);
return 0;
}
/* iterator */
static void *t_start(struct seq_file *m, loff_t *pos)
{
Protect tty drivers list with tty_mutex Additions and removal from tty_drivers list were just done as well as iterating on it for /proc/tty/drivers generation. testing: modprobe/rmmod loop of simple module which does nothing but tty_register_driver() vs cat /proc/tty/drivers loop BUG: unable to handle kernel paging request at virtual address 6b6b6b6b printing eip: c01cefa7 *pde = 00000000 Oops: 0000 [#1] PREEMPT last sysfs file: devices/pci0000:00/0000:00:1d.7/usb5/5-0:1.0/bInterfaceProtocol Modules linked in: ohci_hcd af_packet e1000 ehci_hcd uhci_hcd usbcore xfs CPU: 0 EIP: 0060:[<c01cefa7>] Not tainted VLI EFLAGS: 00010297 (2.6.21-rc4-mm1 #4) EIP is at vsnprintf+0x3a4/0x5fc eax: 6b6b6b6b ebx: f6cb50f2 ecx: 6b6b6b6b edx: fffffffe esi: c0354700 edi: f6cb6000 ebp: 6b6b6b6b esp: f31f5e68 ds: 007b es: 007b fs: 00d8 gs: 0033 ss: 0068 Process cat (pid: 31864, ti=f31f4000 task=c1998030 task.ti=f31f4000) Stack: 00000000 c0103f20 c013003a c0103f20 00000000 f6cb50da 0000000a 00000f0e f6cb50f2 00000010 00000014 ffffffff ffffffff 00000007 c0354753 f6cb50f2 f73e39dc f73e39dc 00000001 c0175416 f31f5ed8 f31f5ed4 0ee00000 f32090bc Call Trace: [<c0103f20>] restore_nocheck+0x12/0x15 [<c013003a>] mark_held_locks+0x6d/0x86 [<c0103f20>] restore_nocheck+0x12/0x15 [<c0175416>] seq_printf+0x2e/0x52 [<c0192895>] show_tty_range+0x35/0x1f3 [<c0175416>] seq_printf+0x2e/0x52 [<c0192add>] show_tty_driver+0x8a/0x1d9 [<c01758f6>] seq_read+0x70/0x2ba [<c0175886>] seq_read+0x0/0x2ba [<c018d8e6>] proc_reg_read+0x63/0x9f [<c015e764>] vfs_read+0x7d/0xb5 [<c018d883>] proc_reg_read+0x0/0x9f [<c015eab1>] sys_read+0x41/0x6a [<c0103e4e>] sysenter_past_esp+0x5f/0x99 ======================= Code: 00 8b 4d 04 e9 44 ff ff ff 8d 4d 04 89 4c 24 50 8b 6d 00 81 fd ff 0f 00 00 b8 a4 c1 35 c0 0f 46 e8 8b 54 24 2c 89 e9 89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 89 c6 8b 44 24 28 89 EIP: [<c01cefa7>] vsnprintf+0x3a4/0x5fc SS:ESP 0068:f31f5e68 Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-08 15:27:12 +08:00
mutex_lock(&tty_mutex);
return seq_list_start(&tty_drivers, *pos);
}
static void *t_next(struct seq_file *m, void *v, loff_t *pos)
{
return seq_list_next(v, &tty_drivers, pos);
}
static void t_stop(struct seq_file *m, void *v)
{
Protect tty drivers list with tty_mutex Additions and removal from tty_drivers list were just done as well as iterating on it for /proc/tty/drivers generation. testing: modprobe/rmmod loop of simple module which does nothing but tty_register_driver() vs cat /proc/tty/drivers loop BUG: unable to handle kernel paging request at virtual address 6b6b6b6b printing eip: c01cefa7 *pde = 00000000 Oops: 0000 [#1] PREEMPT last sysfs file: devices/pci0000:00/0000:00:1d.7/usb5/5-0:1.0/bInterfaceProtocol Modules linked in: ohci_hcd af_packet e1000 ehci_hcd uhci_hcd usbcore xfs CPU: 0 EIP: 0060:[<c01cefa7>] Not tainted VLI EFLAGS: 00010297 (2.6.21-rc4-mm1 #4) EIP is at vsnprintf+0x3a4/0x5fc eax: 6b6b6b6b ebx: f6cb50f2 ecx: 6b6b6b6b edx: fffffffe esi: c0354700 edi: f6cb6000 ebp: 6b6b6b6b esp: f31f5e68 ds: 007b es: 007b fs: 00d8 gs: 0033 ss: 0068 Process cat (pid: 31864, ti=f31f4000 task=c1998030 task.ti=f31f4000) Stack: 00000000 c0103f20 c013003a c0103f20 00000000 f6cb50da 0000000a 00000f0e f6cb50f2 00000010 00000014 ffffffff ffffffff 00000007 c0354753 f6cb50f2 f73e39dc f73e39dc 00000001 c0175416 f31f5ed8 f31f5ed4 0ee00000 f32090bc Call Trace: [<c0103f20>] restore_nocheck+0x12/0x15 [<c013003a>] mark_held_locks+0x6d/0x86 [<c0103f20>] restore_nocheck+0x12/0x15 [<c0175416>] seq_printf+0x2e/0x52 [<c0192895>] show_tty_range+0x35/0x1f3 [<c0175416>] seq_printf+0x2e/0x52 [<c0192add>] show_tty_driver+0x8a/0x1d9 [<c01758f6>] seq_read+0x70/0x2ba [<c0175886>] seq_read+0x0/0x2ba [<c018d8e6>] proc_reg_read+0x63/0x9f [<c015e764>] vfs_read+0x7d/0xb5 [<c018d883>] proc_reg_read+0x0/0x9f [<c015eab1>] sys_read+0x41/0x6a [<c0103e4e>] sysenter_past_esp+0x5f/0x99 ======================= Code: 00 8b 4d 04 e9 44 ff ff ff 8d 4d 04 89 4c 24 50 8b 6d 00 81 fd ff 0f 00 00 b8 a4 c1 35 c0 0f 46 e8 8b 54 24 2c 89 e9 89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 89 c6 8b 44 24 28 89 EIP: [<c01cefa7>] vsnprintf+0x3a4/0x5fc SS:ESP 0068:f31f5e68 Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-08 15:27:12 +08:00
mutex_unlock(&tty_mutex);
}
static const struct seq_operations tty_drivers_op = {
.start = t_start,
.next = t_next,
.stop = t_stop,
.show = show_tty_driver
};
static int tty_drivers_open(struct inode *inode, struct file *file)
{
return seq_open(file, &tty_drivers_op);
}
static const struct file_operations proc_tty_drivers_operations = {
.open = tty_drivers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
/*
* This function is called by tty_register_driver() to handle
* registering the driver's /proc handler into /proc/tty/driver/<foo>
*/
void proc_tty_register_driver(struct tty_driver *driver)
{
struct proc_dir_entry *ent;
if (!driver->driver_name || driver->proc_entry ||
!driver->ops->proc_fops)
return;
ent = proc_create_data(driver->driver_name, 0, proc_tty_driver,
driver->ops->proc_fops, driver);
driver->proc_entry = ent;
}
/*
* This function is called by tty_unregister_driver()
*/
void proc_tty_unregister_driver(struct tty_driver *driver)
{
struct proc_dir_entry *ent;
ent = driver->proc_entry;
if (!ent)
return;
tty fix oops when rmmod 8250 After rmmod 8250.ko tty_kref_put starts kwork (release_one_tty) to release proc interface oops when accessing driver->driver_name in proc_tty_unregister_driver Use jprobe, found driver->driver_name point to 8250.ko static static struct uart_driver serial8250_reg .driver_name= serial, Use name in proc_dir_entry instead of driver->driver_name to fix oops test on linux 4.1.12: BUG: unable to handle kernel paging request at ffffffffa01979de IP: [<ffffffff81310f40>] strchr+0x0/0x30 PGD 1a0d067 PUD 1a0e063 PMD 851c1f067 PTE 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ... ... [last unloaded: 8250] CPU: 7 PID: 116 Comm: kworker/7:1 Tainted: G O 4.1.12 #1 Hardware name: Insyde RiverForest/Type2 - Board Product Name1, BIOS NE5KV904 12/21/2015 Workqueue: events release_one_tty task: ffff88085b684960 ti: ffff880852884000 task.ti: ffff880852884000 RIP: 0010:[<ffffffff81310f40>] [<ffffffff81310f40>] strchr+0x0/0x30 RSP: 0018:ffff880852887c90 EFLAGS: 00010282 RAX: ffffffff81a5eca0 RBX: ffffffffa01979de RCX: 0000000000000004 RDX: ffff880852887d10 RSI: 000000000000002f RDI: ffffffffa01979de RBP: ffff880852887cd8 R08: 0000000000000000 R09: ffff88085f5d94d0 R10: 0000000000000195 R11: 0000000000000000 R12: ffffffffa01979de R13: ffff880852887d00 R14: ffffffffa01979de R15: ffff88085f02e840 FS: 0000000000000000(0000) GS:ffff88085f5c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffa01979de CR3: 0000000001a0c000 CR4: 00000000001406e0 Stack: ffffffff812349b1 ffff880852887cb8 ffff880852887d10 ffff88085f5cd6c2 ffff880852800a80 ffffffffa01979de ffff880852800a84 0000000000000010 ffff88085bb28bd8 ffff880852887d38 ffffffff812354f0 ffff880852887d08 Call Trace: [<ffffffff812349b1>] ? __xlate_proc_name+0x71/0xd0 [<ffffffff812354f0>] remove_proc_entry+0x40/0x180 [<ffffffff815f6811>] ? _raw_spin_lock_irqsave+0x41/0x60 [<ffffffff813be520>] ? destruct_tty_driver+0x60/0xe0 [<ffffffff81237c68>] proc_tty_unregister_driver+0x28/0x40 [<ffffffff813be548>] destruct_tty_driver+0x88/0xe0 [<ffffffff813be5bd>] tty_driver_kref_put+0x1d/0x20 [<ffffffff813becca>] release_one_tty+0x5a/0xd0 [<ffffffff81074159>] process_one_work+0x139/0x420 [<ffffffff810745a1>] worker_thread+0x121/0x450 [<ffffffff81074480>] ? process_scheduled_works+0x40/0x40 [<ffffffff8107a16c>] kthread+0xec/0x110 [<ffffffff81080000>] ? tg_rt_schedulable+0x210/0x220 [<ffffffff8107a080>] ? kthread_freezable_should_stop+0x80/0x80 [<ffffffff815f7292>] ret_from_fork+0x42/0x70 [<ffffffff8107a080>] ? kthread_freezable_should_stop+0x80/0x80 Signed-off-by: nixiaoming <nixiaoming@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-09-15 17:45:56 +08:00
remove_proc_entry(ent->name, proc_tty_driver);
driver->proc_entry = NULL;
}
/*
* Called by proc_root_init() to initialize the /proc/tty subtree
*/
void __init proc_tty_init(void)
{
if (!proc_mkdir("tty", NULL))
return;
proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */
/*
* /proc/tty/driver/serial reveals the exact character counts for
* serial links which is just too easy to abuse for inferring
* password lengths and inter-keystroke timings during password
* entry.
*/
proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
}