Thread

  1. BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always

    PG Bug reporting form <noreply@postgresql.org> — 2025-05-12T09:51:21Z

    The following bug has been logged on the website:
    
    Bug reference:      18925
    Logged by:          Stanislav Osipov
    Email address:      stasos24@gmail.com
    PostgreSQL version: 17.5
    Operating system:   Ubuntu 22
    Description:        
    
    Although pglz_compress is not used with pglz_stategy_always.
    It might be useful in future
    Source code:
    ```
    #include "postgres.h"
    #include "common/pg_lzcompress.h"
    #include "mb/pg_wchar.h"
    #include "utils/memutils.h"
    #include "utils/memdebug.h"
    #include "miscadmin.h"
    extern pg_stack_base_t set_stack_base(void);
    int FuzzerInitialize(char *dbname, char ***argv);
    extern bool             log_checkpoints;
    int LLVMFuzzerInitialize(int *argc, char ***argv) {
            FuzzerInitialize("compress_db", argv);
            return 0;
    }
    /*
    ** Main entry point.  The fuzzer invokes this function with each
    ** fuzzed input.
    */
    int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
            if (size < 1) return 1;
            log_checkpoints = false;
            sigjmp_buf local_sigjmp_buf;
            char *buffer;
            char *comp;
            char *decomp;
            int comp_bytes;
            buffer = (char *) calloc(size+1, sizeof(char));
            memcpy(buffer, data, size);
            comp = (char *) calloc(size+1, sizeof(char));
            decomp = (char *) calloc(size+1, sizeof(char));
            MemoryContextInit();
            set_stack_base();
            if(!sigsetjmp(local_sigjmp_buf,0)){
                    error_context_stack = NULL;
                    comp_bytes = pglz_compress(buffer, size + 1, comp,
    PGLZ_strategy_always);
                    pglz_decompress(comp, comp_bytes, decomp,
                                    size+1, false);
            }
            free(buffer);
            free(comp);
            free(decomp);
            FlushErrorState();
            MemoryContextReset(TopMemoryContext);
            TopMemoryContext->ident = NULL;
            TopMemoryContext->methods->delete_context(TopMemoryContext);
            VALGRIND_DESTROY_MEMPOOL(TopMemoryContext);
            return 0;
    }
    ```
    Input:
    ```
    ZZZ▒ZC
    ```
    Asan Report:
    ==7101==ERROR: AddressSanitizer: heap-buffer-overflow on address
    0x602000011a3a at pc 0x000002593c29 bp 0x7fff7277f850 sp 0x7fff7277f848
    WRITE of size 1 at 0x602000011a3a thread T0
        #0 0x2593c28 in pglz_compress /db/src/common/pg_lzcompress.c:656:4
        #1 0x5751c1 in LLVMFuzzerTestOneInput (/fuzz/compress_fuzzer+0x5751c1)
        #2 0x4a8d23 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*,
    unsigned long) (/fuzz/compress_fuzzer+0x4a8d23)
        #3 0x491b6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned
    long) (/fuzz/compress_fuzzer+0x491b6f)
        #4 0x497df0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char
    const*, unsigned long)) (/fuzz/compress_fuzzer+0x497df0)
        #5 0x4c3962 in main (/fuzz/compress_fuzzer+0x4c3962)
        #6 0x7f5b2bf55d8f in __libc_start_call_main
    csu/../sysdeps/nptl/libc_start_call_main.h:58:16
        #7 0x7f5b2bf55e3f in __libc_start_main csu/../csu/libc-start.c:392:3
        #8 0x48beb4 in _start (/fuzz/compress_fuzzer+0x48beb4)
    0x602000011a3a is located 0 bytes to the right of 10-byte region
    [0x602000011a30,0x602000011a3a)
    allocated by thread T0 here:
        #0 0x540922 in __interceptor_calloc (/fuzz/compress_fuzzer+0x540922)
        #1 0x5750a1 in LLVMFuzzerTestOneInput (/fuzz/compress_fuzzer+0x5750a1)
        #2 0x4a8d23 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*,
    unsigned long) (/fuzz/compress_fuzzer+0x4a8d23)
        #3 0x491b6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned
    long) (/fuzz/compress_fuzzer+0x491b6f)
        #4 0x497df0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char
    const*, unsigned long)) (/fuzz/compress_fuzzer+0x497df0)
        #5 0x4c3962 in main (/fuzz/compress_fuzzer+0x4c3962)
        #6 0x7f5b2bf55d8f in __libc_start_call_main
    csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    SUMMARY: AddressSanitizer: heap-buffer-overflow
    /db/src/common/pg_lzcompress.c:656:4 in pglz_compress
    Shadow bytes around the buggy address:
      0x0c047fffa2f0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
      0x0c047fffa300: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
      0x0c047fffa310: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
      0x0c047fffa320: fa fa 00 04 fa fa 00 05 fa fa 00 03 fa fa 00 00
      0x0c047fffa330: fa fa 00 00 fa fa 00 00 fa fa 00 01 fa fa 00 01
    =>0x0c047fffa340: fa fa 00 02 fa fa 00[02]fa fa 00 02 fa fa fa fa
      0x0c047fffa350: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fffa360: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fffa370: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fffa380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c047fffa390: 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
    ==7101==ABORTING
    
    
  2. Re: BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always

    Dilip Kumar <dilipbalaut@gmail.com> — 2025-05-13T14:22:37Z

    On Tue, May 13, 2025 at 7:34 PM PG Bug reporting form
    <noreply@postgresql.org> wrote:
    >
    > The following bug has been logged on the website:
    >
    > Bug reference:      18925
    > Logged by:          Stanislav Osipov
    > Email address:      stasos24@gmail.com
    > PostgreSQL version: 17.5
    > Operating system:   Ubuntu 22
    > Description:
    >
    > Although pglz_compress is not used with pglz_stategy_always.
    > It might be useful in future
    > Source code:
    > ```
    > #include "postgres.h"
    > #include "common/pg_lzcompress.h"
    > #include "mb/pg_wchar.h"
    > #include "utils/memutils.h"
    > #include "utils/memdebug.h"
    > #include "miscadmin.h"
    > extern pg_stack_base_t set_stack_base(void);
    > int FuzzerInitialize(char *dbname, char ***argv);
    > extern bool             log_checkpoints;
    > int LLVMFuzzerInitialize(int *argc, char ***argv) {
    >         FuzzerInitialize("compress_db", argv);
    >         return 0;
    > }
    > /*
    > ** Main entry point.  The fuzzer invokes this function with each
    > ** fuzzed input.
    > */
    > int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    >         if (size < 1) return 1;
    >         log_checkpoints = false;
    >         sigjmp_buf local_sigjmp_buf;
    >         char *buffer;
    >         char *comp;
    >         char *decomp;
    >         int comp_bytes;
    >         buffer = (char *) calloc(size+1, sizeof(char));
    >         memcpy(buffer, data, size);
    >         comp = (char *) calloc(size+1, sizeof(char));
    >         decomp = (char *) calloc(size+1, sizeof(char));
    >         MemoryContextInit();
    >         set_stack_base();
    >         if(!sigsetjmp(local_sigjmp_buf,0)){
    >                 error_context_stack = NULL;
    >                 comp_bytes = pglz_compress(buffer, size + 1, comp,
    > PGLZ_strategy_always);
    >                 pglz_decompress(comp, comp_bytes, decomp,
    >                                 size+1, false);
    >         }
    >         free(buffer);
    >         free(comp);
    >         free(decomp);
    >         FlushErrorState();
    >         MemoryContextReset(TopMemoryContext);
    >         TopMemoryContext->ident = NULL;
    >         TopMemoryContext->methods->delete_context(TopMemoryContext);
    >         VALGRIND_DESTROY_MEMPOOL(TopMemoryContext);
    >         return 0;
    > }
    > ```
    > Input:
    > ```
    > ZZZ▒ZC
    > ```
    > Asan Report:
    > ==7101==ERROR: AddressSanitizer: heap-buffer-overflow on address
    > 0x602000011a3a at pc 0x000002593c29 bp 0x7fff7277f850 sp 0x7fff7277f848
    > WRITE of size 1 at 0x602000011a3a thread T0
    >     #0 0x2593c28 in pglz_compress /db/src/common/pg_lzcompress.c:656:4
    >     #1 0x5751c1 in LLVMFuzzerTestOneInput (/fuzz/compress_fuzzer+0x5751c1)
    >     #2 0x4a8d23 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*,
    > unsigned long) (/fuzz/compress_fuzzer+0x4a8d23)
    >     #3 0x491b6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned
    > long) (/fuzz/compress_fuzzer+0x491b6f)
    >     #4 0x497df0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char
    > const*, unsigned long)) (/fuzz/compress_fuzzer+0x497df0)
    >     #5 0x4c3962 in main (/fuzz/compress_fuzzer+0x4c3962)
    >     #6 0x7f5b2bf55d8f in __libc_start_call_main
    > csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    >     #7 0x7f5b2bf55e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    >     #8 0x48beb4 in _start (/fuzz/compress_fuzzer+0x48beb4)
    > 0x602000011a3a is located 0 bytes to the right of 10-byte region
    > [0x602000011a30,0x602000011a3a)
    > allocated by thread T0 here:
    >     #0 0x540922 in __interceptor_calloc (/fuzz/compress_fuzzer+0x540922)
    >     #1 0x5750a1 in LLVMFuzzerTestOneInput (/fuzz/compress_fuzzer+0x5750a1)
    >     #2 0x4a8d23 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*,
    > unsigned long) (/fuzz/compress_fuzzer+0x4a8d23)
    >     #3 0x491b6f in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned
    > long) (/fuzz/compress_fuzzer+0x491b6f)
    >     #4 0x497df0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char
    > const*, unsigned long)) (/fuzz/compress_fuzzer+0x497df0)
    >     #5 0x4c3962 in main (/fuzz/compress_fuzzer+0x4c3962)
    >     #6 0x7f5b2bf55d8f in __libc_start_call_main
    > csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    > SUMMARY: AddressSanitizer: heap-buffer-overflow
    > /db/src/common/pg_lzcompress.c:656:4 in pglz_compress
    > Shadow bytes around the buggy address:
    >   0x0c047fffa2f0: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
    >   0x0c047fffa300: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
    >   0x0c047fffa310: fa fa 00 00 fa fa 00 00 fa fa 00 00 fa fa 00 00
    >   0x0c047fffa320: fa fa 00 04 fa fa 00 05 fa fa 00 03 fa fa 00 00
    >   0x0c047fffa330: fa fa 00 00 fa fa 00 00 fa fa 00 01 fa fa 00 01
    > =>0x0c047fffa340: fa fa 00 02 fa fa 00[02]fa fa 00 02 fa fa fa fa
    >   0x0c047fffa350: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    >   0x0c047fffa360: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    >   0x0c047fffa370: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    >   0x0c047fffa380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    >   0x0c047fffa390: 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
    > ==7101==ABORTING
    >
    
    Do you have a reproducible test case or steps to hit this issue?
    
    -- 
    Regards,
    Dilip Kumar
    EnterpriseDB: http://www.enterprisedb.com
    
    
    
    
  3. Re: BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always

    Daniel Gustafsson <daniel@yesql.se> — 2025-05-14T19:35:08Z

    > On 13 May 2025, at 10:22, Dilip Kumar <dilipbalaut@gmail.com> wrote:
    > On Tue, May 13, 2025 at 7:34 PM PG Bug reporting form
    > <noreply@postgresql.org> wrote:
    
    >> Although pglz_compress is not used with pglz_stategy_always.
    >> It might be useful in future
    
    > Do you have a reproducible test case or steps to hit this issue?
    
    The way I read it there is now way to reproduce this as the codepath used in
    the fuzzer ins't present in postgres (PGLZ_strategy_always is not used by any
    callsite).
    
    Whether or not there is a bug in the compression code, or PGLZ_strategy_always
    being incorrectly defined, or none of the above, remains to be seen.
    
    --
    Daniel Gustafsson
    
    
    
    
    
  4. Re: BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always

    Tom Lane <tgl@sss.pgh.pa.us> — 2025-05-31T23:46:25Z

    Daniel Gustafsson <daniel@yesql.se> writes:
    > The way I read it there is now way to reproduce this as the codepath used in
    > the fuzzer ins't present in postgres (PGLZ_strategy_always is not used by any
    > callsite).
    > Whether or not there is a bug in the compression code, or PGLZ_strategy_always
    > being incorrectly defined, or none of the above, remains to be seen.
    
    I think the bug is in the test program: it's allocating an output
    buffer of the same size as the input buffer.  This does not conform
    to the API spec for pglz_compress:
    
     *            int32
     *            pglz_compress(const char *source, int32 slen, char *dest,
     *                          const PGLZ_Strategy *strategy);
     *
     *                source is the input data to be compressed.
     *
     *                slen is the length of the input data.
     *
     *                dest is the output area for the compressed result.
     *                    It must be at least as big as PGLZ_MAX_OUTPUT(slen).
    
    PGLZ_MAX_OUTPUT adds 4 bytes to the size, which the test program
    is not doing, so an output buffer overrun can be expected
    no matter which strategy is selected.
    
    			regards, tom lane