aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2006-09-29 05:00:03 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-29 12:18:12 -0400
commitca9bda00b4aafc42cd3d1b9d32934463e2993b4c (patch)
treedbb7ba5320bb8d1cbf97b3493687cb87932ad5f4
parentae78bf9c4f5fde3c67e2829505f195d7347ce3e4 (diff)
[PATCH] tty locking on resize
The current kernel serializes console resizes but does not serialize the resize against the tty structure updates. This means that while two parallel resizes cannot mess up the console you can get incorrect results reported. Secondly while doing this I added vc_lock_resize() to lock and resize the console. This leaves all knowledge of the console_sem in the vt/console driver and kicks it out of the tty layer, which is good Thirdly while doing this I decided I couldn't stand "disallocate" any longer so I switched it to "deallocate". Signed-off-by: Alan Cox <alan@redhat.com> Cc: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/char/selection.c2
-rw-r--r--drivers/char/tty_io.c29
-rw-r--r--drivers/char/vt.c12
-rw-r--r--drivers/char/vt_ioctl.c17
-rw-r--r--include/linux/vt_kern.h3
5 files changed, 36 insertions, 27 deletions
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 71093a9fc462..74cff839c857 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -33,7 +33,7 @@ extern void poke_blanked_console(void);
33 33
34/* Variables for selection control. */ 34/* Variables for selection control. */
35/* Use a dynamic buffer, instead of static (Dec 1994) */ 35/* Use a dynamic buffer, instead of static (Dec 1994) */
36struct vc_data *sel_cons; /* must not be disallocated */ 36struct vc_data *sel_cons; /* must not be deallocated */
37static volatile int sel_start = -1; /* cleared by clear_selection */ 37static volatile int sel_start = -1; /* cleared by clear_selection */
38static int sel_end; 38static int sel_end;
39static int sel_buffer_lth; 39static int sel_buffer_lth;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index eb881cfa53e0..2a1e95b0f282 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2770,12 +2770,11 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
2770 * actually has driver level meaning and triggers a VC resize. 2770 * actually has driver level meaning and triggers a VC resize.
2771 * 2771 *
2772 * Locking: 2772 * Locking:
2773 * The console_sem is used to ensure we do not try and resize 2773 * Called function use the console_sem is used to ensure we do
2774 * the console twice at once. 2774 * not try and resize the console twice at once.
2775 * FIXME: Two racing size sets may leave the console and kernel 2775 * The tty->termios_sem is used to ensure we don't double
2776 * parameters disagreeing. Is this exploitable ? 2776 * resize and get confused. Lock order - tty->termios.sem before
2777 * FIXME: Random values racing a window size get is wrong 2777 * console sem
2778 * should lock here against that
2779 */ 2778 */
2780 2779
2781static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, 2780static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
@@ -2785,17 +2784,17 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
2785 2784
2786 if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) 2785 if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
2787 return -EFAULT; 2786 return -EFAULT;
2787
2788 down(&tty->termios_sem);
2788 if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) 2789 if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
2789 return 0; 2790 goto done;
2791
2790#ifdef CONFIG_VT 2792#ifdef CONFIG_VT
2791 if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { 2793 if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
2792 int rc; 2794 if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row)) {
2793 2795 up(&tty->termios_sem);
2794 acquire_console_sem(); 2796 return -ENXIO;
2795 rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row); 2797 }
2796 release_console_sem();
2797 if (rc)
2798 return -ENXIO;
2799 } 2798 }
2800#endif 2799#endif
2801 if (tty->pgrp > 0) 2800 if (tty->pgrp > 0)
@@ -2804,6 +2803,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
2804 kill_pg(real_tty->pgrp, SIGWINCH, 1); 2803 kill_pg(real_tty->pgrp, SIGWINCH, 1);
2805 tty->winsize = tmp_ws; 2804 tty->winsize = tmp_ws;
2806 real_tty->winsize = tmp_ws; 2805 real_tty->winsize = tmp_ws;
2806done:
2807 up(&tty->termios_sem);
2807 return 0; 2808 return 0;
2808} 2809}
2809 2810
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 0fca83ededff..b49f03375439 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -885,8 +885,17 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
885 return err; 885 return err;
886} 886}
887 887
888int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
889{
890 int rc;
891
892 acquire_console_sem();
893 rc = vc_resize(vc, cols, lines);
894 release_console_sem();
895 return rc;
896}
888 897
889void vc_disallocate(unsigned int currcons) 898void vc_deallocate(unsigned int currcons)
890{ 899{
891 WARN_CONSOLE_UNLOCKED(); 900 WARN_CONSOLE_UNLOCKED();
892 901
@@ -3790,6 +3799,7 @@ EXPORT_SYMBOL(default_blu);
3790EXPORT_SYMBOL(update_region); 3799EXPORT_SYMBOL(update_region);
3791EXPORT_SYMBOL(redraw_screen); 3800EXPORT_SYMBOL(redraw_screen);
3792EXPORT_SYMBOL(vc_resize); 3801EXPORT_SYMBOL(vc_resize);
3802EXPORT_SYMBOL(vc_lock_resize);
3793EXPORT_SYMBOL(fg_console); 3803EXPORT_SYMBOL(fg_console);
3794EXPORT_SYMBOL(console_blank_hook); 3804EXPORT_SYMBOL(console_blank_hook);
3795EXPORT_SYMBOL(console_blanked); 3805EXPORT_SYMBOL(console_blanked);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index a5628a8b6620..a53e382cc107 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -96,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str
96 if (!perm) 96 if (!perm)
97 return -EPERM; 97 return -EPERM;
98 if (!i && v == K_NOSUCHMAP) { 98 if (!i && v == K_NOSUCHMAP) {
99 /* disallocate map */ 99 /* deallocate map */
100 key_map = key_maps[s]; 100 key_map = key_maps[s];
101 if (s && key_map) { 101 if (s && key_map) {
102 key_maps[s] = NULL; 102 key_maps[s] = NULL;
@@ -819,20 +819,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
819 if (arg > MAX_NR_CONSOLES) 819 if (arg > MAX_NR_CONSOLES)
820 return -ENXIO; 820 return -ENXIO;
821 if (arg == 0) { 821 if (arg == 0) {
822 /* disallocate all unused consoles, but leave 0 */ 822 /* deallocate all unused consoles, but leave 0 */
823 acquire_console_sem(); 823 acquire_console_sem();
824 for (i=1; i<MAX_NR_CONSOLES; i++) 824 for (i=1; i<MAX_NR_CONSOLES; i++)
825 if (! VT_BUSY(i)) 825 if (! VT_BUSY(i))
826 vc_disallocate(i); 826 vc_deallocate(i);
827 release_console_sem(); 827 release_console_sem();
828 } else { 828 } else {
829 /* disallocate a single console, if possible */ 829 /* deallocate a single console, if possible */
830 arg--; 830 arg--;
831 if (VT_BUSY(arg)) 831 if (VT_BUSY(arg))
832 return -EBUSY; 832 return -EBUSY;
833 if (arg) { /* leave 0 */ 833 if (arg) { /* leave 0 */
834 acquire_console_sem(); 834 acquire_console_sem();
835 vc_disallocate(arg); 835 vc_deallocate(arg);
836 release_console_sem(); 836 release_console_sem();
837 } 837 }
838 } 838 }
@@ -847,11 +847,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
847 if (get_user(ll, &vtsizes->v_rows) || 847 if (get_user(ll, &vtsizes->v_rows) ||
848 get_user(cc, &vtsizes->v_cols)) 848 get_user(cc, &vtsizes->v_cols))
849 return -EFAULT; 849 return -EFAULT;
850 for (i = 0; i < MAX_NR_CONSOLES; i++) { 850 for (i = 0; i < MAX_NR_CONSOLES; i++)
851 acquire_console_sem(); 851 vc_lock_resize(vc_cons[i].d, cc, ll);
852 vc_resize(vc_cons[i].d, cc, ll);
853 release_console_sem();
854 }
855 return 0; 852 return 0;
856 } 853 }
857 854
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 918a29763aea..1009d3fe1fc2 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -33,7 +33,8 @@ extern int fg_console, last_console, want_console;
33int vc_allocate(unsigned int console); 33int vc_allocate(unsigned int console);
34int vc_cons_allocated(unsigned int console); 34int vc_cons_allocated(unsigned int console);
35int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); 35int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
36void vc_disallocate(unsigned int console); 36int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
37void vc_deallocate(unsigned int console);
37void reset_palette(struct vc_data *vc); 38void reset_palette(struct vc_data *vc);
38void do_blank_screen(int entering_gfx); 39void do_blank_screen(int entering_gfx);
39void do_unblank_screen(int leaving_gfx); 40void do_unblank_screen(int leaving_gfx);