replace reproducer with nova-shell-unpatched flake output for A/B testing

This commit is contained in:
Damocles 2026-04-20 23:03:28 +02:00
parent c26e79458a
commit 90c3bd3da2
3 changed files with 7 additions and 110 deletions

View file

@ -89,21 +89,19 @@
docs = pkgs.callPackage ./nix/docs.nix { inherit self; }; docs = pkgs.callPackage ./nix/docs.nix { inherit self; };
default = nova-shell; default = nova-shell;
# Reproducer wrappers: run test/screen-uaf-reproducer/shell.qml # nova-shell on unpatched Qt for A/B crash testing
# with patched vs unpatched quickshell to confirm the fix. nova-shell-unpatched =
screen-uaf-reproducer-patched = pkgs.writeShellScriptBin "screen-uaf-reproducer-patched" ''
exec ${qs}/bin/quickshell -p ${./test/screen-uaf-reproducer/shell.qml}
'';
screen-uaf-reproducer-unpatched =
let let
qsUnpatched = (rawPkgs.extend quickshell.overlays.default).quickshell.override { qsUnpatched = (rawPkgs.extend quickshell.overlays.default).quickshell.override {
withX11 = false; withX11 = false;
withI3 = false; withI3 = false;
}; };
in in
rawPkgs.writeShellScriptBin "screen-uaf-reproducer-unpatched" '' rawPkgs.callPackage ./nix/package.nix {
exec ${qsUnpatched}/bin/quickshell -p ${./test/screen-uaf-reproducer/shell.qml} quickshell = qsUnpatched;
''; nova-stats = rawPkgs.callPackage ./nix/stats-daemon.nix { };
nova-shaders = rawPkgs.callPackage ./nix/shaders.nix { };
};
} }
); );

View file

@ -1,52 +0,0 @@
// Minimal reproducer for Qt 6 Wayland screen use-after-free (QTBUG-XXXXXX).
//
// Creates many layer-shell surfaces bound to each screen. When an output is
// removed, the compositor sends wl_surface.leave + wl_registry.global_remove
// in the same event batch. libwayland resolves the wl_output proxy pointer at
// demarshal time; if the global_remove handler destroys the proxy first, the
// surface.leave handler receives a dangling pointer and crashes in
// QWaylandScreen::fromWlOutput / QPlatformScreen::screen().
//
// Run with unpatched Qt 6.10.2:
// quickshell -p ./shell.qml
//
// Then toggle an output:
// niri msg action power-off-monitors (move mouse to wake)
// wlr-randr --output eDP-1 --off && sleep 0.3 && wlr-randr --output eDP-1 --on
// or unplug/replug an external monitor
//
// Should crash within a few seconds of the output toggle.
import Quickshell
import Quickshell.Wayland
import QtQuick
ShellRoot {
// 20 layer-shell surfaces per screen - all bound to the output,
// so the compositor must send enter/leave for each on removal.
Variants {
model: Quickshell.screens
Scope {
required property var modelData
Repeater {
model: 20
PanelWindow {
screen: modelData
anchors {
top: true
left: true
}
width: 60
height: 20
margins.top: index * 22
margins.left: 4
exclusiveZone: 0
color: "#80ff00ff"
}
}
}
}
}

View file

@ -1,49 +0,0 @@
#!/usr/bin/env bash
# Trigger rapid output power-cycling to provoke the Qt Wayland screen UAF.
#
# First, in another terminal:
# nix run .#screen-uaf-reproducer-unpatched (should crash)
# nix run .#screen-uaf-reproducer-patched (should survive)
#
# Then run this script to toggle the output.
#
# Usage: ./trigger.sh [iterations]
# iterations: number of off/on cycles (default 20)
set -euo pipefail
cycles="${1:-20}"
if command -v niri &>/dev/null && niri msg version &>/dev/null; then
echo "Detected Niri - using niri msg"
for i in $(seq 1 "$cycles"); do
echo "cycle $i/$cycles"
niri msg action power-off-monitors
sleep 0.3
niri msg action power-on-monitors
sleep 0.5
done
elif command -v wlr-randr &>/dev/null; then
output=$(wlr-randr --json 2>/dev/null | python3 -c \
"import sys,json; print(next(o['name'] for o in json.load(sys.stdin) if o['enabled']))" 2>/dev/null \
|| wlr-randr | grep -oP '^\S+' | head -1)
if [ -z "$output" ]; then
echo "error: could not detect an output via wlr-randr" >&2
exit 1
fi
echo "Detected wlroots compositor - toggling output $output"
for i in $(seq 1 "$cycles"); do
echo "cycle $i/$cycles"
wlr-randr --output "$output" --off
sleep 0.3
wlr-randr --output "$output" --on
sleep 0.5
done
else
echo "error: neither niri nor wlr-randr found" >&2
echo "Manually unplug/replug a monitor while the reproducer is running." >&2
exit 1
fi
echo "Done. If the reproducer is still alive, the bug did not trigger."
echo "Try increasing iterations or adding more surfaces."