Skip to content

Commit

Permalink
tty/vt: handle bad user buffer in {G,P}IO_CMAP ioctl
Browse files Browse the repository at this point in the history
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 <mg@ebfe.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Michael Gehring authored and Greg Kroah-Hartman committed Apr 9, 2012
1 parent ef4f9d4 commit 871bdea
Showing 1 changed file with 32 additions and 36 deletions.
68 changes: 32 additions & 36 deletions drivers/tty/vt/vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -3893,61 +3893,57 @@ 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.
*/

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)
Expand Down

0 comments on commit 871bdea

Please sign in to comment.