Hi, there is a potential bug in Simd::Base64Decode variants reachable by invalid Base64 strings.
This bug was reproduced on 3eec4f2.
Description
I found this crashing case while fuzzing, where providing a bad base64 string (i.e. too short or not aligned properly) results in memory corruption during execution.
Reading the code I see that there are assertions for this precondition:
|
assert(srcSize % 4 == 0 && srcSize >= 4); |
But these get removed when you build the library in release mode.
The documentation similarly doesn't really specify if these functions should be robust to invalid base64 or if it is always expected that users will pass valid strings. As a result, it seems likely that users may try to use this function for strings that are not guaranteed to be valid base64, in which case they may hit this memory corruption in release mode builds.
Two fairly simple solutions could be:
- add a comment in the documentation to the extent of "input must be valid base64"
- make these assertions runtime assertions that do not get removed in release builds
POC
The following testcase demonstrates the bug:
testcase.cpp
#include <string>
#include "/fuzz/install/include/Simd/SimdLib.hpp"
int main(){
// Minimal benign input that crashes: a single-character string
std::string s("A", 1);
auto out = Simd::Base64Decode(s);
(void)out;
return 0;
}
stdout
stderr
=================================================================
==1==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fa652800070 at pc 0x55d1b724e64d bp 0x7fffbb1dd440 sp 0x7fffbb1dd438
READ of size 1 at 0x7fa652800070 thread T0
#0 0x55d1b724e64c in Simd::Avx512bw::Base64Decode(unsigned char const*, unsigned long, unsigned char*, unsigned long*) (/fuzz/test+0x504564c) (BuildId: d9a5247ecda2b4d97869af3c5072080603d4fc2b)
#1 0x55d1b23ac0a8 in SimdBase64Decode (/fuzz/test+0x1a30a8) (BuildId: d9a5247ecda2b4d97869af3c5072080603d4fc2b)
#2 0x55d1b23a8ba8 in Simd::Base64Decode(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /fuzz/install/include/Simd/SimdLib.hpp:746:9
#3 0x55d1b23a8ba8 in main /fuzz/testcase.cpp:6:16
#4 0x7fa6543fad8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#5 0x7fa6543fae3f in __libc_start_main csu/../csu/libc-start.c:392:3
#6 0x55d1b22cd814 in _start (/fuzz/test+0xc4814) (BuildId: d9a5247ecda2b4d97869af3c5072080603d4fc2b)
Address 0x7fa652800070 is located in stack of thread T0 at offset 112 in frame
#0 0x55d1b23a891f in main /fuzz/testcase.cpp:3
This frame has 5 object(s):
[32, 40) 'dstSize.i'
[64, 65) 'ref.tmp.i'
[80, 112) 's' (line 5) <== Memory access at offset 112 overflows this variable
[144, 145) 'ref.tmp' (line 5)
[160, 192) 'out' (line 6)
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 (/fuzz/test+0x504564c) (BuildId: d9a5247ecda2b4d97869af3c5072080603d4fc2b) in Simd::Avx512bw::Base64Decode(unsigned char const*, unsigned long, unsigned char*, unsigned long*)
Shadow bytes around the buggy address:
0x7fa6527ffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa6527ffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa6527ffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa6527fff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa6527fff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7fa652800000: f1 f1 f1 f1 00 f2 f2 f2 f8 f2 00 00 00 00[f2]f2
0x7fa652800080: f2 f2 f8 f2 00 00 00 00 f3 f3 f3 f3 00 00 00 00
0x7fa652800100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa652800180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa652800200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7fa652800280: 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
==1==ABORTING
Steps to Reproduce
The crash was triaged with the following Dockerfile:
Dockerfile
# Ubuntu 22.04 with some packages pre-installed
FROM hgarrereyn/stitch_repro_base@sha256:3ae94cdb7bf2660f4941dc523fe48cd2555049f6fb7d17577f5efd32a40fdd2c
RUN git clone https://github.com/ermig1979/Simd /fuzz/src && \
cd /fuzz/src && \
git checkout 3eec4f29031abee11c294a35a279ebabf1ff1154 && \
git submodule update --init --remote --recursive
ENV LD_LIBRARY_PATH=/fuzz/install/lib
ENV ASAN_OPTIONS=hard_rss_limit_mb=1024:detect_leaks=0
RUN echo '#!/bin/bash\nexec clang-17 -fsanitize=address -O0 "$@"' > /usr/local/bin/clang_wrapper && \
chmod +x /usr/local/bin/clang_wrapper && \
echo '#!/bin/bash\nexec clang++-17 -fsanitize=address -O0 "$@"' > /usr/local/bin/clang_wrapper++ && \
chmod +x /usr/local/bin/clang_wrapper++
# Install minimal build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
cmake \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Configure, build and install Simd as a static library
WORKDIR /fuzz/build
ENV CC=clang_wrapper CXX=clang_wrapper++
RUN cmake -S /fuzz/src/prj/cmake -B . \
-DCMAKE_C_COMPILER=clang_wrapper \
-DCMAKE_CXX_COMPILER=clang_wrapper++ \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/fuzz/install \
-DSIMD_TEST=OFF \
-DSIMD_SHARED=OFF \
-DSIMD_PYTHON=OFF \
-DSIMD_OPENCV=OFF \
&& cmake --build . -j"$(nproc)" \
&& cmake --install .
Build Command
clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/install/include -L/fuzz/install/lib -lSimd -lpthread -lm -include climits && /fuzz/test
Reproduce
- Copy
Dockerfile and testcase.cpp into a local folder.
- Build the repro image:
docker build . -t repro --platform=linux/amd64
- Compile and run the testcase in the image:
docker run \
-it --rm \
--platform linux/amd64 \
--mount type=bind,source="$(pwd)/testcase.cpp",target=/fuzz/testcase.cpp \
repro \
bash -c "clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/install/include -L/fuzz/install/lib -lSimd -lpthread -lm -include climits && /fuzz/test"
Additional Info
This testcase was discovered by STITCH, an autonomous fuzzing system. All reports are reviewed manually (by a human) before submission.
Hi, there is a potential bug in
Simd::Base64Decodevariants reachable by invalid Base64 strings.This bug was reproduced on 3eec4f2.
Description
I found this crashing case while fuzzing, where providing a bad base64 string (i.e. too short or not aligned properly) results in memory corruption during execution.
Reading the code I see that there are assertions for this precondition:
Simd/src/Simd/SimdBaseBase64.cpp
Line 33 in 4b7ec69
But these get removed when you build the library in release mode.
The documentation similarly doesn't really specify if these functions should be robust to invalid base64 or if it is always expected that users will pass valid strings. As a result, it seems likely that users may try to use this function for strings that are not guaranteed to be valid base64, in which case they may hit this memory corruption in release mode builds.
Two fairly simple solutions could be:
POC
The following testcase demonstrates the bug:
testcase.cpp
stdout
stderr
Steps to Reproduce
The crash was triaged with the following Dockerfile:
Dockerfile
Build Command
clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/install/include -L/fuzz/install/lib -lSimd -lpthread -lm -include climits && /fuzz/testReproduce
Dockerfileandtestcase.cppinto a local folder.docker build . -t repro --platform=linux/amd64docker run \ -it --rm \ --platform linux/amd64 \ --mount type=bind,source="$(pwd)/testcase.cpp",target=/fuzz/testcase.cpp \ repro \ bash -c "clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/install/include -L/fuzz/install/lib -lSimd -lpthread -lm -include climits && /fuzz/test"Additional Info
This testcase was discovered by
STITCH, an autonomous fuzzing system. All reports are reviewed manually (by a human) before submission.