• Tetsuo Handa's avatar
    fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins. · dd58bd1b
    Tetsuo Handa authored
    commit 033724d6 upstream.
    
    syzbot is reporting general protection fault in bitfill_aligned() [1]
    caused by integer underflow in bit_clear_margins(). The cause of this
    problem is when and how do_vc_resize() updates vc->vc_{cols,rows}.
    
    If vc_do_resize() fails (e.g. kzalloc() fails) when var.xres or var.yres
    is going to shrink, vc->vc_{cols,rows} will not be updated. This allows
    bit_clear_margins() to see info->var.xres < (vc->vc_cols * cw) or
    info->var.yres < (vc->vc_rows * ch). Unexpectedly large rw or bh will
    try to overrun the __iomem region and causes general protection fault.
    
    Also, vc_resize(vc, 0, 0) does not set vc->vc_{cols,rows} = 0 due to
    
      new_cols = (cols ? cols : vc->vc_cols);
      new_rows = (lines ? lines : vc->vc_rows);
    
    exception. Since cols and lines are calculated as
    
      cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
      rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
      cols /= vc->vc_font.width;
      rows /= vc->vc_font.height;
      vc_resize(vc, cols, rows);
    
    in fbcon_modechanged(), var.xres < vc->vc_font.width makes cols = 0
    and var.yres < vc->vc_font.height makes rows = 0. This means that
    
      const int fd = open("/dev/fb0", O_ACCMODE);
      struct fb_var_screeninfo var = { };
      ioctl(fd, FBIOGET_VSCREENINFO, &var);
      var.xres = var.yres = 1;
      ioctl(fd, FBIOPUT_VSCREENINFO, &var);
    
    easily reproduces integer underflow bug explained above.
    
    Of course, callers of vc_resize() are not handling vc_do_resize() failure
    is bad. But we can't avoid vc_resize(vc, 0, 0) which returns 0. Therefore,
    as a band-aid workaround, this patch checks integer underflow in
    "struct fbcon_ops"->clear_margins call, assuming that
    vc->vc_cols * vc->vc_font.width and vc->vc_rows * vc->vc_font.heigh do not
    cause integer overflow.
    
    [1] https://syzkaller.appspot.com/bug?id=a565882df74fa76f10d3a6fec4be31098dbb37c6Reported-and-tested-by: default avatarsyzbot <syzbot+e5fd3e65515b48c02a30@syzkaller.appspotmail.com>
    Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
    Cc: stable <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/20200715015102.3814-1-penguin-kernel@I-love.SAKURA.ne.jpSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    dd58bd1b
fbcon_ud.c 11.5 KB