From d541ae4e76ae35b76490206ef946a9124b993e32 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 19 Jul 2018 00:05:25 -0400 Subject: [PATCH] vt: avoid a VLA in the unicode screen scroll function The nr argument is typically small: most often nr == 1. However this could be abused with a very large explicit scroll in a resized screen. Make the code scroll lines by performing an array rotation operation to avoid the need for a large temporary space. Requested-by: Kees Cook Suggested-by: Adam Borowski Signed-off-by: Nicolas Pitre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 4b3c371f0f84..5f1183b0b89d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -104,6 +104,7 @@ #include #include #include +#include #define MAX_NR_CON_DRIVER 16 @@ -434,20 +435,29 @@ static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b, struct uni_screen *uniscr = get_vc_uniscr(vc); if (uniscr) { - unsigned int s, d, rescue, clear; - char32_t *save[nr]; + unsigned int i, j, k, sz, d, clear; - s = clear = t; - d = t + nr; - rescue = b - nr; - if (dir == SM_UP) { - swap(s, d); - swap(clear, rescue); + sz = b - t; + clear = b - nr; + d = nr; + if (dir == SM_DOWN) { + clear = t; + d = sz - nr; + } + for (i = 0; i < gcd(d, sz); i++) { + char32_t *tmp = uniscr->lines[t + i]; + j = i; + while (1) { + k = j + d; + if (k >= sz) + k -= sz; + if (k == i) + break; + uniscr->lines[t + j] = uniscr->lines[t + k]; + j = k; + } + uniscr->lines[t + j] = tmp; } - memcpy(save, uniscr->lines + rescue, nr * sizeof(*save)); - memmove(uniscr->lines + d, uniscr->lines + s, - (b - t - nr) * sizeof(*uniscr->lines)); - memcpy(uniscr->lines + clear, save, nr * sizeof(*save)); vc_uniscr_clear_lines(vc, clear, nr); } }