Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTTP/3 fuzzing harness #97

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Expand Up @@ -51,6 +51,7 @@ jobs:
- curl_fuzzer_gopher
- curl_fuzzer_http
- curl_fuzzer_https
- curl_fuzzer_http3
- curl_fuzzer_imap
- curl_fuzzer_ldap
- curl_fuzzer_mqtt
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Expand Up @@ -40,6 +40,8 @@ missing
/curl_fuzzer_http_seed_corpus.zip
/curl_fuzzer_https
/curl_fuzzer_https_seed_corpus.zip
/curl_fuzzer_http3
/curl_fuzzer_http3_seed_corpus.zip
/curl_fuzzer_imap
/curl_fuzzer_imap_seed_corpus.zip
/curl_fuzzer_ldap
Expand All @@ -62,3 +64,7 @@ missing
/curl_fuzzer_smtp_seed_corpus.zip
/curl_fuzzer_tftp
/curl_fuzzer_tftp_seed_corpus.zip
/curl_fuzzer_ws
/curl_fuzzer_ws_seed_corpus.zip
/fuzz_url
/fuzz_url.zip
12 changes: 9 additions & 3 deletions Makefile.am
Expand Up @@ -25,7 +25,7 @@ ACLOCAL_AMFLAGS = -I m4
@CODE_COVERAGE_RULES@

# Include debug symbols by default as recommended by libfuzzer.
AM_CXXFLAGS = -g -I@INSTALLDIR@/include -I@INSTALLDIR@/utfuzzer
AM_CXXFLAGS = -g

LIBS = -lpthread -lm

Expand All @@ -42,6 +42,7 @@ FUZZPROGS = curl_fuzzer \
curl_fuzzer_gopher \
curl_fuzzer_http \
curl_fuzzer_https \
curl_fuzzer_http3 \
curl_fuzzer_imap \
curl_fuzzer_ldap \
curl_fuzzer_mqtt \
Expand All @@ -59,8 +60,10 @@ FUZZPROGS = curl_fuzzer \
FUZZLIBS = libstandaloneengine.a

COMMON_SOURCES = curl_fuzzer.cc curl_fuzzer_tlv.cc curl_fuzzer_callback.cc
COMMON_FLAGS = $(AM_CXXFLAGS) $(CODE_COVERAGE_CXXFLAGS)
COMMON_LDADD = @INSTALLDIR@/lib/libcurl.la $(LIB_FUZZING_ENGINE) $(CODE_COVERAGE_LIBS)
COMMON_FLAGS = -I@INSTALLDIR@/openssl/include -I@INSTALLDIR@/openssl/utfuzzer $(AM_CXXFLAGS) $(CODE_COVERAGE_CXXFLAGS)
COMMON_LDADD = @INSTALLDIR@/openssl/lib/libcurl.la $(LIB_FUZZING_ENGINE) $(CODE_COVERAGE_LIBS)
HTTP3_FLAGS = -I@INSTALLDIR@/openssl_quic/include -I@INSTALLDIR@/openssl_quic/utfuzzer $(AM_CXXFLAGS) $(CODE_COVERAGE_CXXFLAGS)
HTTP3_LDADD = @INSTALLDIR@/openssl_quic/lib/libcurl.la $(LIB_FUZZING_ENGINE) $(CODE_COVERAGE_LIBS)

libstandaloneengine_a_SOURCES = standalone_fuzz_target_runner.cc
libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS)
Expand Down Expand Up @@ -89,6 +92,9 @@ curl_fuzzer_http_LDADD = $(COMMON_LDADD)
curl_fuzzer_https_SOURCES = $(COMMON_SOURCES)
curl_fuzzer_https_CXXFLAGS = $(COMMON_FLAGS) -DFUZZ_PROTOCOLS_HTTPS
curl_fuzzer_https_LDADD = $(COMMON_LDADD)
curl_fuzzer_http3_SOURCES = $(COMMON_SOURCES)
curl_fuzzer_http3_CXXFLAGS = $(HTTP3_FLAGS) -DFUZZ_PROTOCOLS_HTTP3 -DFUZZ_PROTOCOLS_HTTPS
curl_fuzzer_http3_LDADD = $(HTTP3_LDADD)
curl_fuzzer_imap_SOURCES = $(COMMON_SOURCES)
curl_fuzzer_imap_CXXFLAGS = $(COMMON_FLAGS) -DFUZZ_PROTOCOLS_IMAP
curl_fuzzer_imap_LDADD = $(COMMON_LDADD)
Expand Down
Binary file added corpora/curl_fuzzer_http3/test_simple_httppost
Binary file not shown.
12 changes: 12 additions & 0 deletions curl_fuzzer.cc
Expand Up @@ -207,8 +207,10 @@ int fuzz_set_easy_options(FUZZ_DATA *fuzz)
/* Set the hsts header cache filepath so that it can be fuzzed. */
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_HSTS, FUZZ_HSTS_HEADER_CACHE_PATH));

#ifndef FUZZ_PROTOCOLS_HTTPS
/* Set the Certificate Revocation List file path so it can be fuzzed */
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_CRLFILE, FUZZ_CRL_FILE_PATH));
#endif

/* Set the .netrc file path so it can be fuzzed */
FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_NETRC_FILE, FUZZ_NETRC_FILE_PATH));
Expand Down Expand Up @@ -571,6 +573,16 @@ int fuzz_set_allowed_protocols(FUZZ_DATA *fuzz)

FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_PROTOCOLS_STR, allowed_protocols));

#ifdef FUZZ_PROTOCOLS_HTTP3
/* If we are fuzzing HTTP3, then we must be fuzzing the HTTPS protocol */
#ifndef FUZZ_PROTOCOLS_HTTPS
rc = 255;
goto EXIT_LABEL;
#endif

FTRY(curl_easy_setopt(fuzz->easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3ONLY));
#endif

EXIT_LABEL:

return rc;
Expand Down
9 changes: 8 additions & 1 deletion curl_fuzzer_callback.cc
Expand Up @@ -69,7 +69,14 @@ curl_socket_t fuzz_open_socket(void *ptr,
sman->index,
sman->index);

if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {

#ifdef FUZZ_PROTOCOLS_HTTP3
const int socket_type = SOCK_DGRAM;
#else
const int socket_type = SOCK_STREAM;
#endif

if(socketpair(AF_UNIX, socket_type, 0, fds)) {
/* Failed to create a pair of sockets. */
return CURL_SOCKET_BAD;
}
Expand Down
41 changes: 29 additions & 12 deletions mainline.sh
Expand Up @@ -8,21 +8,25 @@ SCRIPTDIR=${BUILD_ROOT}/scripts

CURLDIR=/tmp/curl
OPENSSLDIR=/tmp/openssl
NGHTTPDIR=/tmp/nghttp2
INSTALLDIR=/tmp/curl_install
NGHTTP2DIR=/tmp/nghttp2
NGHTTP3DIR=/tmp/nghttp3
NGTCP2DIR=/tmp/ngtcp2
INSTALLDIRTOP=/tmp/curl_install

# Parse the options.
OPTIND=1

while getopts "c:n:o:" opt
while getopts "c:n:o:t:" opt
do
case "$opt" in
c) CURLDIR=$OPTARG
;;
n) NGHTTPDIR=$OPTARG
n) NGHTTP2DIR=$OPTARG
;;
o) OPENSSLDIR=$OPTARG
;;
t) NGTCP2DIR=$OPTARG
;;
esac
done
shift $((OPTIND-1))
Expand All @@ -34,16 +38,29 @@ FUZZ_FLAG="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
export CFLAGS="-fsanitize=address"
export CXXFLAGS="-fsanitize=address -stdlib=libstdc++ $FUZZ_FLAG"
export CPPFLAGS="$FUZZ_FLAG"
export OPENSSLFLAGS="-fno-sanitize=alignment"
export OPENSSLFLAGS="-fno-sanitize=alignment -lstdc++"

for tls_lib in openssl openssl_quic; do
INSTALLDIR="$INSTALLDIRTOP/$tls_lib"
mkdir -p "$INSTALLDIR"

# Install tls_lib
${SCRIPTDIR}/handle_x.sh ${tls_lib} ${OPENSSLDIR}/${tls_lib} ${INSTALLDIR} || exit 1

# Install openssl
${SCRIPTDIR}/handle_x.sh openssl ${OPENSSLDIR} ${INSTALLDIR} || exit 1
# Install nghttp2
${SCRIPTDIR}/handle_x.sh nghttp2 ${NGHTTP2DIR} ${INSTALLDIR} || exit 1

# Install nghttp2
${SCRIPTDIR}/handle_x.sh nghttp2 ${NGHTTPDIR} ${INSTALLDIR} || exit 1
if [[ "$tls_lib" == "openssl_quic" ]]; then
# Install nghttp3
${SCRIPTDIR}/handle_x.sh nghttp3 ${NGHTTP3DIR} ${INSTALLDIR} || exit 1

# Install curl after all other dependencies
${SCRIPTDIR}/handle_x.sh curl ${CURLDIR} ${INSTALLDIR} || exit 1
# Install ngtcp2
${SCRIPTDIR}/handle_x.sh ngtcp2 ${NGTCP2DIR} ${INSTALLDIR} || exit 1
fi

# Install curl after all other dependencies
${SCRIPTDIR}/handle_x.sh curl ${CURLDIR} ${INSTALLDIR} || exit 1
done

# Compile and test the fuzzers.
${SCRIPTDIR}/compile_fuzzer.sh ${INSTALLDIR} || exit 1
${SCRIPTDIR}/compile_fuzzer.sh ${INSTALLDIRTOP} || exit 1
50 changes: 33 additions & 17 deletions ossfuzz.sh
Expand Up @@ -29,7 +29,9 @@ SCRIPTDIR=${BUILD_ROOT}/scripts

ZLIBDIR=/src/zlib
OPENSSLDIR=/src/openssl
NGHTTPDIR=/src/nghttp2
NGHTTP2DIR=/src/nghttp2
NGHTTP3DIR=/src/nghttp3
NGTCP2DIR=/src/ngtcp2
GDBDIR=/src/gdb

# Check for GDB-specific behaviour by checking for the GDBMODE flag.
Expand All @@ -53,7 +55,7 @@ echo "FUZZ_TARGETS: $FUZZ_TARGETS"
export MAKEFLAGS+="-j$(nproc)"

# Make an install directory
export INSTALLDIR=/src/curl_install
export INSTALLDIRTOP=/src/curl_install

# Check for GDB-specific behaviour by checking for the GDBMODE flag.
# - Compile and installing GDB if necessary.
Expand All @@ -67,26 +69,40 @@ then
fi
fi

# Install zlib
${SCRIPTDIR}/handle_x.sh zlib ${ZLIBDIR} ${INSTALLDIR} || exit 1
for tls_lib in openssl openssl_quic; do
INSTALLDIR="$INSTALLDIRTOP/$tls_lib"
mkdir -p "$INSTALLDIR"

# For the memory sanitizer build, turn off OpenSSL as it causes bugs we can't
# affect (see 16697, 17624)
if [[ ${SANITIZER} != "memory" ]]
then
# Install openssl
export OPENSSLFLAGS="-fno-sanitize=alignment"
${SCRIPTDIR}/handle_x.sh openssl ${OPENSSLDIR} ${INSTALLDIR} || exit 1
fi
# Install zlib
${SCRIPTDIR}/handle_x.sh zlib ${ZLIBDIR} ${INSTALLDIR} || exit 1

# For the memory sanitizer build, turn off OpenSSL as it causes bugs we can't
# affect (see 16697, 17624)
if [[ ${SANITIZER} != "memory" ]]
then
# Install openssl_quic (need openssl_quic, nghttp3, and ngtcp2 for HTTP3 support)
export OPENSSLFLAGS="-fno-sanitize=alignment"
${SCRIPTDIR}/handle_x.sh ${tls_lib} ${OPENSSLDIR}/${tls_lib} ${INSTALLDIR} || exit 1

# Install nghttp2
${SCRIPTDIR}/handle_x.sh nghttp2 ${NGHTTPDIR} ${INSTALLDIR} || exit 1
if [[ "$tls_lib" == "openssl_quic" ]]
then
# Install nghttp3
${SCRIPTDIR}/handle_x.sh nghttp3 ${NGHTTP3DIR} ${INSTALLDIR} || exit 1

# Compile curl
${SCRIPTDIR}/install_curl.sh /src/curl ${INSTALLDIR}
# Install ngtcp2
${SCRIPTDIR}/handle_x.sh ngtcp2 ${NGTCP2DIR} ${INSTALLDIR} || exit 1
fi
fi

# Install nghttp2
${SCRIPTDIR}/handle_x.sh nghttp2 ${NGHTTP2DIR} ${INSTALLDIR} || exit 1

# Compile curl
${SCRIPTDIR}/install_curl.sh /src/curl ${INSTALLDIR}
done

# Build the fuzzers.
${SCRIPTDIR}/compile_fuzzer.sh ${INSTALLDIR}
${SCRIPTDIR}/compile_fuzzer.sh ${INSTALLDIRTOP}
make zip

# Copy the fuzzers over.
Expand Down
11 changes: 11 additions & 0 deletions renovate.json
Expand Up @@ -23,6 +23,17 @@
"depNameTemplate": "openssl/openssl",
"versioningTemplate": "regex:^openssl-(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)$",
"registryUrlTemplate": "https://github.com"
},
{
"customType": "regex",
"fileMatch": ["^scripts/VERSIONS$"],
"matchStrings": [
"QUICTLS_VERSION=(?<currentValue>.*)\\s"
],
"datasourceTemplate": "github-tags",
"depNameTemplate": "openssl/openssl",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this actually wants to be quictls/openssl

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! I'll get that changed

"versioningTemplate": "regex:^openssl-(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)-quic\\d+$",
"registryUrlTemplate": "https://github.com"
}
],
"packageRules": [
Expand Down
9 changes: 9 additions & 0 deletions scripts/VERSIONS
Expand Up @@ -3,5 +3,14 @@
# Handled by renovate.json
OPENSSL_VERSION=openssl-3.2.0

# Handled by renovate.json
QUICTLS_VERSION=openssl-3.1.4-quic1

# renovate: datasource=github-tags depName=nghttp2/nghttp2 versioning=semver registryUrl=https://github.com
NGHTTP2_VERSION=v1.58.0

# renovate: datasource=github-tags depName=ngtcp2/nghttp3 versioning=semver registryUrl=https://github.com
NGHTTP3_VERSION=v1.1.0

# renovate: datasource=github-tags depName=ngtcp2/ngtcp2 versioning=semver registryUrl=https://github.com
NGTCP2_VERSION=v1.1.0
18 changes: 18 additions & 0 deletions scripts/download_curl.sh
Expand Up @@ -6,3 +6,21 @@ set -ex
# Clone the curl repository to the specified directory.
git clone http://github.com/curl/curl $1

# TODO: Ignore HTTP3 socket connection failures
pushd $1
patch -p1 <<'EOF'
diff --git a/lib/cf-socket.c b/lib/cf-socket.c
index e42b4a87b..f99fcd80c 100644
--- a/lib/cf-socket.c
+++ b/lib/cf-socket.c
@@ -1650,7 +1650,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,

rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
if(-1 == rc) {
- return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
+ /* return socket_connect_result(data, ctx->r_ip, SOCKERRNO); */
}
set_local_ip(cf, data);
CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
EOF
popd
11 changes: 11 additions & 0 deletions scripts/download_nghttp3.sh
@@ -0,0 +1,11 @@
#!/bin/bash

# If any commands fail, fail the script immediately.
set -ex

# Get the script directory and source the VERSIONS file
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source $SCRIPT_DIR/VERSIONS

# Clone the repository to the specified directory.
git clone --depth 1 --branch ${NGHTTP3_VERSION} https://github.com/ngtcp2/nghttp3 $1