From 7b083b32924cf32e88fc524d29fd787a606b0fb9 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Thu, 29 Jul 2004 08:47:55 -0700 Subject: [PATCH] [PATCH] con_set_font sanitized con_font_set() sanitized. We are passing console_font and flags into the method in separate arguments and we are not messing with console_font_op->data anymore - it's a userland pointer (to be annotated several patches later in the series, due to another abuse of console_font_op that needs to be fixed first), while console_font->data is kernel one and they don't mix anymore. We also do a sanity check (font width > 0) in the caller instead of method instances, since we are already checking for width <= 32 and height <= 32 there; doesn't make sense leaving that one in method instances. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- drivers/char/vt.c | 26 +++++++++--------- drivers/video/console/fbcon.c | 42 ++++++++++++++++++----------- drivers/video/console/newport_con.c | 6 ++--- drivers/video/console/vgacon.c | 11 ++++---- include/linux/console.h | 2 +- 5 files changed, 48 insertions(+), 39 deletions(-) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7f3d93ba1e7a3..90395eed34a96 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -3081,14 +3081,12 @@ out: int con_font_set(int currcons, struct console_font_op *op) { - struct console_font_op old_op; + struct console_font font; int rc = -EINVAL; int size; - u8 *temp; if (vt_cons[currcons]->vc_mode != KD_TEXT) return -EINVAL; - memcpy(&old_op, op, sizeof(old_op)); if (!op->data) return -EINVAL; if (op->charcount > 512) @@ -3113,28 +3111,28 @@ int con_font_set(int currcons, struct console_font_op *op) nonzero: op->height = h; } - if (op->width > 32 || op->height > 32) + if (op->width <= 0 || op->width > 32 || op->height > 32) return -EINVAL; size = (op->width+7)/8 * 32 * op->charcount; if (size > max_font_size) return -ENOSPC; - temp = kmalloc(size, GFP_KERNEL); - if (!temp) + font.charcount = op->charcount; + font.height = op->height; + font.width = op->width; + font.data = kmalloc(size, GFP_KERNEL); + if (!font.data) return -ENOMEM; - if (copy_from_user(temp, op->data, size)) { - rc = -EFAULT; - goto out; + if (copy_from_user(font.data, op->data, size)) { + kfree(font.data); + return -EFAULT; } - op->data = temp; acquire_console_sem(); if (sw->con_font_set) - rc = sw->con_font_set(vc_cons[currcons].d, op); + rc = sw->con_font_set(vc_cons[currcons].d, &font, op->flags); else rc = -ENOSYS; release_console_sem(); - op->data = old_op.data; -out: - kfree(temp); + kfree(font.data); return rc; } diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 40f3a0010300e..005c5eed4b4e6 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2180,16 +2180,25 @@ static int fbcon_copy_font(struct vc_data *vc, int con) return fbcon_do_set_font(vc, &crap, od->fontdata, od->userfont); } -static int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) +/* + * User asked to set font; we are guaranteed that + * a) width and height are in range 1..32 + * b) charcount does not exceed 512 + */ + +static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) { - int w = op->width; - int h = op->height; + unsigned charcount = font->charcount; + int w = font->width; + int h = font->height; int size = h; int i, k; - u8 *new_data, *data = op->data, *p; + u8 *new_data, *data = font->data, *p; + struct console_font_op crap = {.width = font->width, + .height = font->height, + .op = KD_FONT_OP_SET}; - if ((w <= 0) || (w > 32) - || (op->charcount != 256 && op->charcount != 512)) + if (charcount != 256 && charcount != 512) return -EINVAL; if (w > 8) { @@ -2198,32 +2207,33 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) else size *= 4; } - size *= op->charcount; + size *= charcount; + + new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER); - if (! - (new_data = - kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER))) + if (!new_data) return -ENOMEM; + new_data += FONT_EXTRA_WORDS * sizeof(int); FNTSIZE(new_data) = size; - FNTCHARCNT(new_data) = op->charcount; + FNTCHARCNT(new_data) = charcount; REFCOUNT(new_data) = 0; /* usage counter */ p = new_data; if (w <= 8) { - for (i = 0; i < op->charcount; i++) { + for (i = 0; i < charcount; i++) { memcpy(p, data, h); data += 32; p += h; } } else if (w <= 16) { h *= 2; - for (i = 0; i < op->charcount; i++) { + for (i = 0; i < charcount; i++) { memcpy(p, data, h); data += 64; p += h; } } else if (w <= 24) { - for (i = 0; i < op->charcount; i++) { + for (i = 0; i < charcount; i++) { int j; for (j = 0; j < h; j++) { memcpy(p, data, 3); @@ -2235,7 +2245,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) } } else { h *= 4; - for (i = 0; i < op->charcount; i++) { + for (i = 0; i < charcount; i++) { memcpy(p, data, h); data += 128; p += h; @@ -2265,7 +2275,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font_op *op) break; } } - return fbcon_do_set_font(vc, op, new_data, 1); + return fbcon_do_set_font(vc, &crap, new_data, 1); } static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index ad59eed1793e8..b30ae70cbafeb 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -477,7 +477,7 @@ static int newport_blank(struct vc_data *c, int blank) return 1; } -static int newport_set_font(int unit, struct console_font_op *op) +static int newport_set_font(int unit, struct console_font *op) { int w = op->width; int h = op->height; @@ -548,9 +548,9 @@ static int newport_font_default(struct vc_data *vc, struct console_font *op, cha return newport_set_def_font(vc->vc_num, op); } -static int newport_font_set(struct vc_data *vc, struct console_font_op *op) +static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags) { - return newport_set_font(vc->vc_num, op); + return newport_set_font(vc->vc_num, font); } static int newport_set_palette(struct vc_data *vc, unsigned char *table) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index c3af575de98c2..91a1d022d44ff 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -907,22 +907,23 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) return 0; } -static int vgacon_font_set(struct vc_data *c, struct console_font_op *op) +static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags) { + unsigned charcount = font->charcount; int rc; if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; - if (op->width != 8 || (op->charcount != 256 && op->charcount != 512)) + if (font->width != 8 || (charcount != 256 && charcount != 512)) return -EINVAL; - rc = vgacon_do_font_op(&state, op->data, 1, op->charcount == 512); + rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512); if (rc) return rc; - if (!(op->flags & KD_FONT_FLAG_DONT_RECALC)) - rc = vgacon_adjust_height(c, op->height); + if (!(flags & KD_FONT_FLAG_DONT_RECALC)) + rc = vgacon_adjust_height(c, font->height); return rc; } diff --git a/include/linux/console.h b/include/linux/console.h index 02da3a451213e..4db1f52f69502 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -41,7 +41,7 @@ struct consw { void (*con_bmove)(struct vc_data *, int, int, int, int, int, int); int (*con_switch)(struct vc_data *); int (*con_blank)(struct vc_data *, int, int); - int (*con_font_set)(struct vc_data *, struct console_font_op *); + int (*con_font_set)(struct vc_data *, struct console_font *, unsigned); int (*con_font_get)(struct vc_data *, struct console_font_op *); int (*con_font_default)(struct vc_data *, struct console_font *, char *); int (*con_font_copy)(struct vc_data *, int); -- 2.53.0