Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e400b6ec4ede4dc0aa8e5640425df5b29796fe0e
Commit:     e400b6ec4ede4dc0aa8e5640425df5b29796fe0e
Parent:     0058f479e52d0c0718c843cb34223bc1bfce36e1
Author:     Antonino A. Daplas <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 16 01:29:35 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue Oct 16 09:43:20 2007 -0700

    vt/vgacon: Check if screen resize request comes from userspace
    
    Various console drivers are able to resize the screen via the con_resize()
    hook.  This hook is also visible in userspace via the TIOCWINSZ, VT_RESIZE 
and
    VT_RESIZEX ioctl's.  One particular utility, SVGATextMode, expects that
    con_resize() of the VGA console will always return success even if the
    resulting screen is not compatible with the hardware.  However, this
    particular behavior of the VGA console, as reported in Kernel Bugzilla Bug
    7513, can cause undefined behavior if the user starts with a console size
    larger than 80x25.
    
    To work around this problem, add an extra parameter to con_resize().  This
    parameter is ignored by drivers except for vgacon.  If this parameter is
    non-zero, then the resize request came from a VT_RESIZE or VT_RESIZEX ioctl
    and vgacon will always return success.  If this parameter is zero, vgacon 
will
    return -EINVAL if the requested size is not compatible with the hardware.  
The
    latter is the more correct behavior.
    
    With this change, SVGATextMode should still work correctly while in-kernel 
and
    stty resize calls can expect correct behavior from vgacon.
    
    Signed-off-by: Antonino Daplas <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 drivers/char/vt.c                       |   13 +++++++++----
 drivers/char/vt_ioctl.c                 |   15 +++++++++++++--
 drivers/usb/misc/sisusbvga/sisusb_con.c |    3 ++-
 drivers/video/console/fbcon.c           |    2 +-
 drivers/video/console/vgacon.c          |    7 ++++---
 include/linux/console.h                 |    3 ++-
 include/linux/console_struct.h          |    1 +
 7 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index edb7002..0d56f8f 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -750,13 +750,15 @@ int vc_allocate(unsigned int currcons)    /* return 0 on 
success */
        return 0;
 }
 
-static inline int resize_screen(struct vc_data *vc, int width, int height)
+static inline int resize_screen(struct vc_data *vc, int width, int height,
+                               int user)
 {
        /* Resizes the resolution of the display adapater */
        int err = 0;
 
        if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
-               err = vc->vc_sw->con_resize(vc, width, height);
+               err = vc->vc_sw->con_resize(vc, width, height, user);
+
        return err;
 }
 
@@ -772,7 +774,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, 
unsigned int lines)
        unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
        unsigned int old_cols, old_rows, old_row_size, old_screen_size;
        unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-       unsigned int end;
+       unsigned int end, user;
        unsigned short *newscreen;
 
        WARN_CONSOLE_UNLOCKED();
@@ -780,6 +782,9 @@ int vc_resize(struct vc_data *vc, unsigned int cols, 
unsigned int lines)
        if (!vc)
                return -ENXIO;
 
+       user = vc->vc_resize_user;
+       vc->vc_resize_user = 0;
+
        if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
                return -EINVAL;
 
@@ -800,7 +805,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, 
unsigned int lines)
        old_row_size = vc->vc_size_row;
        old_screen_size = vc->vc_screenbuf_size;
 
-       err = resize_screen(vc, new_cols, new_rows);
+       err = resize_screen(vc, new_cols, new_rows, user);
        if (err) {
                kfree(newscreen);
                return err;
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 7a61a2a..f69a825 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -847,14 +847,24 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
        case VT_RESIZE:
        {
                struct vt_sizes __user *vtsizes = up;
+               struct vc_data *vc;
+
                ushort ll,cc;
                if (!perm)
                        return -EPERM;
                if (get_user(ll, &vtsizes->v_rows) ||
                    get_user(cc, &vtsizes->v_cols))
                        return -EFAULT;
-               for (i = 0; i < MAX_NR_CONSOLES; i++)
-                       vc_lock_resize(vc_cons[i].d, cc, ll);
+
+               for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                       vc = vc_cons[i].d;
+
+                       if (vc) {
+                               vc->vc_resize_user = 1;
+                               vc_lock_resize(vc_cons[i].d, cc, ll);
+                       }
+               }
+
                return 0;
        }
 
@@ -900,6 +910,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                vc_cons[i].d->vc_scan_lines = vlin;
                        if (clin)
                                vc_cons[i].d->vc_font.height = clin;
+                       vc_cons[i].d->vc_resize_user = 1;
                        vc_resize(vc_cons[i].d, cc, ll);
                        release_console_sem();
                }
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c 
b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 43722e5..b624320 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -1042,7 +1042,8 @@ sisusbcon_set_origin(struct vc_data *c)
 
 /* Interface routine */
 static int
-sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows)
+sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
+                unsigned int user)
 {
        struct sisusb_usb_data *sisusb;
        int fh;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6d0dcde..97a0224 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2168,7 +2168,7 @@ static __inline__ void updatescrollmode(struct display *p,
 }
 
 static int fbcon_resize(struct vc_data *vc, unsigned int width, 
-                       unsigned int height)
+                       unsigned int height, unsigned int user)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
        struct fbcon_ops *ops = info->fbcon_par;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index d18b73a..e9afb7e 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1278,13 +1278,14 @@ static int vgacon_font_get(struct vc_data *c, struct 
console_font *font)
 #endif
 
 static int vgacon_resize(struct vc_data *c, unsigned int width,
-                               unsigned int height)
+                        unsigned int height, unsigned int user)
 {
        if (width % 2 || width > ORIG_VIDEO_COLS ||
            height > (ORIG_VIDEO_LINES * vga_default_font_height)/
            c->vc_font.height)
-               /* let svgatextmode tinker with video timings */
-               return 0;
+               /* let svgatextmode tinker with video timings and
+                  return success */
+               return (user) ? 0 : -EINVAL;
 
        if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */
                vgacon_doresize(c, width, height);
diff --git a/include/linux/console.h b/include/linux/console.h
index 56a7bcd..0a4542d 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -45,7 +45,8 @@ struct consw {
        int     (*con_font_get)(struct vc_data *, struct console_font *);
        int     (*con_font_default)(struct vc_data *, struct console_font *, 
char *);
        int     (*con_font_copy)(struct vc_data *, int);
-       int     (*con_resize)(struct vc_data *, unsigned int, unsigned int);
+       int     (*con_resize)(struct vc_data *, unsigned int, unsigned int,
+                              unsigned int);
        int     (*con_set_palette)(struct vc_data *, unsigned char *);
        int     (*con_scrolldelta)(struct vc_data *, int);
        int     (*con_set_origin)(struct vc_data *);
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index dc77fed..d71f7c0 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -100,6 +100,7 @@ struct vc_data {
        unsigned char   vc_G1_charset;
        unsigned char   vc_saved_G0;
        unsigned char   vc_saved_G1;
+       unsigned int    vc_resize_user;         /* resize request from user */
        unsigned int    vc_bell_pitch;          /* Console bell pitch */
        unsigned int    vc_bell_duration;       /* Console bell duration */
        struct vc_data **vc_display_fg;         /* [!] Ptr to var holding fg 
console for this display */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to