| Author | Andy Green <andy@warmcat.com> 2026-09-12 15:09 UTC | | Committer | Andy Green <andy@warmcat.com> 2026-09-12 15:09 UTC | | Tree | 491b0feb28089fb71d12a98392b66725327b7e30 Raw Patch | | | web: tolerate NULL pss in the http and ws close callbacks | web: tolerate NULL pss in the http and ws close callbacks
lws delivers LWS_CALLBACK_CLOSED_HTTP, LWS_CALLBACK_HTTP_DROP_PROTOCOL
and LWS_CALLBACK_CLOSED with wsi->user_space as the user pointer, which
is NULL when the connection went away before per-session storage was
allocated, eg, a wsi that never bound to a protocol and closed on error
or timeout.
saiw_close_artifact() dereferenced that unconditionally, giving an
invalid read at the artifact field offset (0x9e0) under valgrind after a
while. Bail early on NULL pss there, and guard the ws CLOSED case the
same way before it touches the buflists and subscription list.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
diff --git a/src/web/w-comms.c b/src/web/w-comms.c
index 3daf952..d3c6395 100644
--- a/src/web/w-comms.c
+++ b/src/web/w-comms.c
@@ -145,6 +145,15 @@ saiw_event_db_close_all_now(struct vhd *vhd)
static void
saiw_close_artifact(struct pss *pss)
{
+ /*
+ * lws hands the close callbacks wsi->user_space, which is NULL if the
+ * connection went away before per-session storage was allocated (eg,
+ * a wsi that never bound to a protocol, closed on error or timeout).
+ * There can be no artifact state without a pss, so nothing to do.
+ */
+ if (!pss)
+ return;
+
if (pss->blob_artifact) {
sqlite3_blob_close(pss->blob_artifact);
pss->blob_artifact = NULL;
@@ -811,6 +820,8 @@ http_resp:
case LWS_CALLBACK_CLOSED:
lwsl_wsi_info(wsi, "CLOSED browse conn");
+ if (!pss)
+ break;
lws_buflist2_destroy_all_segments(&pss->raw_tx);
lws_buflist_destroy_all_segments(&pss->rx_reasm);
saiw_browser_state_changed(pss, 0);
|