git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitb4f1a488e9273f8c2807d504e9c20f9272143468
parent03f18788d3
authorIsaac Freund <[email protected]>
date2023-01-07 14:58
session-lock: fix assertion failure due to race

There's currently a potential race in the implementation that can be hit
during unlocking. This is not a security vulnerability, but it does
cause the compositor to crash due to a failed assertion.

This commit simplifies the code and fixes the race as well as tightening
up the assertions around this state/control flow even further.

 river/Output.zig |  4 ++--
 river/render.zig | 13 ++++++++++---
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/river/Output.zig b/river/Output.zig
index 0d5a541..b14247a 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -530,7 +530,7 @@ fn handlePresent(
     const self = @fieldParentPtr(Self, "present", listener);
 
     switch (self.lock_render_state) {
-        .unlocked => return,
+        .unlocked => assert(server.lock_manager.state != .locked),
         .pending_blank, .pending_lock_surface => {
             if (!event.presented) {
                 self.lock_render_state = .unlocked;
@@ -548,7 +548,7 @@ fn handlePresent(
                 server.lock_manager.maybeLock();
             }
         },
-        .blanked, .lock_surface => unreachable,
+        .blanked, .lock_surface => {},
     }
 }
 
diff --git a/river/render.zig b/river/render.zig
index a238cd9..6c1280c 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -98,10 +98,17 @@ pub fn renderOutput(output: *Output) void {
             return;
         };
 
-        if (output.lock_surface == null) {
-            output.lock_render_state = .pending_blank;
+        if (server.lock_manager.state == .locked) {
+            switch (output.lock_render_state) {
+                .unlocked, .pending_blank, .pending_lock_surface => unreachable,
+                .blanked, .lock_surface => {},
+            }
         } else {
-            output.lock_render_state = .pending_lock_surface;
+            if (output.lock_surface == null) {
+                output.lock_render_state = .pending_blank;
+            } else {
+                output.lock_render_state = .pending_lock_surface;
+            }
         }
 
         return;