Skip to content

stack-buffer-overflow in decNumber#9019

Open
ChudaykinAlex wants to merge 1 commit intoFirebirdSQL:masterfrom
ChudaykinAlex:work/decNumber_stack_buffer_overflow
Open

stack-buffer-overflow in decNumber#9019
ChudaykinAlex wants to merge 1 commit intoFirebirdSQL:masterfrom
ChudaykinAlex:work/decNumber_stack_buffer_overflow

Conversation

@ChudaykinAlex
Copy link
Copy Markdown
Contributor

Background

The QA team was running fuzz testing on the decimal floating-point arithmetic routines in the decNumber library. Three stable crash scenarios were identified, each terminating with a stack-buffer-overflow error (READ of size 4).

Potentially on versions 3, 4, 5, and master


Affected files

File Line Function
lib/decBasic.c 1123, 1401 decFloatAdd / decQuadAdd
lib/decCommon.c 464 decFinalize (fold-down path)

How to reproduce

Clang

clang -g -O0 -fsanitize=address -I./lib \
    lib/decContext.c lib/decNumber.c lib/decDouble.c lib/decQuad.c \
    lib/decimal32.c lib/decimal64.c lib/decimal128.c lib/decPacked.c \
    poc.c -o poc_runner
./poc_runner 1   # or 2, 3

GCC

gcc -g -O0 -fsanitize=address -I./lib \
    lib/decContext.c lib/decNumber.c lib/decDouble.c lib/decQuad.c \
    lib/decimal32.c lib/decimal64.c lib/decimal128.c lib/decPacked.c \
    poc.c -o poc_runner
./poc_runner 1   # or 2, 3

All three cases crash consistently on the vulnerable code under ASan with both compilers.

poc.c


ASan stack traces

Case 1 — decQuadAdd
ERROR: AddressSanitizer: stack-buffer-overflow on address ... READ of size 4
    #0 decQuadAdd     lib/decBasic.c:1401
    #1 main           poc.c:27

[256, 330) 'buf' (line 1123) <== Memory access at offset 330 overflows this variable
Case 2 — decDoubleReduce
ERROR: AddressSanitizer: stack-buffer-overflow on address ... READ of size 4
    #0 decFinalize        lib/decCommon.c:464
    #1 decDoubleReduce    lib/decBasic.c:3213
    #2 main               poc.c:33

[96, 112) 'buf' (line 3192) <== Memory access at offset 112 overflows this variable
Case 3 — decQuadReduce
ERROR: AddressSanitizer: stack-buffer-overflow on address ... READ of size 4
    #0 decFinalize      lib/decCommon.c:464
    #1 decQuadReduce    lib/decBasic.c:3213
    #2 main             poc.c:39

[96, 130) 'buf' (line 3192) <== Memory access at offset 130 overflows this variable

Full
stack.txt


Changes

lib/decBasic.c — bug #1

The tail-copy loop in decFloatAdd reads 4 bytes at a time, but the buffer was declared without headroom for that read. Extended by 4 bytes:

// before
uByte buf[4+2+DECPMAX*2];
// after
uByte buf[4+2+DECPMAX*2+4];

lib/decCommon.c — bugs #2, #3

The fold-down loop in decFinalize performed a 4-byte read when s == ulsd, overflowing past the end of the caller's buffer. Split into a fast 4-byte pass (while safe) and a byte-wise tail:

// before
for (; s<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s));
// after
for (; s+3<=ulsd; s+=4, t+=4) UBFROMUI(t, UBTOUI(s));
for (; s<=ulsd; s++, t++) *t=*s;

Verification

=== CASE 1 === exit=0   ✓
=== CASE 2 === exit=0   ✓
=== CASE 3 === exit=0   ✓

Clean exit with no stack-buffer-overflow on both clang and gcc.

@ChudaykinAlex
Copy link
Copy Markdown
Contributor Author

@AlexPeshkoff Good day. Should I write a unit test?

@AlexPeshkoff
Copy link
Copy Markdown
Member

Should I write a unit test?

If you wish - please do. On the one hand result appears to be obvious, but additional test makes no harm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants