| From a1ad1cc9704f64c169261a76e1aee1cf1ae51832 Mon Sep 17 00:00:00 2001 |
| From: Grzegorz Halat <ghalat@redhat.com> |
| Date: Fri, 26 Apr 2019 16:59:46 +0200 |
| Subject: vt/fbcon: deinitialize resources in visual_init() after failed memory allocation |
| |
| From: Grzegorz Halat <ghalat@redhat.com> |
| |
| commit a1ad1cc9704f64c169261a76e1aee1cf1ae51832 upstream. |
| |
| After memory allocation failure vc_allocate() doesn't clean up data |
| which has been initialized in visual_init(). In case of fbcon this |
| leads to divide-by-0 in fbcon_init() on next open of the same tty. |
| |
| memory allocation in vc_allocate() may fail here: |
| 1097: vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL); |
| |
| on next open() fbcon_init() skips vc_font.data initialization: |
| 1088: if (!p->fontdata) { |
| |
| division by zero in fbcon_init() happens here: |
| 1149: new_cols /= vc->vc_font.width; |
| |
| Additional check is needed in fbcon_deinit() to prevent |
| usage of uninitialized vc_screenbuf: |
| |
| 1251: if (vc->vc_hi_font_mask && vc->vc_screenbuf) |
| 1252: set_vc_hi_font(vc, false); |
| |
| Crash: |
| |
| #6 [ffffc90001eafa60] divide_error at ffffffff81a00be4 |
| [exception RIP: fbcon_init+463] |
| RIP: ffffffff814b860f RSP: ffffc90001eafb18 RFLAGS: 00010246 |
| ... |
| #7 [ffffc90001eafb60] visual_init at ffffffff8154c36e |
| #8 [ffffc90001eafb80] vc_allocate at ffffffff8154f53c |
| #9 [ffffc90001eafbc8] con_install at ffffffff8154f624 |
| ... |
| |
| Signed-off-by: Grzegorz Halat <ghalat@redhat.com> |
| Reviewed-by: Oleksandr Natalenko <oleksandr@redhat.com> |
| Acked-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/tty/vt/vt.c | 11 +++++++++-- |
| drivers/video/fbdev/core/fbcon.c | 2 +- |
| 2 files changed, 10 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/tty/vt/vt.c |
| +++ b/drivers/tty/vt/vt.c |
| @@ -1059,6 +1059,13 @@ static void visual_init(struct vc_data * |
| vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row; |
| } |
| |
| + |
| +static void visual_deinit(struct vc_data *vc) |
| +{ |
| + vc->vc_sw->con_deinit(vc); |
| + module_put(vc->vc_sw->owner); |
| +} |
| + |
| int vc_allocate(unsigned int currcons) /* return 0 on success */ |
| { |
| struct vt_notifier_param param; |
| @@ -1106,6 +1113,7 @@ int vc_allocate(unsigned int currcons) / |
| |
| return 0; |
| err_free: |
| + visual_deinit(vc); |
| kfree(vc); |
| vc_cons[currcons].d = NULL; |
| return -ENOMEM; |
| @@ -1334,9 +1342,8 @@ struct vc_data *vc_deallocate(unsigned i |
| param.vc = vc = vc_cons[currcons].d; |
| atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); |
| vcs_remove_sysfs(currcons); |
| - vc->vc_sw->con_deinit(vc); |
| + visual_deinit(vc); |
| put_pid(vc->vt_pid); |
| - module_put(vc->vc_sw->owner); |
| vc_uniscr_set(vc, NULL); |
| kfree(vc->vc_screenbuf); |
| vc_cons[currcons].d = NULL; |
| --- a/drivers/video/fbdev/core/fbcon.c |
| +++ b/drivers/video/fbdev/core/fbcon.c |
| @@ -1237,7 +1237,7 @@ finished: |
| if (free_font) |
| vc->vc_font.data = NULL; |
| |
| - if (vc->vc_hi_font_mask) |
| + if (vc->vc_hi_font_mask && vc->vc_screenbuf) |
| set_vc_hi_font(vc, false); |
| |
| if (!con_is_bound(&fb_con)) |