aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonino A. Daplas <adaplas@gmail.com>2007-10-16 04:29:35 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-16 12:43:20 -0400
commite400b6ec4ede4dc0aa8e5640425df5b29796fe0e (patch)
tree8fbca730c850fd85fbf0f2d70daef7765ed4cb7f
parent0058f479e52d0c0718c843cb34223bc1bfce36e1 (diff)
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 <adaplas@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/vt.c13
-rw-r--r--drivers/char/vt_ioctl.c15
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c3
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/console/vgacon.c7
-rw-r--r--include/linux/console.h3
-rw-r--r--include/linux/console_struct.h1
7 files changed, 32 insertions, 12 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index edb7002a3216..0d56f8fc105c 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 */
750 return 0; 750 return 0;
751} 751}
752 752
753static inline int resize_screen(struct vc_data *vc, int width, int height) 753static inline int resize_screen(struct vc_data *vc, int width, int height,
754 int user)
754{ 755{
755 /* Resizes the resolution of the display adapater */ 756 /* Resizes the resolution of the display adapater */
756 int err = 0; 757 int err = 0;
757 758
758 if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) 759 if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
759 err = vc->vc_sw->con_resize(vc, width, height); 760 err = vc->vc_sw->con_resize(vc, width, height, user);
761
760 return err; 762 return err;
761} 763}
762 764
@@ -772,7 +774,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
772 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; 774 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
773 unsigned int old_cols, old_rows, old_row_size, old_screen_size; 775 unsigned int old_cols, old_rows, old_row_size, old_screen_size;
774 unsigned int new_cols, new_rows, new_row_size, new_screen_size; 776 unsigned int new_cols, new_rows, new_row_size, new_screen_size;
775 unsigned int end; 777 unsigned int end, user;
776 unsigned short *newscreen; 778 unsigned short *newscreen;
777 779
778 WARN_CONSOLE_UNLOCKED(); 780 WARN_CONSOLE_UNLOCKED();
@@ -780,6 +782,9 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
780 if (!vc) 782 if (!vc)
781 return -ENXIO; 783 return -ENXIO;
782 784
785 user = vc->vc_resize_user;
786 vc->vc_resize_user = 0;
787
783 if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) 788 if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
784 return -EINVAL; 789 return -EINVAL;
785 790
@@ -800,7 +805,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
800 old_row_size = vc->vc_size_row; 805 old_row_size = vc->vc_size_row;
801 old_screen_size = vc->vc_screenbuf_size; 806 old_screen_size = vc->vc_screenbuf_size;
802 807
803 err = resize_screen(vc, new_cols, new_rows); 808 err = resize_screen(vc, new_cols, new_rows, user);
804 if (err) { 809 if (err) {
805 kfree(newscreen); 810 kfree(newscreen);
806 return err; 811 return err;
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 7a61a2a9aafe..f69a8258095c 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,
847 case VT_RESIZE: 847 case VT_RESIZE:
848 { 848 {
849 struct vt_sizes __user *vtsizes = up; 849 struct vt_sizes __user *vtsizes = up;
850 struct vc_data *vc;
851
850 ushort ll,cc; 852 ushort ll,cc;
851 if (!perm) 853 if (!perm)
852 return -EPERM; 854 return -EPERM;
853 if (get_user(ll, &vtsizes->v_rows) || 855 if (get_user(ll, &vtsizes->v_rows) ||
854 get_user(cc, &vtsizes->v_cols)) 856 get_user(cc, &vtsizes->v_cols))
855 return -EFAULT; 857 return -EFAULT;
856 for (i = 0; i < MAX_NR_CONSOLES; i++) 858
857 vc_lock_resize(vc_cons[i].d, cc, ll); 859 for (i = 0; i < MAX_NR_CONSOLES; i++) {
860 vc = vc_cons[i].d;
861
862 if (vc) {
863 vc->vc_resize_user = 1;
864 vc_lock_resize(vc_cons[i].d, cc, ll);
865 }
866 }
867
858 return 0; 868 return 0;
859 } 869 }
860 870
@@ -900,6 +910,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
900 vc_cons[i].d->vc_scan_lines = vlin; 910 vc_cons[i].d->vc_scan_lines = vlin;
901 if (clin) 911 if (clin)
902 vc_cons[i].d->vc_font.height = clin; 912 vc_cons[i].d->vc_font.height = clin;
913 vc_cons[i].d->vc_resize_user = 1;
903 vc_resize(vc_cons[i].d, cc, ll); 914 vc_resize(vc_cons[i].d, cc, ll);
904 release_console_sem(); 915 release_console_sem();
905 } 916 }
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 43722e5a49d1..b624320df903 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)
1042 1042
1043/* Interface routine */ 1043/* Interface routine */
1044static int 1044static int
1045sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows) 1045sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
1046 unsigned int user)
1046{ 1047{
1047 struct sisusb_usb_data *sisusb; 1048 struct sisusb_usb_data *sisusb;
1048 int fh; 1049 int fh;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6d0dcde66eb4..97a0224a0cf0 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2168,7 +2168,7 @@ static __inline__ void updatescrollmode(struct display *p,
2168} 2168}
2169 2169
2170static int fbcon_resize(struct vc_data *vc, unsigned int width, 2170static int fbcon_resize(struct vc_data *vc, unsigned int width,
2171 unsigned int height) 2171 unsigned int height, unsigned int user)
2172{ 2172{
2173 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; 2173 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
2174 struct fbcon_ops *ops = info->fbcon_par; 2174 struct fbcon_ops *ops = info->fbcon_par;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index d18b73aafa0d..e9afb7ebd566 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)
1278#endif 1278#endif
1279 1279
1280static int vgacon_resize(struct vc_data *c, unsigned int width, 1280static int vgacon_resize(struct vc_data *c, unsigned int width,
1281 unsigned int height) 1281 unsigned int height, unsigned int user)
1282{ 1282{
1283 if (width % 2 || width > ORIG_VIDEO_COLS || 1283 if (width % 2 || width > ORIG_VIDEO_COLS ||
1284 height > (ORIG_VIDEO_LINES * vga_default_font_height)/ 1284 height > (ORIG_VIDEO_LINES * vga_default_font_height)/
1285 c->vc_font.height) 1285 c->vc_font.height)
1286 /* let svgatextmode tinker with video timings */ 1286 /* let svgatextmode tinker with video timings and
1287 return 0; 1287 return success */
1288 return (user) ? 0 : -EINVAL;
1288 1289
1289 if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ 1290 if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */
1290 vgacon_doresize(c, width, height); 1291 vgacon_doresize(c, width, height);
diff --git a/include/linux/console.h b/include/linux/console.h
index 56a7bcda49cb..0a4542ddb73d 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -45,7 +45,8 @@ struct consw {
45 int (*con_font_get)(struct vc_data *, struct console_font *); 45 int (*con_font_get)(struct vc_data *, struct console_font *);
46 int (*con_font_default)(struct vc_data *, struct console_font *, char *); 46 int (*con_font_default)(struct vc_data *, struct console_font *, char *);
47 int (*con_font_copy)(struct vc_data *, int); 47 int (*con_font_copy)(struct vc_data *, int);
48 int (*con_resize)(struct vc_data *, unsigned int, unsigned int); 48 int (*con_resize)(struct vc_data *, unsigned int, unsigned int,
49 unsigned int);
49 int (*con_set_palette)(struct vc_data *, unsigned char *); 50 int (*con_set_palette)(struct vc_data *, unsigned char *);
50 int (*con_scrolldelta)(struct vc_data *, int); 51 int (*con_scrolldelta)(struct vc_data *, int);
51 int (*con_set_origin)(struct vc_data *); 52 int (*con_set_origin)(struct vc_data *);
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index dc77fed7b285..d71f7c0f931b 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -100,6 +100,7 @@ struct vc_data {
100 unsigned char vc_G1_charset; 100 unsigned char vc_G1_charset;
101 unsigned char vc_saved_G0; 101 unsigned char vc_saved_G0;
102 unsigned char vc_saved_G1; 102 unsigned char vc_saved_G1;
103 unsigned int vc_resize_user; /* resize request from user */
103 unsigned int vc_bell_pitch; /* Console bell pitch */ 104 unsigned int vc_bell_pitch; /* Console bell pitch */
104 unsigned int vc_bell_duration; /* Console bell duration */ 105 unsigned int vc_bell_duration; /* Console bell duration */
105 struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ 106 struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */