Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVHm6-001qiV-2A for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 23:46:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wVHm5-009KFV-1f for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 23:46:57 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVHm4-009KFM-2v for pgsql-hackers@lists.postgresql.org; Thu, 04 Jun 2026 23:46:57 +0000 Received: from forward102d.mail.yandex.net ([2a02:6b8:c41:1300:1:45:d181:d102]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wVHm1-000000019Gd-0McS for pgsql-hackers@lists.postgresql.org; Thu, 04 Jun 2026 23:46:56 +0000 Received: from mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net [IPv6:2a02:6b8:c42:7ba3:0:640:5ad4:0]) by forward102d.mail.yandex.net (Yandex) with ESMTPS id F34ECC00FD for ; Fri, 05 Jun 2026 02:46:44 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net (smtp) with ESMTPSA id ikrjvQFd7uQ0-6rEJADWJ; Fri, 05 Jun 2026 02:46:44 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tantorlabs.com; s=mail; t=1780616804; bh=SFOt31rmB386rVhPfgGodpo54IRb+Sxx43k34TiJ7UE=; h=Message-ID:Subject:To:From:Date; b=pNoeVjBl5zpJbMr+LAivWP3NHAZSgZDtnm+YTLaCu9QfaBL2VOPZgm3ZbIN2vGjE6 784S7u6eua9BHBQqmjUqC+wMqbrGfH4NpCx7LTat0k2WayxqrbW13AWgXgOaHoEKU+ 7NxCIvvzTkIx5a1ATQm+xUiP27fJ9aOIOVJdiWGQ= Authentication-Results: mail-nwsmtp-smtp-production-main-77.klg.yp-c.yandex.net; dkim=pass header.i=@tantorlabs.com Date: Fri, 5 Jun 2026 02:46:42 +0300 From: Andrey Chernyy To: pgsql-hackers@lists.postgresql.org Subject: [PATCH] xml2: Fix stylesheet document leak in xslt_process() Message-ID: <20260605024642.5a1b6518@andrnote> X-Mailer: Claws Mail 4.4.0 (GTK 3.24.52; x86_64-redhat-linux-gnu) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="MP_/JNWBJ4_fkREZAfM76xZSan6" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --MP_/JNWBJ4_fkREZAfM76xZSan6 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi, While following up on the recent xml2 XPath leak fixes at https://postgr.es/m/20260601010124.5edf9a20@andrnote, I noticed the same class of libxml/libxslt ownership issue in xslt_process(). xslt_process() parses the stylesheet argument with xmlReadMemory(), then passes the resulting xmlDoc to xsltParseStylesheetDoc(). On failure, libxslt leaves that document owned by the caller, as can be seen from its own xsltParseStylesheetFile() wrapper. Postgres currently cannot release it in the error cleanup path because ssdoc is scoped inside the PG_TRY block. The attached patch keeps ssdoc visible to the cleanup path, clears it once ownership has been transferred to the stylesheet, and frees it in PG_CATCH if parsing failed before that transfer completed. I also attached a manual repro script. It repeatedly calls xslt_process() with a large XML document that is not a stylesheet, catches the ERROR in one backend, and samples VmRSS via /proc. On my machine, without the patch, the same backend kept growing after each failed parse: NOTICE: xslt_process i=1, failures=1, total_kb=34668, diff_kb=12992 NOTICE: xslt_process i=2, failures=1, total_kb=44428, diff_kb=9760 NOTICE: xslt_process i=3, failures=1, total_kb=54120, diff_kb=9692 NOTICE: xslt_process i=4, failures=1, total_kb=63808, diff_kb=9688 NOTICE: xslt_process i=5, failures=1, total_kb=73496, diff_kb=9688 NOTICE: xslt_process i=6, failures=1, total_kb=83188, diff_kb=9692 NOTICE: xslt_process i=7, failures=1, total_kb=92876, diff_kb=9688 NOTICE: xslt_process i=8, failures=1, total_kb=102564, diff_kb=9688 NOTICE: xslt_process i=9, failures=1, total_kb=112256, diff_kb=9692 NOTICE: xslt_process i=10, failures=1, total_kb=121944, diff_kb=9688 With the patch, it plateaued after the initial warmup: NOTICE: xslt_process i=1, failures=1, total_kb=23228, diff_kb=1596 NOTICE: xslt_process i=2, failures=1, total_kb=23888, diff_kb=660 NOTICE: xslt_process i=3, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=4, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=5, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=6, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=7, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=8, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=9, failures=1, total_kb=23888, diff_kb=0 NOTICE: xslt_process i=10, failures=1, total_kb=23888, diff_kb=0 -- Andrey Chernyy --MP_/JNWBJ4_fkREZAfM76xZSan6 Content-Type: application/sql Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=xml2-xslt-process-leak-repro.sql XHNldCBPTl9FUlJPUl9TVE9QIG9uCgpDUkVBVEUgRVhURU5TSU9OIElGIE5PVCBFWElTVFMgeG1s MjsKCkNSRUFURSBPUiBSRVBMQUNFIEZVTkNUSU9OIHBnX3RlbXAudm1yc3Nfa2IoKQpSRVRVUk5T IGludGVnZXIKTEFOR1VBR0Ugc3FsCkFTICQkCiAgU0VMRUNUICgocmVnZXhwX21hdGNoKAogICAg ICAgICAgICAgcGdfcmVhZF9maWxlKCcvcHJvYy8nIHx8IHBnX2JhY2tlbmRfcGlkKCkgfHwgJy9z dGF0dXMnKSwKICAgICAgICAgICAgICdWbVJTUzpbWzpzcGFjZTpdXSsoWzAtOV0rKVtbOnNwYWNl Ol1dK2tCJwogICAgICAgICApKVsxXSk6OmludGVnZXI7CiQkOwoKRFJPUCBUQUJMRSBJRiBFWElT VFMgcGdfdGVtcC54bWwyX3hzbHRfcHJvY2Vzc19kb2M7CgpDUkVBVEUgVEVNUCBUQUJMRSB4bWwy X3hzbHRfcHJvY2Vzc19kb2MgQVMKU0VMRUNUICc8ZG9jLz4nIEFTIGRvYywKICAgICAgICc8Zm9v PicgfHwKICAgICAgIHN0cmluZ19hZ2coJzxiYXIgYXR0cj0idmFsdWUiPnBheWxvYWQ8L2Jhcj4n LCAnJykgfHwKICAgICAgICc8L2Zvbz4nIEFTIGJhZF94c2wKRlJPTSBnZW5lcmF0ZV9zZXJpZXMo MSwgMjAwMDApIEFTIGc7CgpETyAkJApERUNMQVJFCiAgICBiZWZvcmVfcnNzIGJpZ2ludDsKICAg IGFmdGVyX3JzcyAgYmlnaW50OwogICAgZGlmZiAgICAgICBiaWdpbnQ7CiAgICBmYWlsdXJlcyAg IGludGVnZXI7CiAgICBlcnJjb2RlICAgIHRleHQ7CiAgICBjYWxsc19wZXJfcm91bmQgY29uc3Rh bnQgaW50ZWdlciA6PSAxOwpCRUdJTgogICAgRk9SIGkgSU4gMS4uMTAgTE9PUAogICAgICAgIGJl Zm9yZV9yc3MgOj0gcGdfdGVtcC52bXJzc19rYigpOwogICAgICAgIGZhaWx1cmVzIDo9IDA7Cgog ICAgICAgIEZPUiBqIElOIDEuLmNhbGxzX3Blcl9yb3VuZCBMT09QCiAgICAgICAgICAgIEJFR0lO CiAgICAgICAgICAgICAgICBQRVJGT1JNIHhzbHRfcHJvY2Vzcyhkb2MsIGJhZF94c2wpCiAgICAg ICAgICAgICAgICBGUk9NIHhtbDJfeHNsdF9wcm9jZXNzX2RvYzsKICAgICAgICAgICAgRVhDRVBU SU9OIFdIRU4gb3RoZXJzIFRIRU4KICAgICAgICAgICAgICAgIEdFVCBTVEFDS0VEIERJQUdOT1NU SUNTIGVycmNvZGUgPSBSRVRVUk5FRF9TUUxTVEFURTsKICAgICAgICAgICAgICAgIElGIGVycmNv ZGUgPD4gJzEwNjA4JyBUSEVOCiAgICAgICAgICAgICAgICAgICAgUkFJU0U7CiAgICAgICAgICAg ICAgICBFTkQgSUY7CiAgICAgICAgICAgICAgICBmYWlsdXJlcyA6PSBmYWlsdXJlcyArIDE7CiAg ICAgICAgICAgIEVORDsKICAgICAgICBFTkQgTE9PUDsKCiAgICAgICAgYWZ0ZXJfcnNzIDo9IHBn X3RlbXAudm1yc3Nfa2IoKTsKICAgICAgICBkaWZmIDo9IGFmdGVyX3JzcyAtIGJlZm9yZV9yc3M7 CiAgICAgICAgUkFJU0UgTk9USUNFICd4c2x0X3Byb2Nlc3MgaT0lLCBmYWlsdXJlcz0lLCB0b3Rh bF9rYj0lLCBkaWZmX2tiPSUnLAogICAgICAgICAgICAgICAgICAgICBpLCBmYWlsdXJlcywgYWZ0 ZXJfcnNzLCBkaWZmOwogICAgRU5EIExPT1A7CkVORCAkJDsK --MP_/JNWBJ4_fkREZAfM76xZSan6 Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=0001-xml2-Fix-stylesheet-document-leak-in-xslt_process.patch