-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Hi, there is a potential bug in http_make_path reachable by invoking cupsCreateCredentials with root_name="".
This bug was reproduced on https://github.com/OpenPrinting/libcups.git/commit/881de116d71c695f125bf2d47acc3a988b9afaee.
Description
The failing code path is inside http_make_path (cups/tls.c) called from cupsCreateCredentials (tls-openssl.c). When assembling the filesystem path for the credential, the function computes a filename pointer and then unconditionally checks filename[-1] in the condition:
if (bufptr < bufend && filename[-1] != '.')
In cases where cupsCreateCredentials was invoked with a non-empty root_name, the filename pointer gets incremented before this. However, if it is "" then we end up dereferencing the byte before it.
I was not able to tell from the documentation whether it is legal to invoke cupsCreateCredentials in such a way. However, passing NULL is explicitly allowed and there's no mention that it cannot be the empty string.
POC
The following testcase demonstrates the bug:
testcase.cpp
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <cstring>
extern "C" {
#include "/fuzz/src/cups/cups.h"
}
int main(){
const char *path = "/tmp"; // writable directory
bool ca_cert = false;
cups_credpurpose_t purpose = (cups_credpurpose_t)0; // any value
cups_credtype_t type = CUPS_CREDTYPE_RSA_2048_SHA256;
cups_credusage_t usage = (cups_credusage_t)0;
// Subject fields: only CN provided; others NULL
const char *org = NULL, *orgu = NULL, *loc = NULL, *st = NULL, *c = NULL;
const char *cn = "A"; // minimal non-empty CN
const char *email = NULL;
size_t num_alt_names = 0; const char * const *alt_names = NULL;
const char *root_name = ""; // no root signer
time_t expiration = 0; // any value
(void)cupsCreateCredentials(path, ca_cert, purpose, type, usage,
org, orgu, loc, st, c,
cn, email, num_alt_names, alt_names,
root_name, expiration);
return 0;
}
stdout
=================================================================
==1==ERROR: AddressSanitizer: global-buffer-overflow on address 0x560505fb8bdf at pc 0x560505f56cae bp 0x7ffdb6d38db0 sp 0x7ffdb6d38da8
READ of size 1 at 0x560505fb8bdf thread T0
#0 0x560505f56cad in http_make_path /fuzz/src/cups/tls.c:717:26
#1 0x560505f55d78 in cupsCreateCredentials /fuzz/src/cups/./tls-openssl.c:341:3
#2 0x560505f552fa in main /fuzz/testcase.cpp:21:9
#3 0x7fd55b159d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#4 0x7fd55b159e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#5 0x560505e7a0a4 in _start (/fuzz/test+0x640a4) (BuildId: 8cd322b62f88c85b5d1f21d4f8807283ce809055)
0x560505fb8bdf is located 1 bytes before global variable '.str.2' defined in '/fuzz/testcase.cpp:19' (0x560505fb8be0) of size 1
'.str.2' is ascii string ''
0x560505fb8bdf is located 29 bytes after global variable '.str.1' defined in '/fuzz/testcase.cpp:16' (0x560505fb8bc0) of size 2
'.str.1' is ascii string 'A'
SUMMARY: AddressSanitizer: global-buffer-overflow /fuzz/src/cups/tls.c:717:26 in http_make_path
Shadow bytes around the buggy address:
0x560505fb8900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x560505fb8980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x560505fb8a00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x560505fb8a80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x560505fb8b00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x560505fb8b80: 00 00 00 00 05 f9 f9 f9 02 f9 f9[f9]01 f9 f9 f9
0x560505fb8c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x560505fb8c80: 03 f9 f9 f9 00 00 f9 f9 00 00 00 00 04 f9 f9 f9
0x560505fb8d00: f9 f9 f9 f9 07 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
0x560505fb8d80: 03 f9 f9 f9 00 00 00 00 00 00 05 f9 f9 f9 f9 f9
0x560505fb8e00: 00 00 00 03 f9 f9 f9 f9 00 00 00 04 f9 f9 f9 f9
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/OpenPrinting/libcups.git /fuzz/src && \
cd /fuzz/src && \
git checkout 881de116d71c695f125bf2d47acc3a988b9afaee && \
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 build dependencies
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
pkg-config \
libavahi-client-dev \
libnss-mdns \
libssl-dev \
zlib1g-dev \
libpng-dev \
ca-certificates \
make \
&& rm -rf /var/lib/apt/lists/*
# Provide a dummy pdfio pkg-config file so configure doesn't try to build the embedded submodule
# We won't build the tools that require PDFio, only the libcups library.
RUN mkdir -p /usr/local/lib/pkgconfig && \
printf "prefix=/usr/local\nexec_prefix=\${prefix}\nlibdir=\${exec_prefix}/lib\nincludedir=\${prefix}/include\n\nName: pdfio\nDescription: Dummy PDFio for building libcups library only\nVersion: 1.6.0\nLibs: \nCflags: \n" > /usr/local/lib/pkgconfig/pdfio.pc
# Build and install libcups (static only) into /fuzz/install
WORKDIR /fuzz/src
ENV CC=clang_wrapper CXX=clang_wrapper++
RUN ./configure --prefix=/fuzz/install --disable-shared --enable-static --with-tls=openssl --disable-dbus
# Build only the library (skip tools that may need external PDFio)
RUN make -j"$(nproc)" DIRS=cups && make -j"$(nproc)" DIRS=cups installBuild Command
clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/src/cups -I/fuzz/install/include/cups -L/fuzz/install/lib -lcups3 -lavahi-client -lavahi-common -lssl -lcrypto -lz -lpthread -lm && /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="testcase.cpp",target=/fuzz/testcase.cpp \
repro \
bash -c "clang++-17 -fsanitize=address -g -O0 -o /fuzz/test /fuzz/testcase.cpp -I/fuzz/src/cups -I/fuzz/install/include/cups -L/fuzz/install/lib -lcups3 -lavahi-client -lavahi-common -lssl -lcrypto -lz -lpthread -lm && /fuzz/test"Additional Info
This testcase was discovered by STITCH, an autonomous fuzzing system. All reports are reviewed manually (by a human) before submission.