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

[Nginx] Initial integration, new fuzzer added #4144

Merged
merged 48 commits into from
Aug 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
55df55b
[postgresql] Added auto_css to project.yaml
yooyoo9 Jul 1, 2020
3b68612
[postgresql] Added new fuzzer
yooyoo9 Jul 1, 2020
e9c20a7
[postgresql] Cleaned up files, changed project.yaml
yooyoo9 Jul 1, 2020
1ff3708
Dockerfile - changed to official repo
yooyoo9 Jul 1, 2020
0924667
Renamed fix.diff
yooyoo9 Jul 1, 2020
bc96764
[postgresql] Fixed parser_fuzzer, added new json_parser_fuzzer
yooyoo9 Jul 8, 2020
291874c
[nginx] updated project.yaml
yooyoo9 Jul 16, 2020
519e52b
[nginx] added first fuzzer
yooyoo9 Jul 16, 2020
da30b18
[nginx] added build file for fuzzers
yooyoo9 Jul 16, 2020
fba5786
Added license header
yooyoo9 Jul 16, 2020
6547869
Removed dictionary
yooyoo9 Jul 16, 2020
c68a47d
Removed dictionary
yooyoo9 Jul 17, 2020
a99ddb5
Moved fuzzers to fuzzer directory
yooyoo9 Jul 17, 2020
5e8bd8c
fixed new lines
yooyoo9 Jul 17, 2020
e6d31a6
Updated years, removed maintainer field in Dockerfile
yooyoo9 Jul 17, 2020
829a3c5
Removed line spaces
yooyoo9 Jul 17, 2020
3af152a
Updated year
yooyoo9 Jul 17, 2020
cbcce1d
Changed existing fuzzer
yooyoo9 Jul 17, 2020
8c183ba
Changed Makefile
yooyoo9 Jul 17, 2020
ed61f81
delete newlines
yooyoo9 Jul 24, 2020
3e412dc
remove patch
yooyoo9 Jul 24, 2020
268b46c
update year
yooyoo9 Jul 24, 2020
e269dbc
add socket wrapper functions
yooyoo9 Jul 24, 2020
f7d6886
modified fuzzer initialization
yooyoo9 Jul 24, 2020
7f64ba5
add new grpc module fuzzer
yooyoo9 Jul 24, 2020
ca84f84
Merge branch 'master' of github.com:google/oss-fuzz into pgsql
yooyoo9 Jul 24, 2020
372e731
Merge branch 'master' of github.com:google/oss-fuzz into nginx
yooyoo9 Jul 27, 2020
94e9b20
Removed grpc fuzzer
yooyoo9 Jul 27, 2020
f49f44a
Fixed http request fuzzer
yooyoo9 Jul 27, 2020
a08f4ce
Add nginx patch
yooyoo9 Jul 27, 2020
d4a56b4
Add Makefile for fuzzers
yooyoo9 Jul 27, 2020
1cd4810
Fix fuzzer
yooyoo9 Jul 29, 2020
b2c5a49
Added client side fuzzing
yooyoo9 Jul 29, 2020
8fb8203
fixed fuzzer
yooyoo9 Jul 31, 2020
2d78bfd
Merge branch 'master' of github.com:google/oss-fuzz into nginx
yooyoo9 Aug 19, 2020
60a5296
Merge branch 'pgsql' into nginx
yooyoo9 Aug 24, 2020
dd8a2ed
Removed memory and undefined sanitizers
yooyoo9 Aug 25, 2020
a299963
Added dictionary
yooyoo9 Aug 25, 2020
97b8d9a
Changed fuzzer from c to c++
yooyoo9 Aug 25, 2020
7601376
Use protobuf for input to fuzzer
yooyoo9 Aug 25, 2020
1cea2f4
Improved style
yooyoo9 Aug 25, 2020
3884c3d
Added configuration file needed by fuzzer
yooyoo9 Aug 25, 2020
9aaf93e
Added licence header
yooyoo9 Aug 25, 2020
17afbf1
Added makefile for fuzzers
yooyoo9 Aug 25, 2020
4c43fba
Fixed dictionary
yooyoo9 Aug 25, 2020
b0a95ac
Modified make_fuzzers
yooyoo9 Aug 26, 2020
75ba108
moved dictionary
yooyoo9 Aug 28, 2020
d1eb9f4
Undo last commit
yooyoo9 Aug 28, 2020
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
27 changes: 27 additions & 0 deletions projects/nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2020 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################

FROM gcr.io/oss-fuzz-base/base-builder

RUN apt-get update && apt-get install -y libpcre3-dev zlib1g-dev mercurial ninja-build cmake liblzma-dev libz-dev binutils libtool
RUN hg clone http://hg.nginx.org/nginx/
RUN git clone --depth 1 https://github.com/google/libprotobuf-mutator.git
RUN git clone --depth 1 https://github.com/google/fuzzer-test-suite
RUN (mkdir LPM && cd LPM && cmake ../libprotobuf-mutator -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release && ninja)

WORKDIR nginx
COPY fuzz $SRC/fuzz
COPY build.sh add_fuzzers.diff make_fuzzers $SRC/
12 changes: 12 additions & 0 deletions projects/nginx/add_fuzzers.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/auto/configure b/auto/configure
index 7e6e33a7..bb368cfb 100755
--- a/auto/configure
+++ b/auto/configure
@@ -100,6 +100,7 @@ have=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\""
. auto/define

. auto/make
+. auto/make_fuzzers
. auto/lib/make
. auto/install

32 changes: 32 additions & 0 deletions projects/nginx/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash -eu
# Copyright 2020 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
hg import $SRC/add_fuzzers.diff --no-commit

cp -r $SRC/fuzz src/
cp $SRC/make_fuzzers auto/make_fuzzers

cd src/fuzz
rm -rf genfiles && mkdir genfiles && $SRC/LPM/external.protobuf/bin/protoc http_request_proto.proto --cpp_out=genfiles
cd ../..

auto/configure \
--with-ld-opt="-Wl,--wrap=listen -Wl,--wrap=setsockopt -Wl,--wrap=bind -Wl,--wrap=shutdown -Wl,--wrap=connect" \
--with-http_v2_module
make -f objs/Makefile fuzzers

cp objs/*_fuzzer $OUT/
cp $SRC/fuzz/*.dict $OUT/
321 changes: 321 additions & 0 deletions projects/nginx/fuzz/http_request_fuzzer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
extern "C" {
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_http.h>
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

#include "http_request_proto.pb.h"
#include "libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h"

static char configuration[] =
"error_log stderr emerg;\n"
"events {\n"
" use epoll;\n"
" worker_connections 2;\n"
" multi_accept off;\n"
" accept_mutex off;\n"
"}\n"
"http {\n"
" server_tokens off;\n"
" default_type application/octet-stream;\n"
" map $http_upgrade $connection_upgrade {\n"
" default upgrade;\n"
" '' close;\n"
" }\n"
" error_log stderr emerg;\n"
" access_log off;\n"
" map $subdomain $nss {\n"
" default local_upstream;\n"
" }\n"
" upstream local_upstream {\n"
" server 127.0.0.1:1010 max_fails=0;\n"
" server 127.0.0.1:1011 max_fails=0;\n"
" server 127.0.0.1:1012 max_fails=0;\n"
" server 127.0.0.1:1013 max_fails=0;\n"
" server 127.0.0.1:1014 max_fails=0;\n"
" server 127.0.0.1:1015 max_fails=0;\n"
" server 127.0.0.1:1016 max_fails=0;\n"
" server 127.0.0.1:1017 max_fails=0;\n"
" server 127.0.0.1:1018 max_fails=0;\n"
" server 127.0.0.1:1019 max_fails=0;\n"
" }\n"
" client_max_body_size 256M;\n"
" client_body_temp_path /tmp/;\n"
" proxy_temp_path /tmp/;\n"
" proxy_buffer_size 24K;\n"
" proxy_max_temp_file_size 0;\n"
" proxy_buffers 8 4K;\n"
" proxy_busy_buffers_size 28K;\n"
" proxy_buffering off;\n"
" server {\n"
" listen unix:nginx.sock;\n"
" server_name ~^(?<subdomain>.+)\\.url.com$;\n"
" proxy_next_upstream off;\n"
" proxy_read_timeout 5m;\n"
" proxy_http_version 1.1;\n"
" proxy_set_header Host $http_host;\n"
" proxy_set_header X-Real-IP $remote_addr;\n"
" proxy_set_header X-Real-Port $remote_port;\n"
" location / {\n"
" proxy_pass http://$nss;\n"
" proxy_set_header Host $http_host;\n"
" proxy_set_header X-Real-IP $remote_addr;\n"
" proxy_set_header X-Real-Port $remote_port;\n"
" proxy_set_header Connection '';\n"
" chunked_transfer_encoding off;\n"
" proxy_buffering off;\n"
" proxy_cache off;\n"
" }\n"
" }\n"
"}\n"
"\n";


static ngx_cycle_t *cycle;
static ngx_log_t ngx_log;
static ngx_open_file_t ngx_log_file;
static char *my_argv[2];
static char arg1[] = {0, 0xA, 0};

extern char **environ;

static const char *config_file = "http_config.conf";

struct fuzzing_data {
const uint8_t *data;
size_t data_len;
};

static struct fuzzing_data request;
static struct fuzzing_data reply;

static ngx_http_upstream_t *upstream;
static ngx_http_request_t *req_reply;
static ngx_http_cleanup_t cln_new = {};
static int cln_added;

// Called when finalizing the request to upstream
// Do not need to clean the request pool
static void cleanup_reply(void *data) { req_reply = NULL; }

// Called by the http parser to read the buffer
static ssize_t request_recv_handler(ngx_connection_t *c, u_char *buf,
size_t size) {
if (request.data_len < size)
size = request.data_len;
memcpy(buf, request.data, size);
request.data += size;
request.data_len -= size;
return size;
}

// Feed fuzzing input for the reply from upstream
static ssize_t reply_recv_handler(ngx_connection_t *c, u_char *buf,
size_t size) {
req_reply = (ngx_http_request_t *)(c->data);
if (!cln_added) { // add cleanup so that we know whether everything is cleanup
// correctly
cln_added = 1;
cln_new.handler = cleanup_reply;
cln_new.next = req_reply->cleanup;
cln_new.data = NULL;
req_reply->cleanup = &cln_new;
}
upstream = req_reply->upstream;

if (reply.data_len < size)
size = reply.data_len;
memcpy(buf, reply.data, size);
reply.data += size;
reply.data_len -= size;
if (size == 0)
c->read->ready = 0;
return size;
}

static ngx_int_t add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) {
return NGX_OK;
}

static ngx_int_t init_event(ngx_cycle_t *cycle, ngx_msec_t timer) {
return NGX_OK;
}

// Used when sending data, do nothing
static ngx_chain_t *send_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit) {
c->read->ready = 1;
c->recv = reply_recv_handler;
return in->next;
}

// Create a base state for Nginx without starting the server
extern "C" int InitializeNginx(void) {
ngx_log_t *log;
ngx_cycle_t init_cycle;

if (access("nginx.sock", F_OK) != -1) {
remove("nginx.sock");
}

ngx_debug_init();
ngx_strerror_init();
ngx_time_init();
ngx_regex_init();

// Just output logs to stderr
ngx_log.file = &ngx_log_file;
ngx_log.log_level = NGX_LOG_EMERG;
ngx_log_file.fd = ngx_stderr;
log = &ngx_log;

ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
init_cycle.log = log;
ngx_cycle = &init_cycle;

init_cycle.pool = ngx_create_pool(1024, log);

// Set custom argv/argc
my_argv[0] = arg1;
my_argv[1] = NULL;
ngx_argv = ngx_os_argv = my_argv;
ngx_argc = 0;

// Weird trick to free a leaking buffer always caught by ASAN
// We basically let ngx overwrite the environment variable, free the leak and
// restore the environment as before.
char *env_before = environ[0];
environ[0] = my_argv[0] + 1;
ngx_os_init(log);
free(environ[0]);
environ[0] = env_before;

ngx_crc32_table_init();
ngx_preinit_modules();

FILE *fptr = fopen(config_file, "w");
fprintf(fptr, "%s", configuration);
fclose(fptr);
init_cycle.conf_file.len = strlen(config_file);
init_cycle.conf_file.data = (unsigned char *) config_file;

cycle = ngx_init_cycle(&init_cycle);

ngx_os_status(cycle->log);
ngx_cycle = cycle;

ngx_event_actions.add = add_event;
ngx_event_actions.init = init_event;
ngx_io.send_chain = send_chain;
ngx_event_flags = 1;
ngx_event_timer_init(cycle->log);
return 0;
}

extern "C" long int invalid_call(ngx_connection_s *a, ngx_chain_s *b,
long int c) {
return 0;
}

DEFINE_PROTO_FUZZER(const HttpProto &input) {
static int init = InitializeNginx();
assert(init == 0);

// have two free connections, one for client, one for upstream
ngx_event_t read_event1 = {};
ngx_event_t write_event1 = {};
ngx_connection_t local1 = {};
ngx_event_t read_event2 = {};
ngx_event_t write_event2 = {};
ngx_connection_t local2 = {};
ngx_connection_t *c;
ngx_listening_t *ls;

req_reply = NULL;
upstream = NULL;
cln_added = 0;

const char *req_string = input.request().c_str();
size_t req_len = strlen(req_string);
const char *rep_string = input.reply().c_str();
size_t rep_len = strlen(rep_string);
request.data = (const uint8_t *)req_string;
request.data_len = req_len;
reply.data = (const uint8_t *)rep_string;
reply.data_len = rep_len;

// Use listening entry created from configuration
ls = (ngx_listening_t *)ngx_cycle->listening.elts;

// Fake event ready for dispatch on read
local1.read = &read_event1;
local1.write = &write_event1;
local2.read = &read_event2;
local2.write = &write_event2;
local2.send_chain = send_chain;

// Create fake free connection to feed the http handler
ngx_cycle->free_connections = &local1;
local1.data = &local2;
ngx_cycle->free_connection_n = 2;

// Initialize connection
c = ngx_get_connection(
255, &ngx_log); // 255 - (hopefully unused) socket descriptor

c->shared = 1;
c->type = SOCK_STREAM;
c->pool = ngx_create_pool(256, ngx_cycle->log);
c->sockaddr = ls->sockaddr;
c->listening = ls;
c->recv = request_recv_handler; // Where the input will be read
c->send_chain = send_chain;
c->send = (ngx_send_pt)invalid_call;
c->recv_chain = (ngx_recv_chain_pt)invalid_call;
c->log = &ngx_log;
c->pool->log = &ngx_log;
c->read->log = &ngx_log;
c->write->log = &ngx_log;
c->socklen = ls->socklen;
c->local_sockaddr = ls->sockaddr;
c->local_socklen = ls->socklen;

read_event1.ready = 1;
write_event1.ready = write_event1.delayed = 1;

// Will redirect to http parser
ngx_http_init_connection(c);

// Clean-up in case of error
if (req_reply && upstream && upstream->cleanup) {
(*(upstream->cleanup))(req_reply);
if (!c->destroyed)
ngx_http_close_connection(c);
} else if (!c->destroyed) {
ngx_http_request_t *r = (ngx_http_request_t *)(c->data);
ngx_http_free_request(r, 0);
ngx_http_close_connection(c);
}
}