lkml.org 
[lkml]   [2020]   [Sep]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 53/78] vt: defer kfree() of vc_screenbuf in vc_do_resize()
    Date
    From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>

    commit f8d1653daec02315e06d30246cff4af72e76e54e upstream.

    syzbot is reporting UAF bug in set_origin() from vc_do_resize() [1], for
    vc_do_resize() calls kfree(vc->vc_screenbuf) before calling set_origin().

    Unfortunately, in set_origin(), vc->vc_sw->con_set_origin() might access
    vc->vc_pos when scroll is involved in order to manipulate cursor, but
    vc->vc_pos refers already released vc->vc_screenbuf until vc->vc_pos gets
    updated based on the result of vc->vc_sw->con_set_origin().

    Preserving old buffer and tolerating outdated vc members until set_origin()
    completes would be easier than preventing vc->vc_sw->con_set_origin() from
    accessing outdated vc members.

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

    Reported-by: syzbot <syzbot+9116ecc1978ca3a12f43@syzkaller.appspotmail.com>
    Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    Cc: stable <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/1596034621-4714-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/tty/vt/vt.c | 5 +++--
    1 file changed, 3 insertions(+), 2 deletions(-)

    --- a/drivers/tty/vt/vt.c
    +++ b/drivers/tty/vt/vt.c
    @@ -868,7 +868,7 @@ static int vc_do_resize(struct tty_struc
    unsigned int old_rows, old_row_size;
    unsigned int new_cols, new_rows, new_row_size, new_screen_size;
    unsigned int user;
    - unsigned short *newscreen;
    + unsigned short *oldscreen, *newscreen;

    WARN_CONSOLE_UNLOCKED();

    @@ -950,10 +950,11 @@ static int vc_do_resize(struct tty_struc
    if (new_scr_end > new_origin)
    scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
    new_scr_end - new_origin);
    - kfree(vc->vc_screenbuf);
    + oldscreen = vc->vc_screenbuf;
    vc->vc_screenbuf = newscreen;
    vc->vc_screenbuf_size = new_screen_size;
    set_origin(vc);
    + kfree(oldscreen);

    /* do part of a reset_terminal() */
    vc->vc_top = 0;

    \
     
     \ /
      Last update: 2020-09-01 19:13    [W:4.040 / U:0.180 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site