Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 376810e5 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by Greg Kroah-Hartman
Browse files

fbmem: pull fbcon_update_vcs() out of fb_set_var()

[ Upstream commit d88ca7e1a27eb2df056bbf37ddef62e1c73d37ea ]

syzbot is reporting OOB read bug in vc_do_resize() [1] caused by memcpy()
based on outdated old_{rows,row_size} values, for resize_screen() can
recurse into vc_do_resize() which changes vc->vc_{cols,rows} that outdates
old_{rows,row_size} values which were saved before calling resize_screen().

Daniel Vetter explained that resize_screen() should not recurse into
fbcon_update_vcs() path due to FBINFO_MISC_USEREVENT being still set
when calling resize_screen().

Instead of masking FBINFO_MISC_USEREVENT before calling fbcon_update_vcs(),
we can remove FBINFO_MISC_USEREVENT by calling fbcon_update_vcs() only if
fb_set_var() returned 0. This change assumes that it is harmless to call
fbcon_update_vcs() when fb_set_var() returned 0 without reaching
fb_notifier_call_chain().

[1] https://syzkaller.appspot.com/bug?id=c70c88cfd16dcf6e1d3c7f0ab8648b3144b5b25e



Reported-and-tested-by: default avatarsyzbot <syzbot+c37a14770d51a085a520@syzkaller.appspotmail.com>
Suggested-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reported-by: kernel test robot <lkp@intel.com> for missing #include
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/075b7e37-3278-cd7d-31ab-c5073cfa8e92@i-love.sakura.ne.jp


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 6a862aa3
Loading
Loading
Loading
Loading
+2 −6
Original line number Diff line number Diff line
@@ -952,7 +952,6 @@ static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
int
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
	int flags = info->flags;
	int ret = 0;
	u32 activate;
	struct fb_var_screeninfo old_var;
@@ -1047,9 +1046,6 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
	event.data = &mode;
	fb_notifier_call_chain(FB_EVENT_MODE_CHANGE, &event);

	if (flags & FBINFO_MISC_USEREVENT)
		fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);

	return 0;
}
EXPORT_SYMBOL(fb_set_var);
@@ -1100,9 +1096,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
			return -EFAULT;
		console_lock();
		lock_fb_info(info);
		info->flags |= FBINFO_MISC_USEREVENT;
		ret = fb_set_var(info, &var);
		info->flags &= ~FBINFO_MISC_USEREVENT;
		if (!ret)
			fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
		unlock_fb_info(info);
		console_unlock();
		if (!ret && copy_to_user(argp, &var, sizeof(var)))
+2 −2
Original line number Diff line number Diff line
@@ -91,9 +91,9 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)

	var->activate |= FB_ACTIVATE_FORCE;
	console_lock();
	fb_info->flags |= FBINFO_MISC_USEREVENT;
	err = fb_set_var(fb_info, var);
	fb_info->flags &= ~FBINFO_MISC_USEREVENT;
	if (!err)
		fbcon_update_vcs(fb_info, var->activate & FB_ACTIVATE_ALL);
	console_unlock();
	if (err)
		return err;
+3 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/fb.h>
#include <linux/fbcon.h>
#include <linux/init.h>

#include <asm/cell-regs.h>
@@ -824,12 +825,12 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
				var = info->var;
				fb_videomode_to_var(&var, vmode);
				console_lock();
				info->flags |= FBINFO_MISC_USEREVENT;
				/* Force, in case only special bits changed */
				var.activate |= FB_ACTIVATE_FORCE;
				par->new_mode_id = val;
				retval = fb_set_var(info, &var);
				info->flags &= ~FBINFO_MISC_USEREVENT;
				if (!retval)
					fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
				console_unlock();
			}
			break;
+0 −2
Original line number Diff line number Diff line
@@ -400,8 +400,6 @@ struct fb_tile_ops {
#define FBINFO_HWACCEL_YPAN		0x2000 /* optional */
#define FBINFO_HWACCEL_YWRAP		0x4000 /* optional */

#define FBINFO_MISC_USEREVENT          0x10000 /* event request
						  from userspace */
#define FBINFO_MISC_TILEBLITTING       0x20000 /* use tile blitting */

/* A driver may set this flag to indicate that it does want a set_par to be