[PATCH] vt: resize saved unicode buffer on alt screen exit after resize
From: Nicolas Pitre
Date: Fri Mar 27 2026 - 23:09:57 EST
Instead of discarding the saved unicode buffer when the console was
resized while in the alternate screen, resize it to the current
dimensions using vc_uniscr_copy_area() to preserve its content. This
properly restores the unicode screen on alt screen exit rather than
lazily rebuilding it from a lossy reverse glyph translation.
On allocation failure the stale buffer is freed and vc_uni_lines is
set to NULL so it gets lazily rebuilt via vc_uniscr_check() when next
needed.
Signed-off-by: Nicolas Pitre <nico@xxxxxxxxxxx>
---
Liav Mordouch identified and fixed a bug of mine where the saved unicode
buffer would be blindly restored with stale dimensions after a console
resize during the alternate screen, causing out-of-bounds accesses:
https://lore.kernel.org/r/20260327170204.29706-1-liavmordouch@xxxxxxxxx
His fix correctly discards the stale buffer and lets it be lazily
rebuilt. I don't want to simply replace his patch as he deserves credits
for investigating the bug and providing a good fix.
This patch, which goes on top, improves on that by resizing the saved
unicode buffer to the current dimensions instead of discarding it. This
preserves the original unicode screen content rather than relying on a
lossy reverse glyph translation to reconstruct it.
It would be nice to have this in before v7.0 is released.
drivers/tty/vt/vt.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 99f15b3e9544..b4b19157f05c 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1901,7 +1901,6 @@ static void leave_alt_screen(struct vc_data *vc)
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 */
@@ -1912,16 +1911,23 @@ static void leave_alt_screen(struct vc_data *vc)
}
/*
* 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.
+ * resize the saved unicode buffer to the current dimensions.
+ * On allocation failure new_uniscr is NULL, causing the old
+ * buffer to be freed and vc_uni_lines to be lazily rebuilt
+ * via vc_uniscr_check() when next needed.
*/
- uni_lines_stale = vc->vc_saved_rows != vc->vc_rows ||
- vc->vc_saved_cols != vc->vc_cols;
- if (uni_lines_stale)
+ if (vc->vc_saved_uni_lines &&
+ (vc->vc_saved_rows != vc->vc_rows ||
+ vc->vc_saved_cols != vc->vc_cols)) {
+ u32 **new_uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
+
+ if (new_uniscr)
+ vc_uniscr_copy_area(new_uniscr, vc->vc_cols, vc->vc_rows,
+ vc->vc_saved_uni_lines, cols, 0, rows);
vc_uniscr_free(vc->vc_saved_uni_lines);
- else
- vc_uniscr_set(vc, vc->vc_saved_uni_lines);
+ vc->vc_saved_uni_lines = new_uniscr;
+ }
+ vc_uniscr_set(vc, vc->vc_saved_uni_lines);
vc->vc_saved_uni_lines = NULL;
restore_cur(vc);
/* Update the entire screen */
--
2.53.0