[PATCH OLK-5.10 0/3] CVE-2024-26798

Jiri Slaby (SUSE) (1): fbcon: always restore the old font data in fbcon_do_set_font() Shigeru Yoshida (1): fbdev: fbcon: Properly revert changes when vc_resize() failed Tetsuo Handa (1): fbdev: fbcon: release buffer when fbcon_do_set_font() failed drivers/video/fbdev/core/fbcon.c | 66 +++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 22 deletions(-) -- 2.25.1

From: Shigeru Yoshida <syoshida@redhat.com> mainline inclusion from mainline-v6.0-rc3 commit a5a923038d70d2d4a86cb4e3f32625a5ee6e7e24 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9E448 CVE: CVE-2024-26798 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... ------------------------------------------------- fbcon_do_set_font() calls vc_resize() when font size is changed. However, if if vc_resize() failed, current implementation doesn't revert changes for font size, and this causes inconsistent state. syzbot reported unable to handle page fault due to this issue [1]. syzbot's repro uses fault injection which cause failure for memory allocation, so vc_resize() failed. This patch fixes this issue by properly revert changes for font related date when vc_resize() failed. Link: https://syzkaller.appspot.com/bug?id=3443d3a1fa6d964dd7310a0cb1696d165a3e07c... [1] Reported-by: syzbot+a168dbeaaa7778273c1b@syzkaller.appspotmail.com Signed-off-by: Shigeru Yoshida <syoshida@redhat.com> Signed-off-by: Helge Deller <deller@gmx.de> CC: stable@vger.kernel.org # 5.15+ Conflicts: drivers/video/fbdev/core/fbcon.c [Fix context conflicts.] Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/video/fbdev/core/fbcon.c | 59 ++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 6d58c8a5cb44..f0eacf1968d8 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -26,7 +26,7 @@ * * Hardware cursor support added by Emmanuel Marty (core@ggi-project.org) * Smart redraw scrolling, arbitrary font width support, 512char font support - * and software scrollback added by + * and software scrollback added by * Jakub Jelinek (jj@ultra.linux.cz) * * Random hacking by Martin Mares <mj@ucw.cz> @@ -125,7 +125,7 @@ static int logo_shown = FBCON_LOGO_CANSHOW; /* console mappings */ static unsigned int first_fb_vc; static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1; -static int fbcon_is_default = 1; +static int fbcon_is_default = 1; static int primary_device = -1; static int fbcon_has_console_bind; @@ -447,12 +447,12 @@ static int __init fb_console_setup(char *this_opt) strlcpy(fontname, options + 5, sizeof(fontname)); continue; } - + if (!strncmp(options, "scrollback:", 11)) { pr_warn("Ignoring scrollback size option\n"); continue; } - + if (!strncmp(options, "map:", 4)) { options += 4; if (*options) { @@ -478,7 +478,7 @@ static int __init fb_console_setup(char *this_opt) last_fb_vc = simple_strtoul(options, &options, 10) - 1; if (last_fb_vc < first_fb_vc || last_fb_vc >= MAX_NR_CONSOLES) last_fb_vc = MAX_NR_CONSOLES - 1; - fbcon_is_default = 0; + fbcon_is_default = 0; continue; } @@ -966,7 +966,7 @@ static const char *fbcon_startup(void) info = registered_fb[info_idx]; if (!info) return NULL; - + owner = info->fbops->owner; if (!try_module_get(owner)) return NULL; @@ -1429,7 +1429,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; struct fbcon_display *p = &fb_display[vc->vc_num]; - + p->yscroll += count; if (p->yscroll >= p->vrows) /* Deal with wrap */ p->yscroll -= p->vrows; @@ -1448,7 +1448,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count) struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; struct fbcon_display *p = &fb_display[vc->vc_num]; - + p->yscroll -= count; if (p->yscroll < 0) /* Deal with wrap */ p->yscroll += p->vrows; @@ -1515,7 +1515,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_display *p = &fb_display[vc->vc_num]; struct fbcon_ops *ops = info->fbcon_par; - + p->yscroll -= count; if (p->yscroll < 0) { ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, @@ -1898,7 +1898,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_display *p = &fb_display[vc->vc_num]; - + if (fbcon_is_inactive(vc, info)) return; @@ -2023,7 +2023,7 @@ static void updatescrollmode(struct fbcon_display *p, #define PITCH(w) (((w) + 7) >> 3) #define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */ -static int fbcon_resize(struct vc_data *vc, unsigned int width, +static int fbcon_resize(struct vc_data *vc, unsigned int width, unsigned int height, unsigned int user) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; @@ -2201,7 +2201,7 @@ static int fbcon_switch(struct vc_data *vc) ops->update_start(info); } - fbcon_set_palette(vc, color_table); + fbcon_set_palette(vc, color_table); fbcon_clear_margins(vc, 0); if (logo_shown == FBCON_LOGO_DRAW) { @@ -2371,7 +2371,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set) vc->vc_complement_mask >>= 1; vc->vc_s_complement_mask >>= 1; } - + /* ++Edmund: reorder the attribute bits */ if (vc->vc_can_do_color) { unsigned short *cp = @@ -2394,7 +2394,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set) vc->vc_complement_mask <<= 1; vc->vc_s_complement_mask <<= 1; } - + /* ++Edmund: reorder the attribute bits */ { unsigned short *cp = @@ -2429,7 +2429,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; struct fbcon_display *p = &fb_display[vc->vc_num]; - int resize; + int resize, ret, old_userfont, old_width, old_height, old_charcount; int cnt; char *old_data = NULL; @@ -2441,8 +2441,14 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, else cnt = 256; vc->vc_font.data = (void *)(p->fontdata = data); + old_userfont = p->userfont; if ((p->userfont = userfont)) REFCOUNT(data)++; + + old_width = vc->vc_font.width; + old_height = vc->vc_font.height; + old_charcount = vc->vc_font.charcount; + vc->vc_font.width = w; vc->vc_font.height = h; if (vc->vc_hi_font_mask && cnt == 256) @@ -2457,7 +2463,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); cols /= w; rows /= h; - vc_resize(vc, cols, rows); + ret = vc_resize(vc, cols, rows); + if (ret) + goto err_out; } else if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); @@ -2467,6 +2475,21 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, if (old_data && (--REFCOUNT(old_data) == 0)) kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); return 0; + +err_out: + p->fontdata = old_data; + vc->vc_font.data = (void *)old_data; + + if (userfont) { + p->userfont = old_userfont; + REFCOUNT(data)--; + } + + vc->vc_font.width = old_width; + vc->vc_font.height = old_height; + vc->vc_font.charcount = old_charcount; + + return ret; } static int fbcon_copy_font(struct vc_data *vc, int con) @@ -2548,7 +2571,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, /* Check if the same font is on some other console already */ for (i = first_fb_vc; i <= last_fb_vc; i++) { struct vc_data *tmp = vc_cons[i].d; - + if (fb_display[i].userfont && fb_display[i].fontdata && FNTSUM(fb_display[i].fontdata) == csum && @@ -3485,5 +3508,5 @@ void __exit fb_console_exit(void) fbcon_exit(); do_unregister_con_driver(&fb_con); console_unlock(); -} +} #endif -- 2.25.1

From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> mainline inclusion from mainline-v6.2-rc1 commit 3c3bfb8586f848317ceba5d777e11204ba3e5758 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9E448 CVE: CVE-2024-26798 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... ------------------------------------------------- syzbot is reporting memory leak at fbcon_do_set_font() [1], for commit a5a923038d70 ("fbdev: fbcon: Properly revert changes when vc_resize() failed") missed that the buffer might be newly allocated by fbcon_set_font(). Link: https://syzkaller.appspot.com/bug?extid=25bdb7b1703639abd498 [1] Reported-by: syzbot <syzbot+25bdb7b1703639abd498@syzkaller.appspotmail.com> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Tested-by: syzbot <syzbot+25bdb7b1703639abd498@syzkaller.appspotmail.com> Fixes: a5a923038d70 ("fbdev: fbcon: Properly revert changes when vc_resize() failed") CC: stable@vger.kernel.org # 5.15+ Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/video/fbdev/core/fbcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index f0eacf1968d8..8cd853ed6b55 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2482,7 +2482,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, if (userfont) { p->userfont = old_userfont; - REFCOUNT(data)--; + if (--REFCOUNT(data) == 0) + kfree(data - FONT_EXTRA_WORDS * sizeof(int)); } vc->vc_font.width = old_width; -- 2.25.1

From: "Jiri Slaby (SUSE)" <jirislaby@kernel.org> mainline inclusion from mainline-v6.8-rc7 commit 00d6a284fcf3fad1b7e1b5bc3cd87cbfb60ce03f category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9E448 CVE: CVE-2024-26798 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... ------------------------------------------------- Commit a5a923038d70 (fbdev: fbcon: Properly revert changes when vc_resize() failed) started restoring old font data upon failure (of vc_resize()). But it performs so only for user fonts. It means that the "system"/internal fonts are not restored at all. So in result, the very first call to fbcon_do_set_font() performs no restore at all upon failing vc_resize(). This can be reproduced by Syzkaller to crash the system on the next invocation of font_get(). It's rather hard to hit the allocation failure in vc_resize() on the first font_set(), but not impossible. Esp. if fault injection is used to aid the execution/failure. It was demonstrated by Sirius: BUG: unable to handle page fault for address: fffffffffffffff8 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD cb7b067 P4D cb7b067 PUD cb7d067 PMD 0 Oops: 0000 [#1] PREEMPT SMP KASAN CPU: 1 PID: 8007 Comm: poc Not tainted 6.7.0-g9d1694dc91ce #20 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 RIP: 0010:fbcon_get_font+0x229/0x800 drivers/video/fbdev/core/fbcon.c:2286 Call Trace: <TASK> con_font_get drivers/tty/vt/vt.c:4558 [inline] con_font_op+0x1fc/0xf20 drivers/tty/vt/vt.c:4673 vt_k_ioctl drivers/tty/vt/vt_ioctl.c:474 [inline] vt_ioctl+0x632/0x2ec0 drivers/tty/vt/vt_ioctl.c:752 tty_ioctl+0x6f8/0x1570 drivers/tty/tty_io.c:2803 vfs_ioctl fs/ioctl.c:51 [inline] ... So restore the font data in any case, not only for user fonts. Note the later 'if' is now protected by 'old_userfont' and not 'old_data' as the latter is always set now. (And it is supposed to be non-NULL. Otherwise we would see the bug above again.) Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org> Fixes: a5a923038d70 ("fbdev: fbcon: Properly revert changes when vc_resize() failed") Reported-and-tested-by: Ubisectech Sirius <bugreport@ubisectech.com> Cc: Ubisectech Sirius <bugreport@ubisectech.com> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Helge Deller <deller@gmx.de> Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: https://patchwork.freedesktop.org/patch/msgid/20240208114411.14604-1-jirisla... Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/video/fbdev/core/fbcon.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 8cd853ed6b55..81bf4f7bd9e8 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2431,11 +2431,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, struct fbcon_display *p = &fb_display[vc->vc_num]; int resize, ret, old_userfont, old_width, old_height, old_charcount; int cnt; - char *old_data = NULL; + u8 *old_data = vc->vc_font.data; resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); - if (p->userfont) - old_data = vc->vc_font.data; if (userfont) cnt = FNTCHARCNT(data); else @@ -2472,13 +2470,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, update_screen(vc); } - if (old_data && (--REFCOUNT(old_data) == 0)) + if (old_userfont && (--REFCOUNT(old_data) == 0)) kfree(old_data - FONT_EXTRA_WORDS * sizeof(int)); return 0; err_out: p->fontdata = old_data; - vc->vc_font.data = (void *)old_data; + vc->vc_font.data = old_data; if (userfont) { p->userfont = old_userfont; -- 2.25.1

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16816 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/YDS... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/16816 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/YDS...
participants (2)
-
patchwork bot
-
Zeng Heng