Skip to content

Ensure no loops in toplevel parents#4894

Open
robert-ancell wants to merge 1 commit intomainfrom
toplevel-parent-loop
Open

Ensure no loops in toplevel parents#4894
robert-ancell wants to merge 1 commit intomainfrom
toplevel-parent-loop

Conversation

@robert-ancell
Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings April 22, 2026 23:58
@robert-ancell robert-ancell requested a review from a team as a code owner April 22, 2026 23:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent invalid/cyclic xdg_toplevel parent relationships in the Wayland stable xdg-shell implementation, by rejecting self-parenting and parent/child loops.

Changes:

  • Add a self-parent check in XdgToplevelStable::set_parent() and raise xdg_toplevel::error.invalid_parent.
  • Add an ancestor-walk check intended to reject choosing a parent that is a descendant of the child toplevel.

Comment on lines +479 to +495
// Check that the parent is not a descendant of this toplevel
auto const this_surface = scene_surface();
if (this_surface)
{
auto parent_surface = parent_toplevel->scene_surface();
while (parent_surface)
{
if (parent_surface.value() == this_surface.value())
{
BOOST_THROW_EXCEPTION(mw::ProtocolError(
resource,
Error::invalid_parent,
"Parent toplevel must not be a descendant of the child toplevel"));
}
auto const grandparent = parent_surface.value()->parent();
parent_surface = grandparent ? std::optional{grandparent} : std::nullopt;
}
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cycle check walks parent_surface->parent() on mir::scene::Surface, but BasicSurface::parent() is backed by a parent_ member that is fixed at construction (so it won’t reflect later xdg_toplevel.set_parent reparenting handled in miral). This means a client can still create a cyclic toplevel-parent relationship that won’t be detected here, and will instead trip miral’s cycle detection (which throws std::runtime_error), causing wl_surface commit to hit the generic exception path (internal error) rather than a clean xdg_toplevel::error.invalid_parent. Consider validating against the same parent chain used by miral (WindowInfo parent links) or explicitly tracking the xdg-toplevel parent relationship (including pending/uncommitted changes) within XdgToplevelStable and using that for loop detection, so the protocol error is reliably raised here.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, Copilot may be correct in this case. The parent set by WindowWlSurfaceRole::set_parent is const. I see no immediate way the parent we set and the parents we check connect.

Comment on lines +479 to +495
// Check that the parent is not a descendant of this toplevel
auto const this_surface = scene_surface();
if (this_surface)
{
auto parent_surface = parent_toplevel->scene_surface();
while (parent_surface)
{
if (parent_surface.value() == this_surface.value())
{
BOOST_THROW_EXCEPTION(mw::ProtocolError(
resource,
Error::invalid_parent,
"Parent toplevel must not be a descendant of the child toplevel"));
}
auto const grandparent = parent_surface.value()->parent();
parent_surface = grandparent ? std::optional{grandparent} : std::nullopt;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, Copilot may be correct in this case. The parent set by WindowWlSurfaceRole::set_parent is const. I see no immediate way the parent we set and the parents we check connect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants