summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorthankyouverycool <66646555+thankyouverycool@users.noreply.github.com>2023-05-13 05:10:54 -0400
committerAndreas Kling <kling@serenityos.org>2023-05-15 12:15:39 +0200
commit44049f5ad5e7adedcdbc06723856be689c9779b2 (patch)
tree990f0e66f884ea207dc5deb82719ff17ea654ccd /Userland
parentc87c4f6d9456ae142359ef98b8768055d5de8306 (diff)
downloadserenity-44049f5ad5e7adedcdbc06723856be689c9779b2.zip
WindowServer: Catch more Window stealing misbehavior
Previously it was possible for a window to register as a parentless blocking modal then add itself to a stealable parent's modal chain, bypassing a mode misbehavior check in create_window() Also relaxes reciprocity for blockers with the same parent. This scenario is usually created by simultaneous MessageBoxes. It's not an ideal UX to cascade these, but there's no need to crash over it.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Services/WindowServer/ConnectionFromClient.cpp16
-rw-r--r--Userland/Services/WindowServer/Window.cpp2
-rw-r--r--Userland/Services/WindowServer/WindowMode.h2
3 files changed, 14 insertions, 6 deletions
diff --git a/Userland/Services/WindowServer/ConnectionFromClient.cpp b/Userland/Services/WindowServer/ConnectionFromClient.cpp
index dcb57422e7..4bac3d938a 100644
--- a/Userland/Services/WindowServer/ConnectionFromClient.cpp
+++ b/Userland/Services/WindowServer/ConnectionFromClient.cpp
@@ -625,11 +625,6 @@ void ConnectionFromClient::create_window(i32 window_id, Gfx::IntRect const& rect
did_misbehave("CreateWindow with bad parent_window_id");
return;
}
-
- if (auto* blocker = parent_window->blocking_modal_window(); blocker && mode == (i32)WindowMode::Blocking) {
- did_misbehave("CreateWindow with illegal mode: reciprocally blocked");
- return;
- }
}
if (type < 0 || type >= (i32)WindowType::_Count) {
@@ -649,6 +644,11 @@ void ConnectionFromClient::create_window(i32 window_id, Gfx::IntRect const& rect
auto window = Window::construct(*this, (WindowType)type, (WindowMode)mode, window_id, minimizable, closeable, frameless, resizable, fullscreen, parent_window);
+ if (auto* blocker = window->blocking_modal_window(); blocker && mode == to_underlying(WindowMode::Blocking)) {
+ did_misbehave("CreateWindow with illegal mode: Reciprocally blocked");
+ return;
+ }
+
window->set_forced_shadow(forced_shadow);
if (!launch_origin_rect.is_empty())
@@ -1361,6 +1361,12 @@ void ConnectionFromClient::set_window_parent_from_client(i32 client_id, i32 pare
} else {
did_misbehave("SetWindowParentFromClient: Window is not stealable");
}
+
+ auto is_also_blocking = to_underlying(child_window->mode()) == to_underlying(WindowMode::Blocking);
+ if (auto* blocker = child_window->blocking_modal_window(); blocker && is_also_blocking) {
+ did_misbehave("SetWindowParentFromClient: Reciprocally blocked");
+ return;
+ }
}
Messages::WindowServer::GetWindowRectFromClientResponse ConnectionFromClient::get_window_rect_from_client(i32 client_id, i32 window_id)
diff --git a/Userland/Services/WindowServer/Window.cpp b/Userland/Services/WindowServer/Window.cpp
index 809247f2e5..6e0f533111 100644
--- a/Userland/Services/WindowServer/Window.cpp
+++ b/Userland/Services/WindowServer/Window.cpp
@@ -689,6 +689,8 @@ bool Window::is_active() const
Window* Window::blocking_modal_window()
{
auto maybe_blocker = WindowManager::the().for_each_window_in_modal_chain(*this, [&](auto& window) {
+ if (parent_window() == window.parent_window() && is_blocking())
+ return IterationDecision::Continue;
if (is_descendant_of(window))
return IterationDecision::Continue;
if (window.is_blocking() && this != &window)
diff --git a/Userland/Services/WindowServer/WindowMode.h b/Userland/Services/WindowServer/WindowMode.h
index e6c7930adc..c872d62218 100644
--- a/Userland/Services/WindowServer/WindowMode.h
+++ b/Userland/Services/WindowServer/WindowMode.h
@@ -13,7 +13,7 @@ namespace WindowServer {
// - Modeless: No modal effect (default mode for parentless windows)
// - Passive: Joins the modal chain but has no modal effect (default mode for child windows)
// - RenderAbove: Renders above its parent
-// - Blocking: Preempts all interaction with its modal chain excepting descendants and popups (default mode for Dialogs)
+// - Blocking: Preempts all interaction with its modal chain excepting descendants, sibling blockers, and popups (default mode for Dialogs)
enum class WindowMode {
Modeless = 0,
Passive,