Обсуждение: BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always
BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always
От
PG Bug reporting form
Дата:
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
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
Re: BUG #18925: Heap-buffer-overflow: pglz_compress with pglz_stategy_always
От
Daniel Gustafsson
Дата:
> 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
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