Обсуждение: BUG #17477: A crash bug in transformValuesClause()

Поиск
Список
Период
Сортировка

BUG #17477: A crash bug in transformValuesClause()

От
PG Bug reporting form
Дата:
The following bug has been logged on the website:

Bug reference:      17477
Logged by:          Wang Ke
Email address:      krking@zju.edu.cn
PostgreSQL version: 14.2
Operating system:   Ubuntu 20.04.4 LTS x86_64
Description:

Hello, I found a security bug recently in the latest release version of
Postgresql server(14.2) which causes a segmentation fault caused by a READ
memory access, the detail is as follow:

Reported by:
Wang Ke of Zhejiang University

OS version and name:
Linux ubuntu 5.13.0-40-generic #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC
2022 x86_64 x86_64 x86_64 GNU/Linux


PoC:

CREATE VIEW v0 AS SELECT ;
SELECT INTO GLOBAL TEMP TABLE v0 FROM v0 v1 ;
SET SESSION AUTHORIZATION 'x' ;
CREATE TEMP TABLE v1 ( v2 ) ON COMMIT DELETE ROWS AS VALUES ( 'x' ) , ( 'x'
) , ( 'x' ) ;
SELECT v2 , v2 FROM v0 AS v2 GROUP BY DISTINCT CUBE ( ( VALUES ( ( v2 . * )
) FOR READ ONLY ) ) ;


Crash Log:

2022-05-09 17:00:56.605 CST [245199] LOG:  statement: SELECT v2 , v2 FROM v0
AS v2 GROUP BY DISTINCT CUBE ( ( VALUES ( ( v2 . * ) ) FOR READ ONLY ) ) ;
AddressSanitizer:DEADLYSIGNAL
=================================================================
==245199==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000082
(pc 0x55e7ed66ad51 bp 0x7fff1c8b3cd0 sp 0x7fff1c8b3b10 T0)
==245199==The signal is caused by a READ memory access.
==245199==Hint: address points to the zero page.
    #0 0x55e7ed66ad50 in transformValuesClause
postgresql-14.2/bld/../src/backend/parser/analyze.c:1512
    #1 0x55e7ed66ad50 in transformStmt
postgresql-14.2/bld/../src/backend/parser/analyze.c:321
    #2 0x55e7ed670b70 in parse_sub_analyze
postgresql-14.2/bld/../src/backend/parser/analyze.c:198
    #3 0x55e7ed6ce7d0 in transformSubLink
postgresql-14.2/bld/../src/backend/parser/parse_expr.c:1797
    #4 0x55e7ed6ce7d0 in transformExprRecurse
postgresql-14.2/bld/../src/backend/parser/parse_expr.c:229
    #5 0x55e7ed6cab66 in transformExpr
postgresql-14.2/bld/../src/backend/parser/parse_expr.c:104
    #6 0x55e7ed6a90b8 in findTargetlistEntrySQL99
postgresql-14.2/bld/../src/backend/parser/parse_clause.c:2071
    #7 0x55e7ed6a9639 in findTargetlistEntrySQL92
postgresql-14.2/bld/../src/backend/parser/parse_clause.c:2040
    #8 0x55e7ed6b25f1 in transformGroupClauseExpr
postgresql-14.2/bld/../src/backend/parser/parse_clause.c:2264
    #9 0x55e7ed6b2aca in transformGroupingSet
postgresql-14.2/bld/../src/backend/parser/parse_clause.c:2449
    #10 0x55e7ed6b30fa in transformGroupClause
postgresql-14.2/bld/../src/backend/parser/parse_clause.c:2571
    #11 0x55e7ed66b9cd in transformSelectStmt
postgresql-14.2/bld/../src/backend/parser/analyze.c:1299
    #12 0x55e7ed66b9cd in transformStmt
postgresql-14.2/bld/../src/backend/parser/analyze.c:323
    #13 0x55e7ed672aab in transformOptionalSelectInto
postgresql-14.2/bld/../src/backend/parser/analyze.c:268
    #14 0x55e7ed672d21 in transformTopLevelStmt
postgresql-14.2/bld/../src/backend/parser/analyze.c:218
    #15 0x55e7ed672e69 in parse_analyze
postgresql-14.2/bld/../src/backend/parser/analyze.c:127
    #16 0x55e7edd5dadd in pg_analyze_and_rewrite
postgresql-14.2/bld/../src/backend/tcop/postgres.c:657
    #17 0x55e7edd5ecbd in exec_simple_query
postgresql-14.2/bld/../src/backend/tcop/postgres.c:1130
    #18 0x55e7edd606f1 in PostgresMain
postgresql-14.2/bld/../src/backend/tcop/postgres.c:4486
    #19 0x55e7edbc765d in BackendRun
postgresql-14.2/bld/../src/backend/postmaster/postmaster.c:4530
    #20 0x55e7edbc765d in BackendStartup
postgresql-14.2/bld/../src/backend/postmaster/postmaster.c:4252
    #21 0x55e7edbc765d in ServerLoop
postgresql-14.2/bld/../src/backend/postmaster/postmaster.c:1745
    #22 0x55e7edbca087 in PostmasterMain
postgresql-14.2/bld/../src/backend/postmaster/postmaster.c:1417
    #23 0x55e7ed9c046e in main
postgresql-14.2/bld/../src/backend/main/main.c:209
    #24 0x7ffaf632f0b2 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x240b2)
    #25 0x55e7ed37c5ed in _start (/usr/local/pgsql/bin/postgres+0x38d5ed)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV
postgresql-14.2/bld/../src/backend/parser/analyze.c:1512 in
transformValuesClause
==245199==ABORTING
2022-05-09 17:00:56.655 CST [245188] DEBUG:  reaping dead processes
2022-05-09 17:00:56.655 CST [245188] DEBUG:  server process (PID 245199)
exited with exit code 1
2022-05-09 17:00:56.655 CST [245188] DETAIL:  Failed process was running:
SELECT v2 , v2 FROM v0 AS v2 GROUP BY DISTINCT CUBE ( ( VALUES ( ( v2 . * )
) FOR READ ONLY ) ) ;
2022-05-09 17:00:56.655 CST [245188] LOG:  server process (PID 245199)
exited with exit code 1
2022-05-09 17:00:56.655 CST [245188] DETAIL:  Failed process was running:
SELECT v2 , v2 FROM v0 AS v2 GROUP BY DISTINCT CUBE ( ( VALUES ( ( v2 . * )
) FOR READ ONLY ) ) ;
2022-05-09 17:00:56.655 CST [245188] LOG:  terminating any other active
server processes
2022-05-09 17:00:56.655 CST [245188] DEBUG:  sending SIGQUIT to process
245196
2022-05-09 17:00:56.655 CST [245188] DEBUG:  sending SIGQUIT to process
245192
2022-05-09 17:00:56.655 CST [245188] DEBUG:  sending SIGQUIT to process
245191
2022-05-09 17:00:56.655 CST [245188] DEBUG:  sending SIGQUIT to process
245193
2022-05-09 17:00:56.655 CST [245188] DEBUG:  sending SIGQUIT to process
245194
2022-05-09 17:00:56.655 CST [245188] DEBUG:  sending SIGQUIT to process
245195
2022-05-09 17:00:56.656 CST [245188] DEBUG:  forked new backend, pid=245200
socket=9
2022-05-09 17:00:56.656 CST [245195] DEBUG:  writing stats file
"pg_stat/global.stat"
2022-05-09 17:00:56.656 CST [245195] DEBUG:  writing stats file
"pg_stat/db_32931.stat"
2022-05-09 17:00:56.656 CST [245200] FATAL:  the database system is in
recovery mode
2022-05-09 17:00:56.656 CST [245195] DEBUG:  removing temporary stats file
"pg_stat_tmp/db_32931.stat"
2022-05-09 17:00:56.656 CST [245195] DEBUG:  writing stats file
"pg_stat/db_13012.stat"
2022-05-09 17:00:56.656 CST [245200] DEBUG:  shmem_exit(1): 0
before_shmem_exit callbacks to make
2022-05-09 17:00:56.656 CST [245200] DEBUG:  shmem_exit(1): 0 on_shmem_exit
callbacks to make
2022-05-09 17:00:56.656 CST [245200] DEBUG:  proc_exit(1): 1 callbacks to
make
2022-05-09 17:00:56.656 CST [245200] DEBUG:  exit(1)
2022-05-09 17:00:56.656 CST [245195] DEBUG:  removing temporary stats file
"pg_stat_tmp/db_13012.stat"
2022-05-09 17:00:56.656 CST [245195] DEBUG:  writing stats file
"pg_stat/db_0.stat"
2022-05-09 17:00:56.656 CST [245200] DEBUG:  shmem_exit(-1): 0
before_shmem_exit callbacks to make
2022-05-09 17:00:56.656 CST [245200] DEBUG:  shmem_exit(-1): 0 on_shmem_exit
callbacks to make
2022-05-09 17:00:56.656 CST [245200] DEBUG:  proc_exit(-1): 0 callbacks to
make
2022-05-09 17:00:56.656 CST [245195] DEBUG:  removing temporary stats file
"pg_stat_tmp/db_0.stat"
2022-05-09 17:00:56.657 CST [245195] DEBUG:  shmem_exit(-1): 0
before_shmem_exit callbacks to make
2022-05-09 17:00:56.657 CST [245195] DEBUG:  shmem_exit(-1): 0 on_shmem_exit
callbacks to make
2022-05-09 17:00:56.657 CST [245195] DEBUG:  proc_exit(-1): 0 callbacks to
make
2022-05-09 17:00:56.658 CST [245188] DEBUG:  reaping dead processes
2022-05-09 17:00:56.658 CST [245188] DEBUG:  reaping dead processes
2022-05-09 17:00:56.659 CST [245188] DEBUG:  reaping dead processes
2022-05-09 17:00:56.659 CST [245188] DEBUG:  server process (PID 245200)
exited with exit code 1
2022-05-09 17:00:56.659 CST [245188] LOG:  all server processes terminated;
reinitializing
2022-05-09 17:00:56.660 CST [245188] DEBUG:  shmem_exit(1): 0
before_shmem_exit callbacks to make
2022-05-09 17:00:56.660 CST [245188] DEBUG:  shmem_exit(1): 5 on_shmem_exit
callbacks to make
2022-05-09 17:00:56.660 CST [245188] DEBUG:  cleaning up dynamic shared
memory control segment with ID 3198822830
2022-05-09 17:00:56.661 CST [245188] DEBUG:  invoking
IpcMemoryCreate(size=148815872)
2022-05-09 17:00:56.661 CST [245188] DEBUG:  mmap(148897792) with
MAP_HUGETLB failed, huge pages disabled: Cannot allocate memory
2022-05-09 17:00:56.666 CST [245188] DEBUG:  dynamic shared memory system
will support 674 segments
2022-05-09 17:00:56.667 CST [245188] DEBUG:  created dynamic shared memory
control segment 1631943408 (26976 bytes)
2022-05-09 17:00:56.668 CST [245201] LOG:  database system was interrupted;
last known up at 2022-05-09 17:00:07 CST
2022-05-09 17:00:56.668 CST [245201] DEBUG:  removing all temporary WAL
segments
2022-05-09 17:00:56.679 CST [245201] DEBUG:  checkpoint record is at
0/D97D880
2022-05-09 17:00:56.679 CST [245201] DEBUG:  redo record is at 0/D97D880;
shutdown true
2022-05-09 17:00:56.679 CST [245201] DEBUG:  next transaction ID: 954; next
OID: 73880
2022-05-09 17:00:56.679 CST [245201] DEBUG:  next MultiXactId: 1; next
MultiXactOffset: 0
2022-05-09 17:00:56.679 CST [245201] DEBUG:  oldest unfrozen transaction ID:
726, in database 1
2022-05-09 17:00:56.679 CST [245201] DEBUG:  oldest MultiXactId: 1, in
database 1
2022-05-09 17:00:56.679 CST [245201] DEBUG:  commit timestamp Xid
oldest/newest: 0/0
2022-05-09 17:00:56.679 CST [245201] DEBUG:  transaction ID wrap limit is
2147484373, limited by database with OID 1
2022-05-09 17:00:56.679 CST [245201] DEBUG:  MultiXactId wrap limit is
2147483648, limited by database with OID 1
2022-05-09 17:00:56.679 CST [245201] DEBUG:  starting up replication slots
2022-05-09 17:00:56.679 CST [245201] DEBUG:  starting up replication origin
progress state
2022-05-09 17:00:56.679 CST [245201] LOG:  database system was not properly
shut down; automatic recovery in progress


Re: BUG #17477: A crash bug in transformValuesClause()

От
Masahiko Sawada
Дата:
Hi,

On Mon, May 9, 2022 at 7:37 PM PG Bug reporting form
<noreply@postgresql.org> wrote:
>
> The following bug has been logged on the website:
>
> Bug reference:      17477
> Logged by:          Wang Ke
> Email address:      krking@zju.edu.cn
> PostgreSQL version: 14.2
> Operating system:   Ubuntu 20.04.4 LTS x86_64
> Description:
>
> Hello, I found a security bug recently in the latest release version of
> Postgresql server(14.2) which causes a segmentation fault caused by a READ
> memory access, the detail is as follow:
>
> Reported by:
> Wang Ke of Zhejiang University
>
> OS version and name:
> Linux ubuntu 5.13.0-40-generic #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC
> 2022 x86_64 x86_64 x86_64 GNU/Linux
>
>
> PoC:

Thank you for reporting the issue! I've confirmed that this can happen
also on HEAD.

>
> CREATE VIEW v0 AS SELECT ;
> SELECT INTO GLOBAL TEMP TABLE v0 FROM v0 v1 ;
> SET SESSION AUTHORIZATION 'x' ;
> CREATE TEMP TABLE v1 ( v2 ) ON COMMIT DELETE ROWS AS VALUES ( 'x' ) , ( 'x'
> ) , ( 'x' ) ;
> SELECT v2 , v2 FROM v0 AS v2 GROUP BY DISTINCT CUBE ( ( VALUES ( ( v2 . * )
> ) FOR READ ONLY ) ) ;

"SELECT INTO GLOBAL TEMP TABLE" seems an extension that is not
supported in community PostgreSQL. Here is another reproducible step:

create table v0();
select * from v0 group by ((values (v0.*)));

Without table creation, SEGV happens also with the following query:

select (values (foo.*)) from (select from pg_class) as foo;

It seems like transformValuesClause() cannot handle properly the value
clause having a relation that has an empty column. Should we raise an
error in this case?

Regards,

-- 
Masahiko Sawada
EDB:  https://www.enterprisedb.com/



Re: BUG #17477: A crash bug in transformValuesClause()

От
Tom Lane
Дата:
Masahiko Sawada <sawada.mshk@gmail.com> writes:
> It seems like transformValuesClause() cannot handle properly the value
> clause having a relation that has an empty column. Should we raise an
> error in this case?

Given that we try to support zero-column relations, I'm not sure why
we'd insist on disallowing zero-column VALUES.  I think the problem
is that the code in transformValuesClause needs to be tweaked to
make that work.  The attached quick hack seems to do the trick.

            regards, tom lane

diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 0144284aa3..6b54e8e46d 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1424,7 +1424,7 @@ static Query *
 transformValuesClause(ParseState *pstate, SelectStmt *stmt)
 {
     Query       *qry = makeNode(Query);
-    List       *exprsLists;
+    List       *exprsLists = NIL;
     List       *coltypes = NIL;
     List       *coltypmods = NIL;
     List       *colcollations = NIL;
@@ -1508,6 +1508,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)

         /* Release sub-list's cells to save memory */
         list_free(sublist);
+
+        /* Prepare an exprsLists element for this row */
+        exprsLists = lappend(exprsLists, NIL);
     }

     /*
@@ -1551,17 +1554,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
     /*
      * Finally, rearrange the coerced expressions into row-organized lists.
      */
-    exprsLists = NIL;
-    foreach(lc, colexprs[0])
-    {
-        Node       *col = (Node *) lfirst(lc);
-        List       *sublist;
-
-        sublist = list_make1(col);
-        exprsLists = lappend(exprsLists, sublist);
-    }
-    list_free(colexprs[0]);
-    for (i = 1; i < sublist_length; i++)
+    for (i = 0; i < sublist_length; i++)
     {
         forboth(lc, colexprs[i], lc2, exprsLists)
         {
@@ -1569,6 +1562,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
             List       *sublist = lfirst(lc2);

             sublist = lappend(sublist, col);
+            lfirst(lc2) = sublist;
         }
         list_free(colexprs[i]);
     }

Re: BUG #17477: A crash bug in transformValuesClause()

От
"Jonathan S. Katz"
Дата:
On 5/9/22 11:25 AM, Tom Lane wrote:
> Masahiko Sawada <sawada.mshk@gmail.com> writes:
>> It seems like transformValuesClause() cannot handle properly the value
>> clause having a relation that has an empty column. Should we raise an
>> error in this case?
> 
> Given that we try to support zero-column relations, I'm not sure why
> we'd insist on disallowing zero-column VALUES.  I think the problem
> is that the code in transformValuesClause needs to be tweaked to
> make that work.  The attached quick hack seems to do the trick.

Agree with the reasoning.

Confirmed reproducing the crash and that this fixes it. I did a short 
double-take on the error message:

    ERROR:  subquery must return only one column

but it is accurate, given this is what the subquery must do, and zero != 
one.

I don't see anything glaring in the code (though I'm not that familiar 
with this part of the codebase), but given this seems like an extreme 
edge case and protects against a crash, I'm satisfied with this.

Jonathan

Вложения

Re: BUG #17477: A crash bug in transformValuesClause()

От
Tom Lane
Дата:
"Jonathan S. Katz" <jkatz@postgresql.org> writes:
> Confirmed reproducing the crash and that this fixes it. I did a short 
> double-take on the error message:
>     ERROR:  subquery must return only one column
> but it is accurate, given this is what the subquery must do, and zero != 
> one.

Yeah, that's just an artifact of the strange test case.
A more straightforward usage might look like

create table nocols();
select * from nocols n, lateral (values(n.*)) v;

Anyway, this is not a security issue per our normal standards.
It is a crash due to SIGSEGV, but I don't see any likelihood
that it could be exploited for memory disclosure or arbitrary
code execution, so the effects are limited to momentary denial
of service.  There are lots of ways to produce DOS if you have
the ability to issue arbitrary SQL, so we generally don't
consider that a security issue unless there's the possibility
of doing more than just crashing one session.  Having said that,
a crash is unpleasant, so I'm going to take the small risk of
pushing this not-very-well-vetted patch into today's releases.

BTW, if this *had* been a security issue, we'd much rather you'd
have reported it to security@postgresql.org.  The bugs list is
an open channel.

            regards, tom lane



Re: BUG #17477: A crash bug in transformValuesClause()

От
Masahiko Sawada
Дата:
On Tue, May 10, 2022 at 2:20 AM Jonathan S. Katz <jkatz@postgresql.org> wrote:
>
> On 5/9/22 11:25 AM, Tom Lane wrote:
> > Masahiko Sawada <sawada.mshk@gmail.com> writes:
> >> It seems like transformValuesClause() cannot handle properly the value
> >> clause having a relation that has an empty column. Should we raise an
> >> error in this case?
> >
> > Given that we try to support zero-column relations, I'm not sure why
> > we'd insist on disallowing zero-column VALUES.  I think the problem
> > is that the code in transformValuesClause needs to be tweaked to
> > make that work.  The attached quick hack seems to do the trick.
>
> Agree with the reasoning.
>
> Confirmed reproducing the crash and that this fixes it. I did a short
> double-take on the error message:
>
>         ERROR:  subquery must return only one column
>
> but it is accurate, given this is what the subquery must do, and zero !=
> one.

Agreed. I've also confirmed that the patch fixes this issue and passed
the regression tests.

Regards,

--
Masahiko Sawada
EDB:  https://www.enterprisedb.com/



Re: BUG #17477: A crash bug in transformValuesClause()

От
Tom Lane
Дата:
Masahiko Sawada <sawada.mshk@gmail.com> writes:
> On Tue, May 10, 2022 at 2:20 AM Jonathan S. Katz <jkatz@postgresql.org> wrote:
>> Confirmed reproducing the crash and that this fixes it. I did a short
>> double-take on the error message:
>>
>> ERROR:  subquery must return only one column
>>
>> but it is accurate, given this is what the subquery must do, and zero !=
>> one.

> Agreed. I've also confirmed that the patch fixes this issue and passed
> the regression tests.

Thanks for checking!  I've pushed the fix now.

When we have a little more time, we might want to look into making
VALUES-with-no-columns be fully supported, that is not a syntax error.
That's not a crasher bug though, so I feel no desire to deal with
it under a release deadline.

            regards, tom lane



Re: BUG #17477: A crash bug in transformValuesClause()

От
Alvaro Herrera
Дата:
Looking at the code, I understand that what your patch is doing is
making the zeroth case no longer a special one but rather handled it in
the same loop block as the other cases, which is why the bug is fixed.
LGTM.

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
"Ed is the standard text editor."
      http://groups.google.com/group/alt.religion.emacs/msg/8d94ddab6a9b0ad3



Re: BUG #17477: A crash bug in transformValuesClause()

От
Tom Lane
Дата:
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
> Looking at the code, I understand that what your patch is doing is
> making the zeroth case no longer a special one but rather handled it in
> the same loop block as the other cases, which is why the bug is fixed.
> LGTM.

Thanks for looking!  With the time constraint being what it is,
the more eyes on the patch the better.

            regards, tom lane