Bug 4812

Summary: Kernel Oops in vt_ioctl()
Product: Drivers Reporter: Petr Tesarik (kernel)
Component: Console/FramebuffersAssignee: Antonino Daplas (adaplas)
Status: CLOSED CODE_FIX    
Severity: normal    
Priority: P2    
Hardware: i386   
OS: Linux   
Kernel Version: 2.6.10 Subsystem:
Regression: --- Bisected commit-id:

Description Petr Tesarik 2005-06-28 10:26:32 UTC
Distribution: Debian Sarge (*not* a Debian-patched kernel)
Hardware Environment: K6/200MHz
Software Environment: mingetty 1.07
Problem Description:

The kernel oopses during mingetty start-up on virtual console #3.
Here is the Oops:

Oops: 0000 [#180]
PREEMPT 
Modules linked in:
CPU:    0
EIP:    0060:[vt_ioctl+30/6848]    Not tainted VLI
EFLAGS: 00010282   (2.6.10) 
EIP is at vt_ioctl+0x1e/0x1ac0
eax: 00000000   ebx: 00005401   ecx: 00000000   edx: c1198c00
esi: fffffff8   edi: c580e000   ebp: c5b21ce0   esp: c3085ec4
ds: 007b   es: 007b   ss: 0068
Process mingetty (pid: 2183, threadinfo=c3084000 task=c32bda20)
Stack: c5b20dc0 c1373660 b7f785e0 00000000 c594fde0 c5494b7c c5b20dc0 c5b20dec 
       c1373660 c32bda20 c010a86f c5b20dc0 c1373660 b7f785e0 00000000 00000000 
       b7f785e0 00000004 c3085fc4 c3085fc4 c02b397c 00000004 0000000e 0000000b 
Call Trace:
 [do_page_fault+847/1349] do_page_fault+0x34f/0x545
 [dentry_open+259/544] dentry_open+0x103/0x220
 [filp_open+70/96] filp_open+0x46/0x60
 [tty_ioctl+857/1184] tty_ioctl+0x359/0x4a0
 [sys_ioctl+146/480] sys_ioctl+0x92/0x1e0
 [syscall_call+7/11] syscall_call+0x7/0xb
Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 55 57 56 53 81 ec 94 00 00 00 8b bc
24 a8 00 00 00 8b 9c 24 b0 00 00 00 8b 87 7c 09 00 00 <8b> 30 8b 04 b5 a0 02 36
c0 89 44 24 2c 56 e8 0f 65 00 00 85 c0 

I have traced the problem down to the source code (drivers/char/vt_ioctl.c:365):

int vt_ioctl(struct tty_struct *tty, struct file * file,
             unsigned int cmd, unsigned long arg)
{
        struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
        struct vc_data *vc = vc_cons[vt->vc_num].d;
        struct console_font_op op;      /* used in multiple places here */
        struct kbd_struct * kbd;
        unsigned int console;
        unsigned char ucval;
        void __user *up = (void __user *)arg;
        int i, perm;

The vc_data variable cannot be initialized, since vt (i.e. tty->driver_data) is
NULL at that moment. :(

Writing to the console proves this diagnostics:

root@metuzalem:~# echo > /dev/tty3
vt: argh, driver_data is NULL !

Steps to reproduce:

Not easily reproducible and most likely a race condition. :(((( I have been
using this kernel for quite some time and it only happened today. The kernel is
currently running on my computer, but I'll have to shut it down eventually... :(

Although driver_data should be never NULL (AFAIK), this seems to be a known
issue. See drivers/char/vt.c:1921:

        acquire_console_sem();
        vt = tty->driver_data;
        if (vt == NULL) {
                printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
                release_console_sem();
                return 0;
        }

If driver_data *is* allowed to be NULL, the problem is still present in 2.6.12,
see drivers/char/vt_ioctl.c:

359 int vt_ioctl(struct tty_struct *tty, struct file * file,
360 	     unsigned int cmd, unsigned long arg)
361 	{
362 	    struct vc_data *vc = (struct vc_data *)tty->driver_data;
363 	    struct console_font_op op;    /* used in multiple places here */
364 	    struct kbd_struct * kbd;
365 	    unsigned int console;
366 	    unsigned char ucval;
367 	    void __user *up = (void __user *)arg;
368 	    int i, perm;
369 	    
370 	    console = vc->vc_num;

At this point, the kernel would oops.
Comment 1 Petr Tesarik 2005-06-28 10:43:33 UTC
Oh, I almost forgot, the console driver thinks something is accessing the device:

root@metuzalem:~# deallocvt 3
VT_DISALLOCATE: Device or resource busy
deallocvt: could not deallocate console 3

(No, this won't crash, since deallocvt opens /dev/tty and passes 3 as an
argument the VT_DISALLOCATE sysctl.)
Comment 2 Petr Tesarik 2005-06-28 11:20:47 UTC
OK, still digging into the problem (before I shut down the system), I have found
out that the VT_GETSTATE ioctl sets the corresponding bit in v_state, which
means that the following condition is true:

console_driver->ttys[3] && console_driver->ttys[3]->count
Comment 3 Antonino Daplas 2005-07-31 19:01:53 UTC
Bug already fixed in linus' tree. I'll close this bug.  Please reopen if there
are still problems
Comment 4 Antonino Daplas 2005-07-31 19:15:11 UTC
Oh, I see what you mean. Is it possible for tty->driver_data to be NULL?  If not,
we can add this test:

if (!tty->driver_data) return -ENOENOIOCTLCMD;
Comment 5 Antonino Daplas 2005-07-31 19:18:54 UTC
Oh, I see what you mean, so I'll reopen it again. Is it possible for
tty->driver_data to be NULL?  If not, we can add this test:

if (!tty->driver_data)
     return -ENOENOIOCTLCMD;
Comment 6 Antonino Daplas 2005-08-23 23:56:59 UTC
I believe we have a bug fix for this.  It's now in 2.6.13-rc6-mm2.