| From: | Ilia Kashintsev <ilia(dot)kashintsev(at)gmail(dot)com> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Subject: | pg_restore: stack-buffer-overflow(read) in _tarGetHeader() in pg_backup_tar.c |
| Date: | 2026-08-20 13:22:52 |
| Message-ID: | CAF6ebR508tkZ1729YQVZJgMN-8pBDGWp7Mw=4UKJ6-Hx3ngyTw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
Hello maintainers!
security@ checked this report and found it to be not a vuln,
since "The OOB read only affects the return value of strlcpy(),
and this caller ignores that return value".
There is a stack-buffer-overflow on unknown address in _tarGetHeader().
It occurs because strlcpy() is being called with src as an argument,
which, according to the comment on line 1167, might not be null-terminated.
In order to calculate its return value, strlcpy is going to walk
through src until '\0', which is missing, resulting in OOB read.
pg_backup_tar.c:1167-1168:
/* Name field is 100 bytes, might not be null-terminated */
strlcpy(tag, &h[TAR_OFFSET_NAME], 100 + 1); <------
Information from the bug reporting form:
PostgreSQL version: 19beta2
Operating system: Ubuntu 24.04.4 LTS
Steps to reproduce:
1)
Build the project with ASAN,
ensure sanitized src/port/strlcpy.c is being used;
sudo mkdir -p /builds2
sudo chown "$(whoami)" /builds2
mkdir -p asan_build
cd asan_build
export CC=clang
export CXX=clang++
export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
export CXXFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
export LDFLAGS="-fsanitize=address"
../postgres/configure --prefix=/builds2/pg-asan ac_cv_func_strlcpy=no
ac_cv_have_decl_strlcpy=no
make -j
sudo make install
2) Run the example:
echo 'dG8wNzJhdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDA2NDQAMDAwMDAw
MAAwMDAwMDAwADAwMDAwMDAwMDczADAwMDAwMDAwMDAwADAwNzIyNAAwMAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw'
| base64 -d > inp.bin
/builds2/pg-asan/bin/pg_restore -f dump.sql inp.bin
Sanitizer output:
==264230==ERROR: AddressSanitizer: stack-buffer-overflow on address
0x764aa7100a20 at pc 0x56bb55abde12 bp 0x7ffe83d4a890 sp
0x7ffe83d4a888
READ of size 1 at 0x764aa7100a20 thread T0
#0 0x56bb55abde11 in strlcpy
/home/reproduce/asan_build/../postgres/src/port/strlcpy.c:66:10
#1 0x56bb55aac83b in _tarGetHeader
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_tar.c:1168:2
#2 0x56bb55aab7ac in _tarPositionTo
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_tar.c:1102:8
#3 0x56bb55aab7ac in tarOpen
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_tar.c:309:8
#4 0x56bb55aa93de in InitArchiveFmt_Tar
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_tar.c:222:13
#5 0x56bb55a8b4ff in _allocAH
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_archiver.c:2482:4
#6 0x56bb55a8bb0e in OpenArchive
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_archiver.c:254:7
#7 0x56bb55a7c631 in main
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_restore.c:488:7
#8 0x764aa8cd41c9 in __libc_start_call_main
csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#9 0x764aa8cd428a in __libc_start_main csu/../csu/libc-start.c:360:3
#10 0x56bb559a1974 in _start
(/builds2/pg-asan/bin/pg_restore+0x43974) (BuildId:
b54d44745ecb5f358a7ac913ad08b66dda84c596)
Address 0x764aa7100a20 is located in stack of thread T0 at offset 544 in frame
#0 0x56bb55aac5ff in _tarGetHeader
/home/reproduce/asan_build/../postgres/src/bin/pg_dump/pg_backup_tar.c:1116
This frame has 2 object(s):
[32, 544) 'h' (line 1118) <== Memory access at offset 544
overflows this variable
[608, 709) 'tag' (line 1119)
HINT: this may be a false positive if your program uses some custom
stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow
/home/reproduce/asan_build/../postgres/src/port/strlcpy.c:66:10 in
strlcpy
Shadow bytes around the buggy address:
0x764aa7100780: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
0x764aa7100800: f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00 00 00
0x764aa7100880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x764aa7100900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x764aa7100980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x764aa7100a00: 00 00 00 00[f2]f2 f2 f2 f2 f2 f2 f2 00 00 00 00
0x764aa7100a80: 00 00 00 00 00 00 00 00 05 f3 f3 f3 f3 f3 f3 f3
0x764aa7100b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x764aa7100b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x764aa7100c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x764aa7100c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==264230==ABORTING
Suggested fix:
Not sure this is entirely correct, but bounded copy and explicit '\0'
resolves the issue.
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index 542fdb4..df3b3af 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -1165,7 +1165,8 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
}
/* Name field is 100 bytes, might not be null-terminated */
- strlcpy(tag, &h[TAR_OFFSET_NAME], 100 + 1);
+ memcpy(tag, &h[TAR_OFFSET_NAME], 100);
+ tag[100] = '\0';
len = read_tar_number(&h[TAR_OFFSET_SIZE], 12);
Best regards,
Ilia Kashintsev
| From | Date | Subject | |
|---|---|---|---|
| Previous Message | Heikki Linnakangas | 2026-08-20 13:19:23 | Re: SIGSEGV in dynahash |