Re: [PATCH v2] vt: discard stale unicode buffer on alt screen exit after resize

From: Nicolas Pitre

Date: Fri Mar 27 2026 - 13:32:50 EST


On Fri, 27 Mar 2026, Liav Mordouch wrote:

> When enter_alt_screen() saves vc_uni_lines into vc_saved_uni_lines and
> sets vc_uni_lines to NULL, a subsequent console resize via vc_do_resize()
> skips reallocating the unicode buffer because vc_uni_lines is NULL.
> However, vc_saved_uni_lines still points to the old buffer allocated for
> the original dimensions.
>
> When leave_alt_screen() later restores vc_saved_uni_lines, the buffer
> dimensions no longer match vc_rows/vc_cols. Any operation that iterates
> over the unicode buffer using the current dimensions (e.g. csi_J clearing
> the screen) will access memory out of bounds, causing a kernel oops:
>
> BUG: unable to handle page fault for address: 0x0000002000000020
> RIP: 0010:csi_J+0x133/0x2d0
>
> The faulting address 0x0000002000000020 is two adjacent u32 space
> characters (0x20) interpreted as a pointer, read from the row data area
> past the end of the 25-entry pointer array in a buffer allocated for
> 80x25 but accessed with 240x67 dimensions.
>
> Fix this by checking whether the console dimensions changed while in the
> alternate screen. If they did, free the stale saved buffer instead of
> restoring it. The unicode screen will be lazily rebuilt via
> vc_uniscr_check() when next needed.
>
> Fixes: 5eb608319bb5 ("vt: save/restore unicode screen buffer for alternate screen")
> Cc: stable@xxxxxxxxxxxxxxx
> Tested-by: Liav Mordouch <liavmordouch@xxxxxxxxx>
> Signed-off-by: Liav Mordouch <liavmordouch@xxxxxxxxx>

Reviewed-by: Nicolas Pitre <nico@xxxxxxxxxxx>


> ---
> v1 -> v2: Reformatted as a proper patch with commit message, Fixes tag,
> and Signed-off-by. v1 was sent as an inline analysis + diff.
>
> Note: writing of this patch and analysis was assisted by AI for grammar
> and flow. Apologies in advance if anything reads off.
>
> drivers/tty/vt/vt.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> --- a/drivers/tty/vt/vt.c
> +++ b/drivers/tty/vt/vt.c
> @@ -1907,6 +1907,7 @@
> unsigned int rows = min(vc->vc_saved_rows, vc->vc_rows);
> unsigned int cols = min(vc->vc_saved_cols, vc->vc_cols);
> u16 *src, *dest;
> + bool uni_lines_stale;
>
> if (vc->vc_saved_screen == NULL)
> return; /* Not inside an alt-screen */
> @@ -1915,7 +1916,18 @@
> dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols;
> memcpy(dest, src, 2 * cols);
> }
> - vc_uniscr_set(vc, vc->vc_saved_uni_lines);
> + /*
> + * If the console was resized while in the alternate screen,
> + * vc_saved_uni_lines was allocated for the old dimensions.
> + * Restoring it would cause out-of-bounds accesses. Discard it
> + * and let the unicode screen be lazily rebuilt.
> + */
> + uni_lines_stale = vc->vc_saved_rows != vc->vc_rows ||
> + vc->vc_saved_cols != vc->vc_cols;
> + if (uni_lines_stale)
> + vc_uniscr_free(vc->vc_saved_uni_lines);
> + else
> + vc_uniscr_set(vc, vc->vc_saved_uni_lines);
> vc->vc_saved_uni_lines = NULL;
> restore_cur(vc);
> /* Update the entire screen */
>