From a5c959b6186acef13260cf6b42aa1cbfc1d56f34 Mon Sep 17 00:00:00 2001 From: sergio Date: Thu, 6 Aug 2026 13:05:34 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=AF=20portal-probe:=20omitir=20`persis?= =?UTF-8?q?t=5Fmode`=20MATA=20al=20portal=20=E2=80=94=20por=20eso=20Start?= =?UTF-8?q?=20no=20contestaba=20nunca?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Causa raíz de que ScreenCast se quedara colgado en Start, medida en metal (OptiPlex 3060). No era el EGL por software de QEMU: en metal, con iris por hardware, pasaba exactamente lo mismo. Esa hipótesis queda falsificada. Lo que pasa de verdad, con cuatro segfaults reproducibles (uno por intento, todos `at 0` y todos en el MISMO offset de libc, 0x34f64 = `strlen`): 1. el cliente no manda `persist_mode` ⇒ el portal asume PERSIST_MODE_NONE 2. el backend de COSMIC devuelve `restore_data` de todos modos 3. xdg-desktop-portal 1.18.4 entra por la rama NONE de xdp_session_persistence_generate_and_save_restore_token, que hace `g_clear_pointer(in_out_restore_token, g_free)` — token = NULL 4. a la vuelta, el llamador hace `g_variant_new_string(*in_out_restore_token)` SIN comprobar nada ⇒ glib llama strlen(NULL) ⇒ SIGSEGV El portal muere JUSTO ANTES de emitir el Response. Desde el cliente eso se ve como «Start aceptado y nunca contesta», que es indistinguible de un backend que se cuelga — y nos mandó a buscar el problema en la GPU durante meses. Con persist_mode >= 1 el token se genera (uuid) y no hay nulo. Es un fallo de aguas arriba; esto lo esquiva desde el cliente sin tocar el portal. Por defecto 1 (transitorio), que es lo que quiere cualquiera que sólo va a capturar una vez. Co-Authored-By: Claude Opus 5 (1M context) --- tools/portal-probe/portal-probe.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/portal-probe/portal-probe.c b/tools/portal-probe/portal-probe.c index cf2e5a7f..f817e3bd 100644 --- a/tools/portal-probe/portal-probe.c +++ b/tools/portal-probe/portal-probe.c @@ -26,7 +26,7 @@ * el path para recién ahí hacer `AddMatch`, el portal puede haber emitido ya la señal y se pierde * para siempre. Es una carrera real, no teórica. * - * Uso: portal-probe screencast [--multiple] [--window] [--wait N] + * Uso: portal-probe screencast [--multiple] [--window] [--wait N] [--persist 0|1|2] * portal-probe filechooser [--save] * portal-probe screenshot [--wait N] * portal-probe version (qué interfaces sirve el portal, y en qué versión) @@ -246,7 +246,7 @@ static int g_wait_s = 60; /* ── ScreenCast: el handshake de CUATRO pasos ─────────────────────────────────────────────────── */ -static int do_screencast(DBusConnection *bus, int multiple, int window) +static int do_screencast(DBusConnection *bus, int multiple, int window, int persist) { const char *IF = "org.freedesktop.portal.ScreenCast"; char tok[64], path[512], session[256] = {0}; @@ -286,6 +286,17 @@ static int do_screencast(DBusConnection *bus, int multiple, int window) opt_u32(&arr, "types", window ? 2 : 1); opt_bool(&arr, "multiple", multiple ? TRUE : FALSE); opt_u32(&arr, "cursor_mode", 2); /* 1=oculto 2=embebido 4=metadatos */ + /* persist_mode NO es un lujo: OMITIRLO CUELGA EL PORTAL. Medido en metal el 2026-08-06. + * Sin esta opción el portal asume PERSIST_MODE_NONE; el backend de COSMIC devuelve + * `restore_data` igual, y xdg-desktop-portal 1.18.4 entra por la rama NONE de + * xdp_session_persistence_generate_and_save_restore_token, que hace + * `g_clear_pointer(in_out_restore_token, g_free)` — deja el token en NULL — y a la vuelta + * el llamador hace `g_variant_new_string(*in_out_restore_token)` SIN comprobarlo. + * glib llama strlen(NULL) y el portal muere con SIGSEGV justo antes de emitir el Response. + * Desde el cliente se ve como «Start aceptado y nunca contesta»: el proceso que debía + * responder ya no existe. Con persist_mode >= 1 el token se genera (uuid) y no hay nulo. + * Es un fallo de aguas arriba; esto lo esquiva sin tocar el portal. */ + opt_u32(&arr, "persist_mode", (dbus_uint32_t)persist); dbus_message_iter_close_container(&it, &arr); if (!call_request(bus, m, "SelectSources")) return 1; } @@ -413,12 +424,13 @@ int main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); const char *cmd = argc > 1 ? argv[1] : "version"; - int multiple = 0, window = 0, save = 0; + int multiple = 0, window = 0, save = 0, persist = 1; /* 0=none 1=transitorio 2=persistente */ for (int i = 2; i < argc; i++) { if (!strcmp(argv[i], "--multiple")) multiple = 1; else if (!strcmp(argv[i], "--window")) window = 1; else if (!strcmp(argv[i], "--save")) save = 1; else if (!strcmp(argv[i], "--wait") && i + 1 < argc) g_wait_s = atoi(argv[++i]); + else if (!strcmp(argv[i], "--persist") && i + 1 < argc) persist = atoi(argv[++i]); } DBusError err; dbus_error_init(&err); @@ -472,11 +484,11 @@ int main(int argc, char **argv) probe_version(bus, "org.freedesktop.portal.Access"); probe_version(bus, "org.freedesktop.portal.RemoteDesktop"); rc = 0; - } else if (!strcmp(cmd, "screencast")) rc = do_screencast(bus, multiple, window); + } else if (!strcmp(cmd, "screencast")) rc = do_screencast(bus, multiple, window, persist); else if (!strcmp(cmd, "filechooser")) rc = do_filechooser(bus, save); else if (!strcmp(cmd, "screenshot")) rc = do_screenshot(bus); else { - fprintf(stderr, "uso: portal-probe {version|screencast|filechooser|screenshot} [--multiple|--window|--save] [--wait N]\n"); + fprintf(stderr, "uso: portal-probe {version|screencast|filechooser|screenshot} [--multiple|--window|--save] [--wait N] [--persist 0|1|2]\n"); rc = 2; } printf("\n== portal-probe %s: %s ==\n", cmd, rc == 0 ? "OK" : "FALLÓ");