wayland: add canary-based heap overflow detection to frame_bufs

Each frame_buf gets a canary field (0xDEADBEEF) set at creation.
Before every frame_paint, all canaries are checked. If one is
trashed, dumps all frame_buf IDs/sizes/addresses to /tmp/wm-canary.log
before aborting.

Set canary in ALL frame_buf creation paths:
- wl_frame_create_toplevel, wl_frame_create_child
- wl_fake_leader_create
- wl_client_reparent (WINGs view frame_buf creation)
- wl_view_commit_backing_impl (WINGs toplevel)
- wl_screen dock_shadow and icon frame_bufs
- wl_window pixmap-to-frame_buf path
This commit is contained in:
lkn 2026-06-25 09:51:45 +02:00
parent 9752672367
commit 01fb5f9e92
6 changed files with 38 additions and 0 deletions

View File

@ -220,6 +220,7 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y)
}
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
/* Connect the WINGs view's backing store to this frame_buf's image */
@ -327,6 +328,7 @@ void wl_view_commit_backing_impl(unsigned long id)
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
}
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
} else {
wfree(fb);

View File

@ -47,6 +47,7 @@ WNativeWindow wl_fake_leader_create(WScreen *scr)
}
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
return fb->id;
}

View File

@ -3,6 +3,7 @@
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_buffer.h>
@ -403,6 +404,7 @@ wl_frame_create_toplevel(WScreen *scr,
}
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
/* Register this frame_buf image in the WINGs backing table so
* WMDrawString() can resolve the window ID to a pixman_image_t
@ -460,6 +462,7 @@ wl_frame_create_child(WNativeWindow parent_win, WScreen *scr,
}
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
W_RegisterBacking(fb->id, fb->image);
return fb->id;
@ -573,9 +576,37 @@ void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
* pixman for bevel lines, and the WINGs font backend for title text.
* Returns 1 (handled) so wFrameWindowPaint skips the Xlib code path.
*/
static void
frame_buf_check_canaries(void)
{
struct wl_frame_buf *fb;
wl_list_for_each(fb, &wl_state.frame_list, link) {
if (fb->canary != 0xDEADBEEF) {
{
FILE *f = fopen("/tmp/wm-canary.log", "w");
if (f) {
fprintf(f, "CANARY TRASHED: fb id=0x%lx size=%dx%d parent=0x%lx canary=0x%08x\n",
(unsigned long)fb->id, fb->width, fb->height,
(unsigned long)fb->parent_id, fb->canary);
struct wl_frame_buf *f2;
wl_list_for_each(f2, &wl_state.frame_list, link) {
fprintf(f, " fb %p id=0x%lx %dx%d parent=0x%lx canary=%s\n",
(void*)f2, (unsigned long)f2->id, f2->width, f2->height,
(unsigned long)f2->parent_id,
f2->canary == 0xDEADBEEF ? "OK" : "BAD");
}
fclose(f);
}
}
abort();
}
}
}
int
wl_frame_paint(struct WFrameWindow *fwin)
{
frame_buf_check_canaries();
/* During live resize, skip expensive repaint — decorations content
* doesn't change, only geometry. Paint once on grab release. */
if (wl_state.grab_type == 2)

View File

@ -513,6 +513,7 @@ wl_screen_create_internals(WScreen *scr)
wlr_scene_node_set_enabled(&dsfb->tree->node, false);
wlr_scene_node_lower_to_bottom(&dsfb->tree->node);
}
dsfb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &dsfb->link);
scr->dock_shadow = dsfb->id;
} else {
@ -562,6 +563,7 @@ wl_screen_create_internals(WScreen *scr)
}
wlr_scene_node_set_enabled(&fb->tree->node, false);
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
W_RegisterBacking(fb->id, fb->image);
scr->workspace_name = fb->id;

View File

@ -109,6 +109,7 @@ struct wl_frame_buf {
int rel_x, rel_y; /* position relative to parent */
int width, height;
pixman_image_t *bg_pixmap; /* background pixmap for window_clear */
uint32_t canary; /* overflow detection: must be 0xDEADBEEF */
struct wl_list link; /* wl_state.frame_list */
};

View File

@ -618,6 +618,7 @@ void wl_balloon_init(WScreen *scr)
wlr_scene_node_set_enabled(&fb->tree->node, false);
}
fb->canary = 0xDEADBEEF;
wl_list_insert(&wl_state.frame_list, &fb->link);
W_RegisterBacking(fb->id, fb->image);
scr->balloon->window = (WNativeWindow)fb->id;