From 871bdea6f8c64517635bec352b8bec6b72a26d80 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Wed, 21 Mar 2012 01:26:45 +0100 Subject: [PATCH] tty/vt: handle bad user buffer in {G,P}IO_CMAP ioctl set_get_cmap() ignored the result of {get,put}_user(), causing ioctl(vt, {G,P}IO_CMAP, 0xdeadbeef) to silently fail. Another side effect of this: calling the PIO_CMAP ioctl with an invalid buffer would zero the default colormap and the palette for all vts (all colors set to black). Leave the default colormap intact and return -EFAULT when reading/writing to the userspace buffer fails. Signed-off-by: Michael Gehring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 68 +++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3bdd4b19dd06..5836289bd861 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3893,36 +3893,6 @@ static void set_palette(struct vc_data *vc) vc->vc_sw->con_set_palette(vc, color_table); } -static int set_get_cmap(unsigned char __user *arg, int set) -{ - int i, j, k; - - WARN_CONSOLE_UNLOCKED(); - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(vc_cons[i].d); - } - } - return 0; -} - /* * Load palette into the DAC registers. arg points to a colour * map, 3 bytes per colour, 16 colours, range from 0 to 255. @@ -3930,24 +3900,50 @@ static int set_get_cmap(unsigned char __user *arg, int set) int con_set_cmap(unsigned char __user *arg) { - int rc; + int i, j, k; + unsigned char colormap[3*16]; + + if (copy_from_user(colormap, arg, sizeof(colormap))) + return -EFAULT; console_lock(); - rc = set_get_cmap (arg,1); + for (i = k = 0; i < 16; i++) { + default_red[i] = colormap[k++]; + default_grn[i] = colormap[k++]; + default_blu[i] = colormap[k++]; + } + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons_allocated(i)) + continue; + for (j = k = 0; j < 16; j++) { + vc_cons[i].d->vc_palette[k++] = default_red[j]; + vc_cons[i].d->vc_palette[k++] = default_grn[j]; + vc_cons[i].d->vc_palette[k++] = default_blu[j]; + } + set_palette(vc_cons[i].d); + } console_unlock(); - return rc; + return 0; } int con_get_cmap(unsigned char __user *arg) { - int rc; + int i, k; + unsigned char colormap[3*16]; console_lock(); - rc = set_get_cmap (arg,0); + for (i = k = 0; i < 16; i++) { + colormap[k++] = default_red[i]; + colormap[k++] = default_grn[i]; + colormap[k++] = default_blu[i]; + } console_unlock(); - return rc; + if (copy_to_user(arg, colormap, sizeof(colormap))) + return -EFAULT; + + return 0; } void reset_palette(struct vc_data *vc)