103 lines
4.0 KiB
Diff
103 lines
4.0 KiB
Diff
From 4aed4d2a911e165342a339c886101dbe3acad5e2 Mon Sep 17 00:00:00 2001
|
|
From: Murad Masimov <m.masimov@mt-integration.ru>
|
|
Date: Mon, 28 Apr 2025 18:34:06 +0300
|
|
Subject: fbdev: Fix do_register_framebuffer to prevent null-ptr-deref in
|
|
fb_videomode_to_var
|
|
|
|
If fb_add_videomode() in do_register_framebuffer() fails to allocate
|
|
memory for fb_videomode, it will later lead to a null-ptr dereference in
|
|
fb_videomode_to_var(), as the fb_info is registered while not having the
|
|
mode in modelist that is expected to be there, i.e. the one that is
|
|
described in fb_info->var.
|
|
|
|
================================================================
|
|
general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN NOPTI
|
|
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
|
|
CPU: 1 PID: 30371 Comm: syz-executor.1 Not tainted 5.10.226-syzkaller #0
|
|
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
|
|
RIP: 0010:fb_videomode_to_var+0x24/0x610 drivers/video/fbdev/core/modedb.c:901
|
|
Call Trace:
|
|
display_to_var+0x3a/0x7c0 drivers/video/fbdev/core/fbcon.c:929
|
|
fbcon_resize+0x3e2/0x8f0 drivers/video/fbdev/core/fbcon.c:2071
|
|
resize_screen drivers/tty/vt/vt.c:1176 [inline]
|
|
vc_do_resize+0x53a/0x1170 drivers/tty/vt/vt.c:1263
|
|
fbcon_modechanged+0x3ac/0x6e0 drivers/video/fbdev/core/fbcon.c:2720
|
|
fbcon_update_vcs+0x43/0x60 drivers/video/fbdev/core/fbcon.c:2776
|
|
do_fb_ioctl+0x6d2/0x740 drivers/video/fbdev/core/fbmem.c:1128
|
|
fb_ioctl+0xe7/0x150 drivers/video/fbdev/core/fbmem.c:1203
|
|
vfs_ioctl fs/ioctl.c:48 [inline]
|
|
__do_sys_ioctl fs/ioctl.c:753 [inline]
|
|
__se_sys_ioctl fs/ioctl.c:739 [inline]
|
|
__x64_sys_ioctl+0x19a/0x210 fs/ioctl.c:739
|
|
do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46
|
|
entry_SYSCALL_64_after_hwframe+0x67/0xd1
|
|
================================================================
|
|
|
|
Even though fbcon_init() checks beforehand if fb_match_mode() in
|
|
var_to_display() fails, it can not prevent the panic because fbcon_init()
|
|
does not return error code. Considering this and the comment in the code
|
|
about fb_match_mode() returning NULL - "This should not happen" - it is
|
|
better to prevent registering the fb_info if its mode was not set
|
|
successfully. Also move fb_add_videomode() closer to the beginning of
|
|
do_register_framebuffer() to avoid having to do the cleanup on fail.
|
|
|
|
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
|
|
|
|
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Murad Masimov <m.masimov@mt-integration.ru>
|
|
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
---
|
|
drivers/video/fbdev/core/fbmem.c | 18 +++++++++++-------
|
|
1 file changed, 11 insertions(+), 7 deletions(-)
|
|
|
|
--- a/drivers/video/fbdev/core/fbmem.c
|
|
+++ b/drivers/video/fbdev/core/fbmem.c
|
|
@@ -388,7 +388,7 @@ static int fb_check_foreignness(struct f
|
|
|
|
static int do_register_framebuffer(struct fb_info *fb_info)
|
|
{
|
|
- int i;
|
|
+ int i, err = 0;
|
|
struct fb_videomode mode;
|
|
|
|
if (fb_check_foreignness(fb_info))
|
|
@@ -397,10 +397,18 @@ static int do_register_framebuffer(struc
|
|
if (num_registered_fb == FB_MAX)
|
|
return -ENXIO;
|
|
|
|
- num_registered_fb++;
|
|
for (i = 0 ; i < FB_MAX; i++)
|
|
if (!registered_fb[i])
|
|
break;
|
|
+
|
|
+ if (!fb_info->modelist.prev || !fb_info->modelist.next)
|
|
+ INIT_LIST_HEAD(&fb_info->modelist);
|
|
+
|
|
+ fb_var_to_videomode(&mode, &fb_info->var);
|
|
+ err = fb_add_videomode(&mode, &fb_info->modelist);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
fb_info->node = i;
|
|
refcount_set(&fb_info->count, 1);
|
|
mutex_init(&fb_info->lock);
|
|
@@ -426,16 +434,12 @@ static int do_register_framebuffer(struc
|
|
if (bitmap_empty(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT))
|
|
bitmap_fill(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
|
|
|
|
- if (!fb_info->modelist.prev || !fb_info->modelist.next)
|
|
- INIT_LIST_HEAD(&fb_info->modelist);
|
|
-
|
|
if (fb_info->skip_vt_switch)
|
|
pm_vt_switch_required(fb_info->device, false);
|
|
else
|
|
pm_vt_switch_required(fb_info->device, true);
|
|
|
|
- fb_var_to_videomode(&mode, &fb_info->var);
|
|
- fb_add_videomode(&mode, &fb_info->modelist);
|
|
+ num_registered_fb++;
|
|
registered_fb[i] = fb_info;
|
|
|
|
#ifdef CONFIG_GUMSTIX_AM200EPD
|