-
Notifications
You must be signed in to change notification settings - Fork 396
Description
Hi, there is a potential issue with policydb_from_image.
This bug was reproduced on dcdafad.
Description
The policydb_from_image function takes a new policydb_t argument to initialize. However in the case that the function fails (i.e. due to an invalid image), policydb_from_image invokes policydb_destroy directly, but does not zero out the policydb_t pointer.
This behavior is not documented, and users might expect that the caller is responsible for invoking policydb_destroy, which results in a use-after-free.
A simple solution here could be to zero-out the policydb_t argument when destroying (probably in policydb_destroy rather than conditionally in policydb_from_image). There is already a null pointer check in policydb_destroy so a second attempted destroy (from the caller) would become a nop.
POC
The following testcase demonstrates the bug:
testcase.cpp
#include <cstring>
extern "C" {
#include "/fuzz/install/include/sepol/handle.h"
#include "/fuzz/install/include/sepol/policydb/policydb.h"
}
int main(){
sepol_handle_t *h = sepol_handle_create();
if(!h) return 0;
policydb_t p; if(policydb_init(&p)!=0) return 0;
// Benign constant buffer; parse will fail but allocates internal tables
unsigned char buf[136] = {0};
const char magic[] = "SE Linux!"; // ASCII header, not expected magic
memcpy(buf, magic, sizeof(magic)-1);
(void)policydb_from_image(h, buf, sizeof(buf), &p); // returns error
// Triggers heap-use-after-free in symtabs_destroy -> hashtab_map
policydb_destroy(&p);
return 0;
}
stdout
stderr
libsepol.policydb_read: policydb magic number 0x4c204553 does not match expected magic number 0xf97cff8c or 0xf97cff8d
libsepol.policydb_from_image: policy image is invalid
=================================================================
==1==ERROR: AddressSanitizer: heap-use-after-free on address 0x503000000048 at pc 0x55fa48e7822b bp 0x7fffcfd444b0 sp 0x7fffcfd444a8
READ of size 4 at 0x503000000048 thread T0
#0 0x55fa48e7822a in hashtab_map (/fuzz/test+0x18c22a) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
#1 0x55fa48e01e9d in symtabs_destroy (/fuzz/test+0x115e9d) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
#2 0x55fa48e00f56 in policydb_destroy (/fuzz/test+0x114f56) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
#3 0x55fa48dfe64a in main /fuzz/testcase.cpp:16:5
#4 0x7f7bc966bd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#5 0x7f7bc966be3f in __libc_start_main csu/../csu/libc-start.c:392:3
#6 0x55fa48d23314 in _start (/fuzz/test+0x37314) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
0x503000000048 is located 8 bytes inside of 32-byte region [0x503000000040,0x503000000060)
freed by thread T0 here:
#0 0x55fa48dbf416 in free (/fuzz/test+0xd3416) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
#1 0x55fa48e01eb3 in symtabs_destroy (/fuzz/test+0x115eb3) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
#2 0x55fa48dfe641 in main /fuzz/testcase.cpp:14:11
#3 0x7f7bc966bd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
previously allocated by thread T0 here:
#0 0x55fa48dbf6be in malloc (/fuzz/test+0xd36be) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
#1 0x55fa48e774f8 in hashtab_create (/fuzz/test+0x18b4f8) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef)
SUMMARY: AddressSanitizer: heap-use-after-free (/fuzz/test+0x18c22a) (BuildId: 04031bba3eb95d32c3bedf5f81f619ef0457bbef) in hashtab_map
Shadow bytes around the buggy address:
0x502ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x502ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x502ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x502fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x502fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x503000000000: fa fa 00 00 00 fa fa fa fd[fd]fd fd fa fa fd fd
0x503000000080: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
0x503000000100: fd fd fd fd fa fa fd fd fd fd fa fa fd fd fd fd
0x503000000180: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
0x503000000200: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
0x503000000280: fd fd fd fd fa fa fd fd fd fd fa fa fd fd fd fd
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/SELinuxProject/selinux /fuzz/src && \
cd /fuzz/src && \
git checkout dcdafad74862d7aae8958a59d4022b519227df65 && \
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 deps (none needed beyond what's in base for static libsepol)
# Keep image small; avoid unnecessary packages. We disable CIL and shared libs to avoid flex/bison.
WORKDIR /fuzz/src
# Build and install only libsepol as a static library
ENV CC=clang_wrapper
ENV CXX=clang_wrapper++
RUN make -C libsepol clean || true \
&& make -C libsepol \
DISABLE_SHARED=y \
DISABLE_CIL=y \
PREFIX=/fuzz/install \
CC=${CC} \
install
ENV PKG_CONFIG_PATH=/fuzz/install/lib/pkgconfig
ENV LD_LIBRARY_PATH=/fuzz/install/lib:$LD_LIBRARY_PATHBuild Command
clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/install/include -L/fuzz/install/lib -lsepol && /fuzz/testReproduce
- Copy
Dockerfileandtestcase.cppinto 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 -lsepol && /fuzz/test"Additional Info
This testcase was discovered by STITCH, an autonomous fuzzing system. All reports are reviewed manually (by a human) before submission.