Thread: BUG #18276: Heap-buffer-overflow triggered in src/backend/utils/adt/datum.c:163

BUG #18276: Heap-buffer-overflow triggered in src/backend/utils/adt/datum.c:163

From
PG Bug reporting form
Date:
The following bug has been logged on the website:

Bug reference:      18276
Logged by:          Zuming Jiang
Email address:      zuming.jiang@inf.ethz.ch
PostgreSQL version: 16.1
Operating system:   Ubuntu 20.04
Description:

My fuzzer finds a heap-buffer-overflow bug in PostgreSQL 17devel, which
makes PostgreSQL crash.

--- Compile Postgres with ASan ---
./configure CC=clang CFLAGS="-fsanitize=address -fno-omit-frame-pointer -g"
LDFLAGS="-fsanitize=address"
make -j
make install

--- Set up database ---
--- Note: you need to replace
'/home/zuming/postgres/src/test/regress/regress.so' with the your source
code path ---

create table exeet_t228 (vkey int4);
CREATE FUNCTION widget_in(cstring)
   RETURNS widget
   AS '/home/zuming/postgres/src/test/regress/regress.so'
   LANGUAGE C STRICT IMMUTABLE;
CREATE FUNCTION widget_out(widget)
   RETURNS cstring
   AS '/home/zuming/postgres/src/test/regress/regress.so'
   LANGUAGE C STRICT IMMUTABLE;
CREATE TYPE widget (
   input = widget_in,
   output = widget_out,
   alignment = double
);
CREATE FUNCTION pt_in_widget(point, widget)
   RETURNS bool
   AS '/home/zuming/postgres/src/test/regress/regress.so'
   LANGUAGE C STRICT;
CREATE OPERATOR <% (
   leftarg = point,
   rightarg = widget,
   procedure = pt_in_widget,
   negator = >=%
);

My fuzzer generates a test case:

--- Test case ---

select 1 from exeet_t228 as ref_0
where (ref_0.vkey >= (case when ('false' <> (select c1 from (
          select cast(subq_c0 as text) as c0, cast(subq_c1 as text) as c1
          from (
            SELECT point '(1,2)' <% widget '(0,0,3)' AS t, point '(1,2)' <%
widget '(0,0,1)' AS f
            ) as subq(subq_c0, subq_c1)
            ) order by c0 asc, c1 asc limit 1 offset 0)) then 0 else
ref_0.vkey end))
    and (not ('2147483648' = (
      select c0
      from (
        select cast(subq_c0 as text) as c0
        from (SELECT 0o20000000000) as subq(subq_c0))
      order by c0 asc limit 1 offset 0)));

--- Expected behavior ---
PostgreSQL server should not crash.

--- Actual behavior ---
PostgreSQL server crashes.

--- Postgres version ---
Github commit: 2a67b5a60ee68892bb028587ddc6de7650822480
Version:  PostgreSQL 17devel on x86_64-pc-linux-gnu, compiled by clang
version 10.0.0-4ubuntu1 , 64-bit

--- Platform information ---
Platform: Ubuntu 20.04
Kernel: Linux 5.4.0-147-generic

--- Bug report from from ASan ---
=================================================================
==90==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x62d000102400 at pc 0x00000051ea5a bp 0x7ffe8eaab580 sp 0x7ffe8eaaad48
READ of size 800042927 at 0x62d000102400 thread T0
    #0 0x51ea59 in __asan_memcpy (/usr/local/pgsql/bin/postgres+0x51ea59)
    #1 0x1acceb2 in datumCopy
/home/zuming/postgres/src/backend/utils/adt/datum.c:163:4
    #2 0x1153f0d in _copyConst
/home/zuming/postgres/src/backend/nodes/copyfuncs.c:95:25
    #3 0x11503a2 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/./copyfuncs.switch.c:34:13
    #4 0x1205b8d in list_copy_deep
/home/zuming/postgres/src/backend/nodes/list.c:1651:4
    #5 0x1151ca7 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/copyfuncs.c:192:13
    #6 0x1157494 in _copyOpExpr
/home/zuming/postgres/src/backend/nodes/./copyfuncs.funcs.c:263:2
    #7 0x115044a in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/./copyfuncs.switch.c:58:13
    #8 0x115fddb in _copyTargetEntry
/home/zuming/postgres/src/backend/nodes/./copyfuncs.funcs.c:810:2
    #9 0x115077d in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/./copyfuncs.switch.c:175:13
    #10 0x1205b8d in list_copy_deep
/home/zuming/postgres/src/backend/nodes/list.c:1651:4
    #11 0x1151ca7 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/copyfuncs.c:192:13
    #12 0x1161f7b in _copyQuery
/home/zuming/postgres/src/backend/nodes/./copyfuncs.funcs.c:904:2
    #13 0x11507e6 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/./copyfuncs.switch.c:190:13
    #14 0x116a27f in _copyRangeTblEntry
/home/zuming/postgres/src/backend/nodes/./copyfuncs.funcs.c:1384:2
    #15 0x1150ab0 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/./copyfuncs.switch.c:292:13
    #16 0x1205b8d in list_copy_deep
/home/zuming/postgres/src/backend/nodes/list.c:1651:4
    #17 0x1151ca7 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/copyfuncs.c:192:13
    #18 0x1161c72 in _copyQuery
/home/zuming/postgres/src/backend/nodes/./copyfuncs.funcs.c:899:2
    #19 0x11507e6 in copyObjectImpl
/home/zuming/postgres/src/backend/nodes/./copyfuncs.switch.c:190:13
    #20 0x14fe377 in pull_up_simple_subquery
/home/zuming/postgres/src/backend/optimizer/prep/prepjointree.c:974:13
    #21 0x14f16c9 in pull_up_subqueries_recurse
/home/zuming/postgres/src/backend/optimizer/prep/prepjointree.c:838:11
    #22 0x14f1da9 in pull_up_subqueries_recurse
/home/zuming/postgres/src/backend/optimizer/prep/prepjointree.c:885:16
    #23 0x14f11c4 in pull_up_subqueries
/home/zuming/postgres/src/backend/optimizer/prep/prepjointree.c:774:3
    #24 0x14729ef in subquery_planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:723:2
    #25 0x14dfa67 in make_subplan
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:221:12
    #26 0x14d4b6b in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:1949:10
    #27 0x12248ba in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:3384:12
    #28 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #29 0x122121b in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:2972:5
    #30 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #31 0x1222681 in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:3147:5
    #32 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #33 0x12248ba in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:3384:12
    #34 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #35 0x12224d7 in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:3136:5
    #36 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #37 0x12248ba in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:3384:12
    #38 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #39 0x122121b in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:2972:5
    #40 0x14d5a41 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2051:9
    #41 0x14d5318 in process_sublinks_mutator
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:2015:13
    #42 0x14d45dd in SS_process_sublinks
/home/zuming/postgres/src/backend/optimizer/plan/subselect.c:1922:9
    #43 0x14797a3 in preprocess_expression
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:1191:10
    #44 0x1479eb0 in preprocess_qual_conditions
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:1236:14
    #45 0x1474072 in subquery_planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:854:2
    #46 0x146e7ab in standard_planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:413:9
    #47 0x146dabb in planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:281:12
    #48 0x19476f5 in pg_plan_query
/home/zuming/postgres/src/backend/tcop/postgres.c:903:9
    #49 0x1948151 in pg_plan_queries
/home/zuming/postgres/src/backend/tcop/postgres.c:995:11
    #50 0x194f70e in exec_simple_query
/home/zuming/postgres/src/backend/tcop/postgres.c:1192:19
    #51 0x194dcb9 in PostgresMain
/home/zuming/postgres/src/backend/tcop/postgres.c:4653:7
    #52 0x16526e7 in BackendRun
/home/zuming/postgres/src/backend/postmaster/postmaster.c:4464:2
    #53 0x164bd3c in BackendStartup
/home/zuming/postgres/src/backend/postmaster/postmaster.c:4140:3
    #54 0x1647253 in ServerLoop
/home/zuming/postgres/src/backend/postmaster/postmaster.c:1776:6
    #55 0x1644ce5 in PostmasterMain
/home/zuming/postgres/src/backend/postmaster/postmaster.c:1475:11
    #56 0x114acde in main
/home/zuming/postgres/src/backend/main/main.c:198:3
    #57 0x7f2c00a79082 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x24082)
    #58 0x4a6ecd in _start (/usr/local/pgsql/bin/postgres+0x4a6ecd)

0x62d000102400 is located 0 bytes to the right of 32768-byte region
[0x62d0000fa400,0x62d000102400)
allocated by thread T0 here:
    #0 0x51f60d in malloc (/usr/local/pgsql/bin/postgres+0x51f60d)
    #1 0x2080712 in AllocSetAlloc
/home/zuming/postgres/src/backend/utils/mmgr/aset.c:928:24
    #2 0x209ed66 in palloc
/home/zuming/postgres/src/backend/utils/mmgr/mcxt.c:1202:8
    #3 0x11f9d23 in new_list
/home/zuming/postgres/src/backend/nodes/list.c:136:21
    #4 0x11fac78 in lappend
/home/zuming/postgres/src/backend/nodes/list.c:343:10
    #5 0x12248c9 in expression_tree_mutator_impl
/home/zuming/postgres/src/backend/nodes/nodeFuncs.c:3383:19
    #6 0x15451ea in simplify_function
/home/zuming/postgres/src/backend/optimizer/util/clauses.c:4061:19
    #7 0x15347e0 in eval_const_expressions_mutator
/home/zuming/postgres/src/backend/optimizer/util/clauses.c:2617:14
    #8 0x15464e8 in simplify_and_arguments
/home/zuming/postgres/src/backend/optimizer/util/clauses.c:3890:9
    #9 0x1536ecf in eval_const_expressions_mutator
/home/zuming/postgres/src/backend/optimizer/util/clauses.c:2849:18
    #10 0x1531c1c in eval_const_expressions
/home/zuming/postgres/src/backend/optimizer/util/clauses.c:2249:9
    #11 0x14796c6 in preprocess_expression
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:1164:10
    #12 0x1479eb0 in preprocess_qual_conditions
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:1236:14
    #13 0x1474072 in subquery_planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:854:2
    #14 0x146e7ab in standard_planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:413:9
    #15 0x146dabb in planner
/home/zuming/postgres/src/backend/optimizer/plan/planner.c:281:12
    #16 0x19476f5 in pg_plan_query
/home/zuming/postgres/src/backend/tcop/postgres.c:903:9
    #17 0x1948151 in pg_plan_queries
/home/zuming/postgres/src/backend/tcop/postgres.c:995:11
    #18 0x194f70e in exec_simple_query
/home/zuming/postgres/src/backend/tcop/postgres.c:1192:19
    #19 0x194dcb9 in PostgresMain
/home/zuming/postgres/src/backend/tcop/postgres.c:4653:7
    #20 0x16526e7 in BackendRun
/home/zuming/postgres/src/backend/postmaster/postmaster.c:4464:2
    #21 0x164bd3c in BackendStartup
/home/zuming/postgres/src/backend/postmaster/postmaster.c:4140:3
    #22 0x1647253 in ServerLoop
/home/zuming/postgres/src/backend/postmaster/postmaster.c:1776:6
    #23 0x1644ce5 in PostmasterMain
/home/zuming/postgres/src/backend/postmaster/postmaster.c:1475:11
    #24 0x114acde in main
/home/zuming/postgres/src/backend/main/main.c:198:3
    #25 0x7f2c00a79082 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x24082)

SUMMARY: AddressSanitizer: heap-buffer-overflow
(/usr/local/pgsql/bin/postgres+0x51ea59) in __asan_memcpy
Shadow bytes around the buggy address:
  0x0c5a80018430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5a80018440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5a80018450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5a80018460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5a80018470: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c5a80018480:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5a80018490: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5a800184a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5a800184b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5a800184c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5a800184d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==90==ABORTING


Hi Zuming!

Thanks for reporting this suspicious ASan alarm.

> On 7 Jan 2024, at 22:50, PG Bug reporting form <noreply@postgresql.org> wrote:
>
> --- Compile Postgres with ASan ---
> ./configure CC=clang CFLAGS="-fsanitize=address -fno-omit-frame-pointer -g"
> LDFLAGS="-fsanitize=address"
> make -j
> make install

I've tried to reproduce the problem. And my system does not pass regressions tests at all with these flags. Maybe I'm
doingsomething wrong. 
Does your system pass `make check`?


Best regards, Andrey Borodin.


Hi Andrey Borodin,
I've tried to reproduce the problem. And my system does not pass regressions tests at all with these flags. Maybe I'm doing something wrong. Does your system pass `make check`?
My system pass the regression test with these flags. FYI, I used clang 10. Best wishes, Zuming
PG Bug reporting form <noreply@postgresql.org> writes:
> My fuzzer finds a heap-buffer-overflow bug in PostgreSQL 17devel, which
> makes PostgreSQL crash.

All I see here is a datatype declaration that doesn't match what the
C functions expect.  You wrote:

> CREATE TYPE widget (
>    input = widget_in,
>    output = widget_out,
>    alignment = double
> );

but the declaration that the regress.so functions expect is what's in
src/test/regress/sql/create_type.sql:

CREATE TYPE widget (
   internallength = 24,
   input = widget_in,
   output = widget_out,
   typmod_in = numerictypmodin,
   typmod_out = numerictypmodout,
   alignment = double
);

That is, widget_in expects it should produce a fixed-length Datum
(24 bytes long, with no length word).  But you declared the type
as variable-length, meaning that datumCopy expects to find a length
word.  That discrepancy leads directly to the reported crash.

            regards, tom lane



Thank you for figuring out the problem, Tom!

but the declaration that the regress.so functions expect is what's in
src/test/regress/sql/create_type.sql:

CREATE TYPE widget (   internallength = 24,   input = widget_in,   output = widget_out,   typmod_in = numerictypmodin,   typmod_out = numerictypmodout,   alignment = double
);

After using the correct type you mentioned, the test case does not trigger crash anymore.

But I am bit wondering whether it is a bug. I think PostgreSQL should not directly crash because of a incorrect datatype. Maybe PostgreSQL can return an error?

Best wishes,
Zuming


From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
Sent: Sunday, January 7, 2024 at 8:16 PM
Subject: BUG #18276: Heap-buffer-overflow triggered in src/backend/utils/adt/datum.c:163

PG Bug reporting form <noreply@postgresql.org> writes:
My fuzzer finds a heap-buffer-overflow bug in PostgreSQL 17devel, which
makes PostgreSQL crash.
All I see here is a datatype declaration that doesn't match what the
C functions expect.  You wrote:

CREATE TYPE widget (   input = widget_in,   output = widget_out,   alignment = double
);
but the declaration that the regress.so functions expect is what's in
src/test/regress/sql/create_type.sql:

CREATE TYPE widget (   internallength = 24,   input = widget_in,   output = widget_out,   typmod_in = numerictypmodin,   typmod_out = numerictypmodout,   alignment = double
);

That is, widget_in expects it should produce a fixed-length Datum
(24 bytes long, with no length word).  But you declared the type
as variable-length, meaning that datumCopy expects to find a length
word.  That discrepancy leads directly to the reported crash.
			regards, tom lane

Zu-Ming Jiang <zuming.jiang@inf.ethz.ch> writes:
> But I am bit wondering whether it is a bug. I think PostgreSQL should 
> not directly crash because of a incorrect datatype. Maybe PostgreSQL can 
> return an error?

It's not reasonable to expect the system to figure out the behavior
of C functions (see: halting problem).  In the end this is why
creating base types is a superuser-only operation: it's possible
to crash the server with a wrong definition.  I don't see any prospect
of making that meaningfully safer.

            regards, tom lane



Thanks for the feedback!

It's not reasonable to expect the system to figure out the behavior
of C functions (see: halting problem).  In the end this is why
creating base types is a superuser-only operation: it's possible
to crash the server with a wrong definition.  I don't see any prospect
of making that meaningfully safer.

I will adjust my fuzzer to avoid such issues.

Best wishes,
Zuming