syzbot is reporting OOB write at vga16fb_imageblit() [1], for resize_screen() from ioctl(VT_RESIZE) returns 0 without checking whether requested rows/columns fit the amount of memory reserved for the graphical screen if current mode is KD_GRAPHICS. ---------- #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/kd.h> #include <linux/vt.h> int main(int argc, char *argv[]) { const int fd = open("/dev/char/4:1", O_RDWR); struct vt_sizes vt = { 0x4100, 2 }; ioctl(fd, KDSETMODE, KD_GRAPHICS); ioctl(fd, VT_RESIZE, &vt); ioctl(fd, KDSETMODE, KD_TEXT); return 0; } ---------- Allow framebuffer drivers to return -EINVAL, by moving vc->vc_mode != KD_GRAPHICS check from resize_screen() to fbcon_resize().
Unified · Split
| @@ -1171,7 +1171,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, · 1170 unmodified lines | |||
| 1171 | /* Resizes the resolution of the display adapater */ | 1171 | /* Resizes the resolution of the display adapater */ |
| 1172 | int err = 0; | 1172 | int err = 0; |
| 1173 | 1173 | ||
| 1174 | if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize) | 1174 | if (vc->vc_sw->con_resize) |
| 1175 | err = vc->vc_sw->con_resize(vc, width, height, user); | 1175 | err = vc->vc_sw->con_resize(vc, width, height, user); |
| 1176 | 1176 | ||
| 1177 | return err; | 1177 | return err; |
| @@ -2019,7 +2019,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, · 2018 unmodified lines | |||
| 2019 | return -EINVAL; | 2019 | return -EINVAL; |
| 2020 | 2020 | ||
| 2021 | pr_debug("resize now %ix%i\n", var.xres, var.yres); | 2021 | pr_debug("resize now %ix%i\n", var.xres, var.yres); |
| 2022 | if (con_is_visible(vc)) { | 2022 | if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) { |
| 2023 | var.activate = FB_ACTIVATE_NOW | | 2023 | var.activate = FB_ACTIVATE_NOW | |
| 2024 | FB_ACTIVATE_FORCE; | 2024 | FB_ACTIVATE_FORCE; |
| 2025 | fb_set_var(info, &var); | 2025 | fb_set_var(info, &var); |