diff options
author | Antonino A. Daplas <adaplas@gmail.com> | 2007-10-16 04:29:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:20 -0400 |
commit | e400b6ec4ede4dc0aa8e5640425df5b29796fe0e (patch) | |
tree | 8fbca730c850fd85fbf0f2d70daef7765ed4cb7f /drivers | |
parent | 0058f479e52d0c0718c843cb34223bc1bfce36e1 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/vt.c | 13 | ||||
-rw-r--r-- | drivers/char/vt_ioctl.c | 15 | ||||
-rw-r--r-- | drivers/usb/misc/sisusbvga/sisusb_con.c | 3 | ||||
-rw-r--r-- | drivers/video/console/fbcon.c | 2 | ||||
-rw-r--r-- | drivers/video/console/vgacon.c | 7 |
5 files changed, 29 insertions, 11 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 | ||
753 | static inline int resize_screen(struct vc_data *vc, int width, int height) | 753 | static 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 */ |
1044 | static int | 1044 | static int |
1045 | sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows) | 1045 | sisusbcon_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 | ||
2170 | static int fbcon_resize(struct vc_data *vc, unsigned int width, | 2170 | static 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 | ||
1280 | static int vgacon_resize(struct vc_data *c, unsigned int width, | 1280 | static 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); |