From e64242caef18b4a5840b0e7a9bff37abd4f4f933 Mon Sep 17 00:00:00 2001
From: Helge Deller <deller@gmx.de>
Date: Sat, 25 Jun 2022 13:00:34 +0200
Subject: [PATCH] fbcon: Prevent that screen size is smaller than font size
Git-commit: e64242caef18b4a5840b0e7a9bff37abd4f4f933
Patch-mainline: v5.19-rc6
References: CVE-2021-33655 bsc#1201635
[ backport note: the patch was heavily modified to be adaptable to the
old kernel code where both fbcon and fbmem were still separated.
The original patch exports fbcon_modechange_possible() from fbcon to
be used by fbmem, but it's not possible with the old kernel.
Hence, this patch makes fbcon_modechange_possible() to be called via
the fb notifier instead. fbmem calls the notifier with the new event
type. -- tiwai ]
We need to prevent that users configure a screen size which is smaller than the
currently selected font size. Otherwise rendering chars on the screen will
access memory outside the graphics memory region.
This patch adds a new function fbcon_modechange_possible() which
implements this check and which later may be extended with other checks
if necessary. The new function is called from the FBIOPUT_VSCREENINFO
ioctl handler in fbmem.c, which will return -EINVAL if userspace asked
for a too small screen size.
Signed-off-by: Helge Deller <deller@gmx.de>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: stable@vger.kernel.org # v5.4+
Acked-by: Takashi Iwai <tiwai@suse.de>
---
drivers/video/console/fbcon.c | 29 +++++++++++++++++++++++++++++
drivers/video/fbdev/core/fbmem.c | 7 ++++++-
include/linux/fb.h | 2 ++
3 files changed, 37 insertions(+), 1 deletion(-)
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2676,6 +2676,32 @@ static void fbcon_set_all_vcs(struct fb_
fbcon_modechanged(info);
}
+/* let fbcon check if it supports a new screen resolution */
+static int fbcon_modechange_possible(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct vc_data *vc;
+ unsigned int i;
+
+ if (!ops)
+ return 0;
+
+ /* prevent setting a screen size which is smaller than font size */
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ vc = vc_cons[i].d;
+ if (!vc || vc->vc_mode != KD_TEXT ||
+ registered_fb[con2fb_map[i]] != info)
+ continue;
+
+ if (vc->vc_font.width > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
+ vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
+ return notifier_from_errno(-EINVAL);
+ }
+
+ return 0;
+}
+
static int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode)
{
@@ -3031,6 +3057,9 @@ static int fbcon_event_notify(struct not
idx = info->node;
fbcon_remap_all(idx);
break;
+ case FB_EVENT_MODE_CHANGE_CHECK:
+ ret = fbcon_modechange_possible(event->info, event->data);
+ break;
}
done:
return ret;
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1123,7 +1123,12 @@ static long do_fb_ioctl(struct fb_info *
return -ENODEV;
}
info->flags |= FBINFO_MISC_USEREVENT;
- ret = fb_set_var(info, &var);
+ event.info = info;
+ event.data = &var;
+ ret = fb_notifier_call_chain(FB_EVENT_MODE_CHANGE_CHECK, &event);
+ ret = notifier_to_errno(ret);
+ if (!ret)
+ ret = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT;
unlock_fb_info(info);
console_unlock();
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -162,6 +162,8 @@ struct fb_cursor_user {
#define FB_EARLY_EVENT_BLANK 0x10
/* A hardware display blank revert early change occured */
#define FB_R_EARLY_EVENT_BLANK 0x11
+/* pre-check for mode change (used only by fbcon) */
+#define FB_EVENT_MODE_CHANGE_CHECK 0x12
struct fb_event {
struct fb_info *info;